diff --git a/dataclass_wizard/class_helper.py b/dataclass_wizard/class_helper.py index 3cf74ac..bd8eec9 100644 --- a/dataclass_wizard/class_helper.py +++ b/dataclass_wizard/class_helper.py @@ -329,44 +329,19 @@ def _process_field(name: str, dump_dataclass_field_to_alias): """Process a :class:`Field` for a dataclass field.""" - if not f.dump_alias is ExplicitNull: - dump_dataclass_field_to_alias[f.name] = ExplicitNull - - else: - # if not f.json.dump: - # field_to_alias[f.name] = ExplicitNull - # elif f.json.all: - # keys = f.json.keys - # if f.json.path: - # if set_paths: - # field_to_path[f.name] = keys - # field_to_alias[f.name] = '' - # else: - # field_to_alias[f.name] = keys[0] - - - if f.path is not None: - if set_paths: + if f.path is not None: + if set_paths and f.load_alias is not ExplicitNull: dataclass_field_to_path[name] = f.path - # TODO: I forgot why this is needed >.> - dump_dataclass_field_to_alias[name] = '' - - else: - if f.load_alias is not None: - load_dataclass_field_to_alias[name] = f.load_alias - if f.dump_alias is not None: - dump_dataclass_field_to_alias[name] = f.dump_alias - - # if not f.json.dump: - # field_to_alias[f.name] = ExplicitNull - # elif f.json.all: - # keys = f.json.keys - # if f.json.path: - # if set_paths: - # field_to_path[f.name] = keys - # field_to_alias[f.name] = '' - # else: - # field_to_alias[f.name] = keys[0] + if f.dump_alias is not ExplicitNull: + value = ExplicitNull if f.skip else '' + dump_dataclass_field_to_alias[name] = value + else: + if f.load_alias is not None: + load_dataclass_field_to_alias[name] = f.load_alias + if f.skip: + dump_dataclass_field_to_alias[name] = ExplicitNull + elif f.dump_alias is not None: + dump_dataclass_field_to_alias[name] = f.dump_alias def _setup_v1_load_config_for_cls( diff --git a/dataclass_wizard/v1/models.py b/dataclass_wizard/v1/models.py index ab2c1cd..3fd6378 100644 --- a/dataclass_wizard/v1/models.py +++ b/dataclass_wizard/v1/models.py @@ -204,6 +204,7 @@ class Extras(TypedDict): def Alias(all=None, *, load=None, dump=None, + skip=False, path=None, default=MISSING, default_factory=MISSING, @@ -217,13 +218,14 @@ def Alias(all=None, *, if all is not None: load = dump = all - return Field(load, dump, path, default, default_factory, init, repr, + return Field(load, dump, skip, path, default, default_factory, init, repr, hash, compare, metadata, kw_only) # noinspection PyPep8Naming,PyShadowingBuiltins def AliasPath(all=None, *, load=None, dump=None, + skip=False, default=MISSING, default_factory=MISSING, init=True, repr=True, @@ -235,7 +237,7 @@ def AliasPath(all=None, *, load = None dump = ExplicitNull - if dump is not None: + elif dump is not None: all = dump dump = None load = ExplicitNull @@ -243,20 +245,23 @@ def AliasPath(all=None, *, if isinstance(all, str): all = split_object_path(all) - return Field(load, dump, all, default, default_factory, init, repr, + return Field(load, dump, skip, all, default, default_factory, init, repr, hash, compare, metadata, kw_only) class Field(_Field): - __slots__ = ('load_alias', 'dump_alias', 'path', ) + __slots__ = ('load_alias', + 'dump_alias', + 'skip', + 'path') # noinspection PyShadowingBuiltins - def __init__(self, load_alias, dump_alias, - path, default, default_factory, init, repr, hash, compare, + def __init__(self, + load_alias, dump_alias, skip, path, + default, default_factory, init, repr, hash, compare, metadata, kw_only): - super().__init__(default, default_factory, init, repr, hash, compare, metadata, kw_only) @@ -266,6 +271,7 @@ def __init__(self, load_alias, dump_alias, self.load_alias = load_alias self.dump_alias = dump_alias + self.skip = skip self.path = path else: # pragma: no cover @@ -273,6 +279,7 @@ def __init__(self, load_alias, dump_alias, def Alias(all=None, *, load=None, dump=None, + skip=False, path=None, default=MISSING, default_factory=MISSING, @@ -285,7 +292,7 @@ def Alias(all=None, *, if all is not None: load = dump = all - return Field(load, dump, path, + return Field(load, dump, skip, path, default, default_factory, init, repr, hash, compare, metadata) @@ -293,6 +300,7 @@ def Alias(all=None, *, def AliasPath(all=None, *, load=None, dump=None, + skip=False, default=MISSING, default_factory=MISSING, init=True, repr=True, @@ -304,7 +312,7 @@ def AliasPath(all=None, *, load = None dump = ExplicitNull - if dump is not None: + elif dump is not None: all = dump dump = None load = ExplicitNull @@ -315,18 +323,21 @@ def AliasPath(all=None, *, if isinstance(all, str): all = split_object_path(all) - return Field(load, dump, all, default, default_factory, init, repr, + return Field(load, dump, skip, all, default, default_factory, init, repr, hash, compare, metadata) class Field(_Field): - __slots__ = ('load_alias', 'dump_alias', 'path', ) + __slots__ = ('load_alias', + 'dump_alias', + 'skip', + 'path') # noinspection PyArgumentList,PyShadowingBuiltins def __init__(self, - load_alias, dump_alias, - path, default, default_factory, init, repr, hash, compare, + load_alias, dump_alias, skip, path, + default, default_factory, init, repr, hash, compare, metadata): super().__init__(default, default_factory, init, repr, hash, @@ -338,4 +349,5 @@ def __init__(self, self.load_alias = load_alias self.dump_alias = dump_alias + self.skip = skip self.path = path diff --git a/dataclass_wizard/v1/models.pyi b/dataclass_wizard/v1/models.pyi index 0346d5c..1d57857 100644 --- a/dataclass_wizard/v1/models.pyi +++ b/dataclass_wizard/v1/models.pyi @@ -69,6 +69,7 @@ class Extras(TypedDict): def AliasPath(all: PathType | str | None = None, *, load : PathType | str | None = None, dump : PathType | str | None = None, + skip: bool = False, default=MISSING, default_factory: Callable[[], MISSING] = MISSING, init=True, repr=True, @@ -123,6 +124,7 @@ def AliasPath(all: PathType | str | None = None, *, def Alias(all: str | None = None, *, load: str | None = None, dump: str | None = None, + skip: bool = False, path: PathType | str | None = None, default=MISSING, default_factory: Callable[[], MISSING] = MISSING, @@ -202,12 +204,15 @@ class Field(_Field): See the docs on the :func:`json_field` function for more info. """ - __slots__ = ('load_alias', 'dump_alias', 'path', ) + __slots__ = ('load_alias', + 'dump_alias', + 'skip', + 'path') load_alias: str | None dump_alias: str | None # keys: tuple[str, ...] | PathType - + skip: bool path: PathType | None # In Python 3.10, dataclasses adds a new parameter to the :class:`Field` @@ -218,6 +223,7 @@ class Field(_Field): def __init__(self, load_alias: str | None, dump_alias: str | None, + skip: bool, path: PathType, default, default_factory, init, repr, hash, compare, metadata, kw_only): ... @@ -226,6 +232,7 @@ class Field(_Field): def __init__(self, alias: str | None, load_alias: str | None, dump_alias: str | None, + skip: bool, path: PathType, default, default_factory, init, repr, hash, compare, metadata): ... diff --git a/tests/unit/test_load.py b/tests/unit/test_load.py index 53c2134..26f8f58 100644 --- a/tests/unit/test_load.py +++ b/tests/unit/test_load.py @@ -2034,7 +2034,7 @@ def test_from_dict_with_nested_object_key_path(): """ @dataclass - class A(JSONWizard, debug=True): + class A(JSONWizard): an_int: int a_bool: Annotated[bool, KeyPath('x.y.z.0')] my_str: str = path_field(['a', 'b', 'c', -1], default='xyz') @@ -2123,7 +2123,7 @@ def test_from_dict_with_nested_object_key_path_with_skip_defaults(): """ @dataclass - class A(JSONWizard, debug=True): + class A(JSONWizard): class _(JSONWizard.Meta): skip_defaults = True @@ -2267,7 +2267,7 @@ class B: extra: CatchAll = None @dataclass - class Container(JSONWizard, debug=False): + class Container(JSONWizard): obj2: Union[A, B] extra: CatchAll = None @@ -2302,7 +2302,7 @@ def test_skip_if(): skip serializing dataclass fields. """ @dataclass - class Example(JSONWizard, debug=True): + class Example(JSONWizard): class _(JSONWizard.Meta): skip_if = IS_NOT(True) key_transform_with_dump = 'NONE' @@ -2322,7 +2322,7 @@ def test_skip_defaults_if(): skip serializing dataclass fields with default values. """ @dataclass - class Example(JSONWizard, debug=True): + class Example(JSONWizard): class _(JSONWizard.Meta): key_transform_with_dump = 'None' skip_defaults_if = IS(None) @@ -2355,7 +2355,7 @@ def test_per_field_skip_if(): ``skip_if_field()`` which wraps ``dataclasses.Field``. """ @dataclass - class Example(JSONWizard, debug=True): + class Example(JSONWizard): class _(JSONWizard.Meta): key_transform_with_dump = 'None' diff --git a/tests/unit/v1/test_loaders.py b/tests/unit/v1/test_loaders.py index 2ae5618..e0eb3c2 100644 --- a/tests/unit/v1/test_loaders.py +++ b/tests/unit/v1/test_loaders.py @@ -2522,11 +2522,9 @@ class _(JSONWizard.Meta): skip_defaults = True an_int: Annotated[int, AliasPath('my."test value"[here!][0]')] - # a_bool: Annotated[bool, AliasPath('x.y.z.-1', all=False)] - # my_str: Annotated[str, AliasPath(['a', 'b', 'c', -1], dump=False)] = 'xyz1' - a_bool: Annotated[bool, AliasPath('x.y.z.-1')] - my_str: Annotated[str, AliasPath(['a', 'b', 'c', -1])] = 'xyz1' + a_bool: Annotated[bool, AliasPath(load='x.y.z.-1')] + my_str: Annotated[str, AliasPath(['a', 'b', 'c', -1], skip=True)] = 'xyz1' other_bool: bool = AliasPath('x.y."z z"', default=True)