53 lines
1.4 KiB
Python
53 lines
1.4 KiB
Python
import inspect
|
|
import json
|
|
import sys
|
|
from dataclasses import InitVar, asdict, dataclass, field, is_dataclass
|
|
from json import JSONEncoder
|
|
from typing import Any, Dict
|
|
|
|
from pydash.strings import snake_case
|
|
|
|
|
|
def get_annotations(obj):
|
|
if sys.version_info.minor >= 10 and hasattr(inspect, "get_annotations"):
|
|
return inspect.get_annotations(obj) # type: ignore
|
|
else:
|
|
return obj.__annotations__
|
|
|
|
|
|
class SerializeableJSONEncoder(JSONEncoder):
|
|
def default(self, o):
|
|
if is_dataclass(o):
|
|
return asdict(o)
|
|
return super().default(o)
|
|
|
|
|
|
encoder_kwargs = {}
|
|
if sys.version_info.minor >= 10:
|
|
encoder_kwargs["kw_only"] = True
|
|
encoder_kwargs["default"] = SerializeableJSONEncoder
|
|
|
|
|
|
@dataclass
|
|
class Serializeable:
|
|
encoder: InitVar[JSONEncoder] = field(**encoder_kwargs)
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]):
|
|
annotations = get_annotations(cls)
|
|
attributes = dict.keys(annotations)
|
|
snake_case_kwargs = {
|
|
snake_case(k): data.get(k) for k in data if snake_case(k) in attributes
|
|
}
|
|
snake_case_kwargs["encoder"] = snake_case_kwargs.get(
|
|
"encoder", SerializeableJSONEncoder
|
|
)
|
|
return cls(**snake_case_kwargs) # type: ignore
|
|
|
|
@property
|
|
def __dict__(self) -> Dict[str, Any]:
|
|
return asdict(self)
|
|
|
|
def to_json(self):
|
|
return json.dumps(self, cls=self.encoder) # type: ignore
|