Closed acepace closed 3 years ago
This seems to have been reported in the RedHat bug tracker https://bugzilla.redhat.com/show_bug.cgi?id=1838327
I've tried the latest version 1.5.1 and this still happens in my machine
just ran into this bug as well:
>>> from dacite import from_dict
>>> from dataclasses import dataclass, field
>>> from typing import Dict
>>>
>>> @dataclass
... class MyDC:
... name: str
... stuff: Dict = field(default_factory=dict)
...
...
>>> stuffdict = {"one": 1, "two": 2}
>>> mydict = {"name": "myname", "stuff": stuffdict}
>>> from_dict(MyDC, mydict)
Traceback (most recent call last):
File "<input>", line 1, in <module>
from_dict(MyDC, mydict)
File "/Users/zach/.virtualenvs/dacite_test/lib/python3.9/site-packages/dacite/core.py", line 57, in from_dict
transformed_value = transform_value(
File "/Users/zach/.virtualenvs/dacite_test/lib/python3.9/site-packages/dacite/types.py", line 28, in transform_value
key_cls, item_cls = extract_generic(target_type)
ValueError: not enough values to unpack (expected 2, got 0)
>>>
As a workaround, it appears if you type-hint the contents of the collection, even using typing.Any
, it works:
>>> from typing import Any
>>> @dataclass
... class MyDC:
... name: str
... stuff: Dict[Any, Any] = field(default_factory=dict)
...
...
>>> from_dict(MyDC, mydict)
MyDC(name='myname', stuff={'one': 1, 'two': 2})
I think a patch should be pretty straightforward; I'll see if I can do it and submit a PR.
extract_generic()
a default=()
kwarg:
def extract_generic(type_: Type, default=()) -> tuple:
key_cls, item_cls = extract_generic(target_type, default=(Any, Any))
item_cls = extract_generic(target_type, default=(Any,))[0]
I do think though, that if you have a collection of mixed & matched dataclass types, there may be no solution, because for those, dacite needs to know the classes explicitly in order to instantiate them
So if we had:
@dataclass
class MyDC:
stuff: Dict[Any, Any]
@dataclass
class MyOtherDC:
pass
@dataclass
class MyOtherOtherDC:
pass
my_dataclass_thing_1 = MyOtherDC()
my_dataclass_thing_2 = MyOtherOtherDC()
And stuff looked like:
{
"my_other_dc": my_dataclass_thing_1,
"my_other_other_dc": my_dataclass_thing_2
}
Then dacite
won't be able to work out from the (Any, Any)
type tuples what object types to instantiate.
So a collection of mixed types just isn't possible if any of the types are dataclass
es, if I'm not mistaken.
Thank you @acepace for reporting this issue. It should be fixed in master
.
@zcutlip thank you for the simple and clean solution.
Thanks for the quick patch. I'm glad I procrastinated and didn't send you a PR because you caught some changes I would have missed.
I seem to have failures when using latest dacite with an object of type Dict.
key_cls, item_cls = extract_generic(target_type)
if target_type is List or Dict I get a zero length tuple rather than the expected two values.