3 """Utilities for dealing with Dataclasses. A non-official type hint and some
4 friendly wrappers around conversion to/from Dicts."""
7 from typing import Any, Dict, Protocol
10 class Dataclass(Protocol):
11 """Dataclass isn't really a first class type and therefore there is no offical
12 type hint for Dataclasses in Python (yet). If you need one, here's a suitable
13 stand in. Example usage::
15 def f(d: Dataclass) -> Any:
18 def g(d: Dict[str, Any]) -> Dataclass:
22 __dataclass_fields__: Dict
25 def dataclass_from_dict(dataclass: type[Dataclass], d: Dict[str, Any]) -> Dataclass:
26 """Given a Dataclass type and a dict, return a populated instance.
29 dataclass: the Class type to return an instance of
30 d: the dict to be used to populate the new instance
33 A constructed and populated dataclass instance.
35 >>> from dataclasses import dataclass
36 >>> from datetime import date
44 ... member_since: date
48 ... 'name': 'John Smith',
49 ... 'phone': '555-1234',
50 ... 'address': '994 Main St.',
52 ... 'member_since': date(2006, 5, 14),
55 >>> dataclass_from_dict(Record, d)
56 Record(name='John Smith', phone='555-1234', address='994 Main St.', age=26, member_since=datetime.date(2006, 5, 14))
58 fields = {f.name for f in dataclasses.fields(dataclass) if f.init}
59 filtered_args = {k: v for k, v in d.items() if k in fields}
60 return dataclass(**filtered_args)
63 def dataclass_to_dict(dataclass: Dataclass) -> Dict[str, Any]:
66 A dict-representation of a valid dataclass.
68 >>> from dataclasses import dataclass
69 >>> from datetime import date
77 ... member_since: date
79 >>> r = Record(name='Jane Doe', phone='555-1232', address='998 Main St.', age=23, member_since=date(2008, 3, 1))
80 >>> dataclass_to_dict(r)
81 {'name': 'Jane Doe', 'phone': '555-1232', 'address': '998 Main St.', 'age': 23, 'member_since': datetime.date(2008, 3, 1)}
83 assert dataclasses.is_dataclass(dataclass)
84 return dataclasses.asdict(dataclass)
87 if __name__ == '__main__':