Skip to content

Commit

Permalink
bugfix for dataclass in dict
Browse files Browse the repository at this point in the history
  • Loading branch information
rnag committed Dec 4, 2024
1 parent 1ec1608 commit a715be0
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
9 changes: 9 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
History
=======

0.32.1 (2024-12-04)
-------------------

**Bugfixes**

- Corrected logic in :class:`MappingParser` that assumed all parsers were
subclasses of :class:`AbstractParser` (:issue:`159`).
- Add test case to confirm intended functionality.

0.32.0 (2024-11-30)
-------------------

Expand Down
8 changes: 5 additions & 3 deletions dataclass_wizard/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ class MappingParser(AbstractParser[Type[M], M]):
__slots__ = ('hook',
'key_parser',
'val_parser',
'val_base_type')
'val_type')

base_type: Type[M]
hook: Callable[[Any, Type[M], AbstractParser, AbstractParser], M]
Expand All @@ -551,12 +551,12 @@ def __post_init__(self, cls: Type,
# Base type of the object which is instantiable
# ex. `Dict[str, Any]` -> `dict`
self.base_type: Type[M] = get_origin(self.base_type)
self.val_type = val_type

val_parser = get_parser(val_type, cls, extras)

self.key_parser = getattr(p := get_parser(key_type, cls, extras), '__call__', p)
self.val_parser = getattr(val_parser, '__call__', val_parser)
self.val_base_type = val_parser.base_type

def __call__(self, o: M) -> M:
return self.hook(o, self.base_type, self.key_parser, self.val_parser)
Expand All @@ -577,7 +577,9 @@ def __post_init__(self, cls: Type,
super().__post_init__(cls, extras, get_parser)

# The default factory argument to pass to the `defaultdict` subclass
self.default_factory: DefFactory = self.val_base_type
val_type = self.val_type
val_base_type = getattr(val_type, '__origin__', val_type)
self.default_factory: DefFactory = val_base_type

def __call__(self, o: DD) -> DD:
return self.hook(o, self.base_type, self.default_factory,
Expand Down
22 changes: 22 additions & 0 deletions tests/unit/test_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,3 +486,25 @@ class MyClass(JSONSerializable):
with expectation:
result = c.to_dict()
log.debug('Parsed object: %r', result)


def test_using_dataclass_in_dict():
"""
Using dataclass in a dictionary (i.e., dict[str, Test])
works as expected.
See https://github.com/rnag/dataclass-wizard/issues/159
"""
@dataclass
class Test:
field: str

@dataclass
class Config:
tests: dict[str, Test]

config = {"tests": {"test_a": {"field": "a"}, "test_b": {"field": "b"}}}

assert fromdict(Config, config) == Config(
tests={'test_a': Test(field='a'),
'test_b': Test(field='b')})

0 comments on commit a715be0

Please sign in to comment.