jsonargparse icon indicating copy to clipboard operation
jsonargparse copied to clipboard

Selecting subtype from union type via command line.

Open MiguelMonteiro opened this issue 1 year ago • 4 comments

🐛 Bug report

No way of selecting a subtype from a union type.

When adding an argument which is a union of two types there seems to be no direct way of specifying the desired type to be parsed/instantiated. This seems to be automatically detected from the argument names and values which is undesirable in scenarios where subtypes have similar arguments but different behaviors when instantiated.

To reproduce

from dataclasses import dataclass
from jsonargparse import ArgumentParser

@dataclass
class A:
    foo: int

@dataclass
class B:
    foo: int
    bar: float = 1.0


if __name__ == "__main__":
    parser = ArgumentParser(description="Example CLI", exit_on_error=False)
    parser.add_argument("--cfg", type=A | B)
    args = parser.parse_args(["--cfg.foo=1"])
    print(args)
    print(parser.instantiate_classes(args))

Expected behavior

A way of selecting the desired subtype from the command line.

Environment

  • jsonargparse version: 4.33.1
  • Python version: 3.10
  • How jsonargparse was installed: pip
  • OS: MacOS

MiguelMonteiro avatar Oct 02 '24 12:10 MiguelMonteiro

Thank you for reporting!

Explanation. Types inside Union are parsed from left to right. The first one that succeeds is chosen. In the example above since only foo is provided, then A succeeds and there is no attempt at B. Right now the only way is to specify bar so that A fails and it gets parsed as B.

Unfortunately this is not an easy fix. I do have in mind a big internal change that would fix this, which is needed to support other cases, e.g. #287. But this will take time.

mauvilsa avatar Oct 05 '24 04:10 mauvilsa

Let me know if I can help, ideally it would be nice if the union type werer treated in the same way subclasses are, the first argument selects the type and defines the help string and then the following arguments get matched against the choice of class/type

MiguelMonteiro avatar Oct 11 '24 12:10 MiguelMonteiro

What I have in mind to do is described in https://github.com/omni-us/jsonargparse/issues/287#issuecomment-2433109024.

mauvilsa avatar Oct 24 '24 19:10 mauvilsa

I manually "solved" the above issue by adding to each dataclass a field with the name of the class so:

@dataclass
class A:
    foo: int
    A: bool 

@dataclass
class B:
    foo: int
    bar: float = 1.0
    B: bool

I choose the correct class using --params.A=true or --params.B=true. While not ideal, this is a plausible way to choose among union types by explicitly naming the type required. The problem with this hack is that I still cannot get the help for the given type. Given --params.A=true --help I would like to get help for type A with all of its fields (and the same for other types obviously). If this was somehow possible, it would make union types much more usable.

trporn avatar Feb 23 '25 07:02 trporn

For an update read https://github.com/omni-us/jsonargparse/issues/287#issuecomment-3310995777

mauvilsa avatar Sep 19 '25 07:09 mauvilsa