Last active
February 14, 2022 09:54
-
-
Save jhidding/ccece4b6184d5827c4a9a72ba399eed9 to your computer and use it in GitHub Desktop.
Convert a nested structure of dict and list to dataclasses
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import typing | |
from dataclasses import is_dataclass | |
def isgeneric(annot): | |
return hasattr(annot, "__origin__") \ | |
and hasattr(annot, "__args__") | |
def construct(annot, json): | |
"""Construct an object from a given type from a JSON stream. | |
The `annot` type should be one of: str, int, list[T], Optional[T], | |
or a dataclass, and the JSON data should match exactly the given | |
definitions in the dataclass hierarchy. | |
""" | |
if annot is str: | |
assert isinstance(json, str) | |
return json | |
if annot is int: | |
assert isinstance(json, int) | |
return json | |
if isgeneric(annot) and typing.get_origin(annot) is list: | |
assert isinstance(json, list) | |
return [construct(typing.get_args(annot)[0], item) for item in json] | |
if isgeneric(annot) and typing.get_origin(annot) is Union \ | |
and typing.get_args(annot)[1] is types.NoneType: | |
if json is None: | |
return None | |
else: | |
return construct(typing.get_args(annot)[0], json) | |
if is_dataclass(annot): | |
assert isinstance(json, dict) | |
arg_annot = typing.get_type_hints(annot) | |
assert all(k in json for k in arg_annot) | |
args = { k: construct(v, json[k]) | |
for k, v in arg_annot.items() } | |
return annot(**args) |
no I misunderstood, the json is already classes
construct(list(list()), [['a']['b']])
would work
Actually:
>>> construct(list[list[str]], [['a'],['b']])
[['a'],['b']]
which is a bit silly, but at least you have validated the schema. A better example:
@dataclass
class Pt:
a: int
b: int
construct(list[Pt], [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}])
#> [Pt(1, 2), Pt(3, 4)]
The proper way to go is to use the dacite
libary, which does pretty much the same (https://github.com/konradhalas/dacite)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Something like this?