diff --git a/dcargs/_parsers.py b/dcargs/_parsers.py index 46d6965c..815bd187 100644 --- a/dcargs/_parsers.py +++ b/dcargs/_parsers.py @@ -255,8 +255,8 @@ def from_field( # Add subparser for each option. parser_from_name: Dict[str, ParserSpecification] = {} for option in options_no_none: - subparser_name = _strings.subparser_name_from_type(prefix, option) - parser_from_name[subparser_name] = ParserSpecification.from_callable( + name = _strings.subparser_name_from_type(prefix, option) + subparser = ParserSpecification.from_callable( option, description=None, parent_classes=parent_classes, @@ -268,6 +268,16 @@ def from_field( avoid_subparsers=avoid_subparsers, ) + # Apply prefix to helptext in nested classes in subparsers. + subparser = dataclasses.replace( + subparser, + helptext_from_nested_class_field_name={ + _strings.make_field_name([prefix, k]): v + for k, v in subparser.helptext_from_nested_class_field_name.items() + }, + ) + parser_from_name[name] = subparser + # Optional if: type hint is Optional[], or a default instance is provided. required = True if field.default not in _fields.MISSING_SINGLETONS: diff --git a/pyproject.toml b/pyproject.toml index cda21fa8..bd329a31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dcargs" -version = "0.2.7" +version = "0.2.8" description = "Strongly typed, zero-effort CLI interfaces" authors = ["brentyi "] include = ["./dcargs/**/*"] diff --git a/tests/test_nested.py b/tests/test_nested.py index eae4840d..b52f25be 100644 --- a/tests/test_nested.py +++ b/tests/test_nested.py @@ -745,3 +745,30 @@ def main( assert hash(dcargs.cli(main, args="--x.num-epochs 10".split(" "))) == hash( frozendict({"num_epochs": 10, "batch_size": 64}) ) + + +def test_nested_in_subparser(): + # https://github.com/brentyi/dcargs/issues/9 + @dataclasses.dataclass(frozen=True) + class Subtype: + data: int = 1 + + @dataclasses.dataclass(frozen=True) + class TypeA: + subtype: Subtype = Subtype(1) + + @dataclasses.dataclass(frozen=True) + class TypeB: + subtype: Subtype = Subtype(2) + + @dataclasses.dataclass(frozen=True) + class Wrapper: + supertype: Union[TypeA, TypeB] = TypeA() + + assert dcargs.cli(Wrapper, args=[]) == Wrapper() + assert ( + dcargs.cli( + Wrapper, args="supertype:type-a --supertype.subtype.data 1".split(" ") + ) + == Wrapper() + )