Skip to content

Commit 260a2f2

Browse files
authored
Union of dataclasses not discarding parameters on class change (#833)
1 parent 384a1ea commit 260a2f2

3 files changed

Lines changed: 39 additions & 3 deletions

File tree

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Fixed
2424
^^^^^
2525
- Choices with an int type not working correctly (`#827
2626
<https://github.com/omni-us/jsonargparse/pull/827>`__).
27+
- Union of dataclasses not discarding parameters on class change (`#833
28+
<https://github.com/omni-us/jsonargparse/pull/833>`__).
2729

2830

2931
v4.45.0 (2025-12-26)

jsonargparse/_typehints.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,15 @@ def adapt_typehints(
10631063
prev_implicit_defaults = True
10641064

10651065
if isinstance(prev_val, (dict, Namespace)) and "class_path" not in prev_val:
1066-
# implicit prev_val class_path and init_args
1067-
prev_val = Namespace(class_path=get_import_path(typehint), init_args=Namespace(prev_val))
1066+
# implicit prev_val init_args
1067+
prev_val = Namespace(class_path=None, init_args=Namespace(prev_val))
10681068

10691069
val_input = val
1070-
val = subclass_spec_as_namespace(val, prev_val)
1070+
if isinstance(prev_val, (dict, Namespace)) and prev_val["class_path"] is None:
1071+
type_class_path = Namespace(class_path=get_import_path(typehint))
1072+
val = subclass_spec_as_namespace(val, type_class_path)
1073+
else:
1074+
val = subclass_spec_as_namespace(val, prev_val)
10711075
if val and not is_subclass_spec(val) and "init_args" not in val:
10721076
# implicit val class_path
10731077
val = Namespace(class_path=get_import_path(typehint), init_args=val)

jsonargparse_tests/test_dataclasses.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,36 @@ def test_class_path_union_dataclasses(parser):
686686
assert json_or_yaml_load(parser.dump(cfg))["union"] == {"p1": "x", "p2": 0}
687687

688688

689+
@dataclasses.dataclass
690+
class SubA:
691+
a: int = 2
692+
693+
694+
@dataclasses.dataclass
695+
class SubB:
696+
b: float = 3.4
697+
698+
699+
@dataclasses.dataclass
700+
class SubAorB:
701+
a_or_b: Union[SubA, SubB] = dataclasses.field(default_factory=SubA)
702+
703+
704+
def test_union_dataclasses(parser):
705+
parser.add_class_arguments(SubAorB, "data")
706+
707+
cfg = parser.parse_args([])
708+
init = parser.instantiate_classes(cfg)
709+
assert isinstance(init.data, SubAorB)
710+
assert isinstance(init.data.a_or_b, SubA)
711+
712+
cfg = parser.parse_args(["--data.a_or_b.b=4"])
713+
assert cfg.data.a_or_b == Namespace(b=4.0)
714+
init = parser.instantiate_classes(cfg)
715+
assert isinstance(init.data, SubAorB)
716+
assert isinstance(init.data.a_or_b, SubB)
717+
718+
689719
if type_alias_type:
690720
IntOrString = type_alias_type("IntOrString", Union[int, str])
691721

0 commit comments

Comments
 (0)