lebrice / SimpleParsing

Simple, Elegant, Typed Argument Parsing with argparse
MIT License
386 stars 47 forks source link

The `Subgroups` makes `to_dict` and `from_dict` violate the inversion rule #204

Closed zhiruiluo closed 1 year ago

zhiruiluo commented 1 year ago

Describe the bug The Subgroups makes to_dict and from_dict violate the inversion rule.

To Reproduce

from __future__ import annotations
from simple_parsing.helpers.serialization import to_dict, from_dict
from simple_parsing import subgroups
from .testutils import TestSetup
from dataclasses import dataclass, field

@dataclass
class A(TestSetup):
    a: float = 0.0

@dataclass
class B(TestSetup):
    b: str = "bar"

@dataclass
class AB(TestSetup):
    integer_only_by_post_init: int = field(init=False)
    integer_in_string: str = "1"
    a_or_b: A | B = subgroups({"a": A, "b": B}, default="a")

    def __post_init__(self):
        self.integer_only_by_post_init = int(self.integer_in_string)

def test_serialization():
    config = AB.setup('--a_or_b b')
    config_dict = to_dict(config)
    print(config_dict)
    new_config = from_dict(AB, config_dict,drop_extra_fields=True)
    print(new_config)
    assert config == new_config

Expected behavior The to_dict and from_dict should be a pair of the inverse operations.

passed

Actual behavior However, the subgroups makes to_dict and from_dict violate the inversion.

failed

Desktop (please complete the following information):

Additional context We could insert a pair {"__subgroup__@[field_name]": [subgroup_key]} when calling to_dict

{
    'integer_only_by_post_init': 1, 
    'integer_in_string': '1',
    '__subgroups__@a_or_b': 'b', 
    'a_or_b': {'b': 'bar'}
}

Then, we could retrieve the selected subgroup in from_dict function and drop __subgroups__@[field_name] after.