-
Notifications
You must be signed in to change notification settings - Fork 109
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
When trying to deserialize a dictionary into a dataclass, if the class structure includes a dictionary with its key being an object, then a WrongTypeError
exception is raised.
To Reproduce
from dataclasses import dataclass
from dacite import Config, from_dict
from bson import ObjectId
@dataclass
class NiceObj:
a: str
b: str
@dataclass
class Foo:
d: dict[ObjectId, NiceObj]
tc = from_dict(Foo, {'d': {'4142434445464748494a4b4c': {"a": "1", "b": "2"}}}, config=Config(cast=[ObjectId]))
print(tc)
Expected behavior
In Dacite 1.7.0, this correctly gives the output
Foo(d={ObjectId('4142434445464748494a4b4c'): NiceObj(a='1', b='2')})
but in v1.8.0+ it outputs the following error
dacite.exceptions.WrongTypeError: wrong value type for field "d" - should be "dict" instead of value "{'4142434445464748494a4b4c': NiceObj(a='1', b='2')}" of type "dict"
Environment
- Python version: 3.11.4
dacite
version: 1.8.0
Additional context
- I think this is similar to dict cannot be matched if keys are specified as enums in dataclass #239 and Regression in handling type_hooks for dict keys between dacite version 1.7 and 1.8 #217
- Modifying the function
_build_value_for_collection
incore.py
to
def _build_value_for_collection(collection: Type, data: Any, config: Config) -> Any:
data_type = data.__class__
if isinstance(data, Mapping) and is_subclass(collection, Mapping):
key_type, item_type = extract_generic(collection, defaults=(Any, Any))
return data_type(
(_build_value(type_=key_type, data=key, config=config), # Modified this line
_build_value(type_=item_type, data=value, config=config))
for key, value in data.items())
elif isinstance(data, tuple) and is_subclass(collection, tuple):
if not data:
return data_type()
types = extract_generic(collection)
if len(types) == 2 and types[1] == Ellipsis:
return data_type(_build_value(type_=types[0], data=item, config=config) for item in data)
return data_type(
_build_value(type_=type_, data=item, config=config) for item, type_ in zip_longest(data, types)
)
elif isinstance(data, Collection) and is_subclass(collection, Collection):
item_type = extract_generic(collection, defaults=(Any,))[0]
return data_type(_build_value(type_=item_type, data=item, config=config) for item in data)
return data
helped. I essentially added a line to recursive build the key in addition to the value that was already being done in the isinstance(data, Mapping) and is_subclass(collection, Mapping)
condition. This was also noted in #217 (comment)
shaunc and DSchabserban
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working