Skip to content

Instantly share code, notes, and snippets.

@laundmo
Created February 15, 2022 15:54
Show Gist options
  • Save laundmo/3bb574545f47ed274fc83bdcc07e2c59 to your computer and use it in GitHub Desktop.
Save laundmo/3bb574545f47ed274fc83bdcc07e2c59 to your computer and use it in GitHub Desktop.
very basic roundtrip dataclass to json-serializeable dict using converters per exact type
# I often find myself wanting a easy way to define custom converters for
# converting dataclasses to and from dicts, but don't want to import
# another dependency (dataclass_factory). In this example i'm converting datetimes.
# published as MIT license: https://opensource.org/licenses/MIT
from dataclasses import dataclass, fields
from datetime import datetime
from typing import List
def strs_to_dts(strs: List[str]) -> List[datetime]:
return list(map(datetime.fromisoformat, strs))
def dts_to_strs(dts: List[datetime]) -> List[str]:
return list(map(datetime.isoformat, dts))
# types not listed in the converters will have the value passed into the type for both conversions: int(value)
converters = {
List[datetime]: (strs_to_dts, dts_to_strs),
datetime: (datetime.fromisoformat, datetime.isoformat),
}
@dataclass
class Test:
a: List[datetime]
b: int
c: datetime
def as_dict(self):
result = {}
for item in fields(self):
from_dict, to_dict = converters.get(item.type, (item.type, item.type))
result[item.name] = to_dict(getattr(self, item.name))
return result
@classmethod
def from_dict(cls, data):
kwargs = {}
for item in fields(cls):
from_dict, to_dict = converters.get(item.type, (item.type, item.type))
kwargs[item.name] = from_dict(data[item.name])
return cls(**kwargs)
m1 = Test(a=[datetime.now(), datetime.now()], b=1, c=datetime.now())
print(m1.as_dict()) # {'a': ['2022-02-15T16:36:13.744117', '2022-02-15T16:36:13.744117'], 'b': 1, 'c': '2022-02-15T16:36:13.744117'}
print(m1 == Test.from_dict(m1.as_dict())) # True
print(Test.from_dict(m1.as_dict())) # Test(a=[datetime.datetime(2022, 2, 15, 16, 36, 13, 744117), datetime.datetime(2022, 2, 15, 16, 36, 13, 744117)], b=1, c=datetime.datetime(2022, 2, 15, 16, 36, 13, 744117))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment