The standard library in 3.7 can recursively convert a dataclass into a dict (example from the docs):
from dataclasses import dataclass, asdict
from typing im
undictify is a library which could be of help. Here is a minimal usage example:
import json
from dataclasses import dataclass
from typing import List, NamedTuple, Optional, Any
from undictify import type_checked_constructor
@type_checked_constructor(skip=True)
@dataclass
class Heart:
weight_in_kg: float
pulse_at_rest: int
@type_checked_constructor(skip=True)
@dataclass
class Human:
id: int
name: str
nick: Optional[str]
heart: Heart
friend_ids: List[int]
tobias_dict = json.loads('''
{
"id": 1,
"name": "Tobias",
"heart": {
"weight_in_kg": 0.31,
"pulse_at_rest": 52
},
"friend_ids": [2, 3, 4, 5]
}''')
tobias = Human(**tobias_dict)
from validated_dc import ValidatedDC
from dataclasses import dataclass
from typing import List, Union
@dataclass
class Foo(ValidatedDC):
foo: int
@dataclass
class Bar(ValidatedDC):
bar: Union[Foo, List[Foo]]
foo = {'foo': 1}
instance = Bar(bar=foo)
print(instance.get_errors()) # None
print(instance) # Bar(bar=Foo(foo=1))
list_foo = [{'foo': 1}, {'foo': 2}]
instance = Bar(bar=list_foo)
print(instance.get_errors()) # None
print(instance) # Bar(bar=[Foo(foo=1), Foo(foo=2)])
validated_dc:
https://github.com/EvgeniyBurdin/validated_dc
And see a more detailed example:
https://github.com/EvgeniyBurdin/validated_dc/blob/master/examples/detailed.py
You can use mashumaro for creating dataclass object from a dict according to the scheme. Mixin from this library adds convenient from_dict
and to_dict
methods to dataclasses:
from dataclasses import dataclass
from typing import List
from mashumaro import DataClassDictMixin
@dataclass
class Point(DataClassDictMixin):
x: int
y: int
@dataclass
class C(DataClassDictMixin):
mylist: List[Point]
p = Point(10, 20)
tmp = {'x': 10, 'y': 20}
assert p.to_dict() == tmp
assert Point.from_dict(tmp) == p
c = C([Point(0, 0), Point(10, 4)])
tmp = {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}
assert c.to_dict() == tmp
assert C.from_dict(tmp) == c
Using no additional modules, you can make use of the __post_init__ function to automatically convert the dict
values to the correct type. This function is called after __init__
.
from dataclasses import dataclass, asdict
@dataclass
class Bar:
fee: str
far: str
@dataclass
class Foo:
bar: Bar
def __post_init__(self):
if isinstance(self.bar, dict):
self.bar = Bar(**self.bar)
foo = Foo(bar=Bar(fee="La", far="So"))
d= asdict(foo)
print(d) # {'bar': {'fee': 'La', 'far': 'So'}}
o = Foo(**d)
print(o) # Foo(bar=Bar(fee='La', far='So'))
This solution has the added benefit of being able to use non-dataclass objects. As long as its str
function can be converted back, it's fair game. For example, it can be used to keep str
fields as IP4Address
internally.