Last active
February 17, 2020 20:31
-
-
Save slavfox/c917d380d4f3813454ca5c87f879ab70 to your computer and use it in GitHub Desktop.
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
from typing import List, Dict, Type | |
from dataclasses import dataclass | |
# importing separately to make clear which names come from dataclasses | |
import dataclasses | |
from pprint import pprint | |
import json | |
JSON_TYPES = [str, int, dict, float, bool, tuple, list, type(None)] | |
def deserialize_dataclasses(dct): | |
if "__dataclass__" in dct: | |
dataclass_ = DataclassFriendlyJsonEncoder.__dataclassses__[dct["__dataclass__"]] | |
del dct["__dataclass__"] | |
return dataclass_( | |
**{ | |
k: v if not isinstance(v, dict) else deserialize_dataclasses(v) | |
for k, v in dct.items() | |
} | |
) | |
return dct | |
class DataclassFriendlyJsonEncoder(json.JSONEncoder): | |
__dataclassses__: Dict[str, Type] = {} | |
def default(self, obj): | |
if dataclasses.is_dataclass(obj): | |
return { | |
**dict(__dataclass__=obj.__class__.__name__), | |
**{ | |
field.name: self.default(getattr(obj, field.name)) | |
for field in dataclasses.fields(obj) | |
}, | |
} | |
elif type(obj) in JSON_TYPES: | |
return obj | |
super(DataclassFriendlyJsonEncoder, self).default(obj) | |
def register_dataclass(cls): | |
DataclassFriendlyJsonEncoder.__dataclassses__[cls.__name__] = cls | |
return cls | |
@register_dataclass | |
@dataclass | |
class Bar: | |
a: str | |
b: str | |
@register_dataclass | |
@dataclass | |
class Foo: | |
a: str | |
b: List[int] | |
bar: Bar | |
foo = Foo("a", [1, 2], Bar("a", "b")) | |
foojson = json.dumps(foo, cls=DataclassFriendlyJsonEncoder) | |
pprint(json.loads(foojson, object_hook=deserialize_dataclasses)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment