Skip to content

Instantly share code, notes, and snippets.

@slavfox
Last active February 17, 2020 20:31
Show Gist options
  • Save slavfox/c917d380d4f3813454ca5c87f879ab70 to your computer and use it in GitHub Desktop.
Save slavfox/c917d380d4f3813454ca5c87f879ab70 to your computer and use it in GitHub Desktop.
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