velai-workshop / velai /serialization /JsonSerializable.py
kratadata's picture
Upload folder via script
0f8b3a0 verified
import dataclasses
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Dict, TypeVar
from velai.serialization.JsonTypeSerializer import DefaultSerializer
from velai.serialization.serialization_utils import (
resolve_type_hints,
normalize_type_for_deserialization,
normalize_type_for_serialization,
)
T = TypeVar("T")
class JsonSerializable(ABC):
@abstractmethod
def to_dict(self: T) -> Dict[str, Any]:
raise NotImplementedError()
@classmethod
@abstractmethod
def from_dict(cls: type[T], data: dict[str, Any]) -> T:
raise NotImplementedError()
@abstractmethod
def update_from_dict(self: T, data: dict[str, Any]) -> None:
raise NotImplementedError()
@dataclass
class DataclassJsonSerializable(JsonSerializable):
def to_dict(self: T) -> Dict[str, Any]:
result: Dict[str, Any] = {}
type_hints = resolve_type_hints(type(self))
for field in dataclasses.fields(self):
value = getattr(self, field.name)
hinted_type = type_hints[field.name]
source_type = normalize_type_for_serialization(hinted_type)
result[field.name] = DefaultSerializer.serialize(
value,
source_type=source_type,
)
return result
@classmethod
def from_dict(cls: type[T], data: Dict[str, Any]) -> T:
parsed_data = cls._parse_fields(data)
return cls(**parsed_data)
def update_from_dict(self: T, data: dict[str, Any]) -> None:
parsed_data = type(self)._parse_fields(data)
for key, value in parsed_data.items():
setattr(self, key, value)
@classmethod
def _parse_fields(cls, data: Dict[str, Any]) -> Dict[str, Any]:
type_hints = resolve_type_hints(cls)
parsed_data: Dict[str, Any] = {}
for key, value in data.items():
if key not in type_hints:
continue
if value is None:
parsed_data[key] = None
continue
target_type = normalize_type_for_deserialization(type_hints[key])
parsed_data[key] = DefaultSerializer.de_serialize(
value,
target_type=target_type,
)
return parsed_data