Source code for kaiju_tools.encoding
"""Object serialization interfaces and classes."""
from enum import Enum
import msgspec
__all__ = [
'MimeType',
'dumps', 'loads',
'msgpack_dumps', 'msgpack_loads',
'yaml_dumps', 'yaml_loads',
'ENCODERS'
]
[docs]class Serializable:
"""Class which supports serialization of its attributes."""
serializable_attrs = None #: Should be a frozenset or None. If None, then all will be used for serialization.
include_null_values = True #: include null values in a representation
[docs] def repr(self) -> dict:
"""Must return a representation of object __init__ arguments."""
_repr = {}
if self.serializable_attrs is None:
if hasattr(self, '__slots__'):
for slot in self.__slots__:
if not slot.startswith('_') and hasattr(self, slot):
v = getattr(self, slot)
if not self.include_null_values and v is None:
continue
if isinstance(v, Serializable):
_repr[slot] = v.repr()
else:
_repr[slot] = v
else:
for k, v in self.__dict__.items():
if not self.include_null_values and v is None:
continue
if not k.startswith('_'):
if isinstance(v, Serializable):
_repr[k] = v.repr()
else:
_repr[k] = v
else:
if hasattr(self, '__slots__'):
for slot in self.__slots__:
if slot in self.serializable_attrs and hasattr(self, slot):
v = getattr(self, slot)
if not self.include_null_values and v is None:
continue
if isinstance(v, Serializable):
_repr[slot] = v.repr()
else:
_repr[slot] = v
else:
for k, v in self.__dict__.items():
if not self.include_null_values and v is None:
continue
if k in self.serializable_attrs:
if isinstance(v, Serializable):
_repr[k] = v.repr()
else:
_repr[k] = v
return _repr
def __repr__(self):
return f'<{self.__class__.__name__}(**{self.repr()})>'
class SerializedClass(Serializable):
"""Serialized class."""
def repr(self) -> dict:
return {'__cls': self.__class__.__name__, '__attrs': super().repr()}
@classmethod
def from_repr(cls, attrs: dict):
return cls(**attrs) # noqa
class MimeType(Enum):
"""Standard data types."""
json = 'application/json'
msgpack = 'application/msgpack'
yaml = 'application/yaml'
_ExtType = msgspec.msgpack.Ext
def enc_hook_msgpack(obj):
if isinstance(obj, Serializable):
return obj.repr()
raise NotImplementedError(f"Objects of type {obj} are not supported")
def enc_hook(obj):
if isinstance(obj, Serializable):
return obj.repr()
raise NotImplementedError(f"Objects of type {obj} are not supported")
_json_encoder = msgspec.json.Encoder(enc_hook=enc_hook)
_json_decoder = msgspec.json.Decoder()
_msgpack_encoder = msgspec.msgpack.Encoder(enc_hook=enc_hook_msgpack)
_msgpack_decoder = msgspec.msgpack.Decoder()
dumps = _json_encoder.encode
loads = _json_decoder.decode
msgpack_dumps = _msgpack_encoder.encode
msgpack_loads = _msgpack_decoder.decode
yaml_dumps = msgspec.yaml.encode
yaml_loads = msgspec.yaml.decode
ENCODERS = {
MimeType.json.value: (dumps, loads),
MimeType.msgpack.value: (msgpack_dumps, msgpack_loads),
MimeType.yaml.value: (yaml_dumps, yaml_loads),
}