Module xtelligent_serial.data_structs.struct_registry
Expand source code
from abc import ABC
from dataclasses import Field
from typing import Type, Mapping, Any
from ..registry import register_deserializer, deserialize
from .struct_descriptor import DescriptorInterface
dispatcher = {}
registries = {}
class FamilyRegistry(ABC):
@classmethod
def has(cls, t: Type) -> bool:
'''Returns True if the type is serialized by the registry.'''
raise NotImplementedError
def register_struct_family(descriptor: DescriptorInterface) -> FamilyRegistry:
def ds_struct(t: Type, raw_data: Mapping):
type_fields = {f.name:f for f in descriptor.get_fields(t)}
def pick_type(field: Field, value: Any) -> Type:
return field.type or type(value)
names_to_type = {k:pick_type(f, raw_data.get(k)) for k, f in type_fields.items()}
kwargs = {k: deserialize(names_to_type[k], v) for k, v in raw_data.items() if k in type_fields}
return t(**kwargs)
def register_specific_type(t: Type):
f = dispatcher.get(t)
if f:
return f
def ds(raw_data: Mapping): # pylint: disable=invalid-name
return ds_struct(t, raw_data)
dispatcher[t] = ds
return ds
class StructProxy(ABC):
@classmethod
def __subclasshook__(cls, subclass):
if descriptor.is_instance(subclass):
register_specific_type(subclass)
return True
return False
def ds_hook(raw_data, **kwargs): # check kwargs for type and dispatch accordingly.
t = kwargs.get('type')
if not t:
raise ValueError('No type argument supplied')
f = dispatcher.get(t)
if not f:
raise NotImplementedError(f'No serializer for type {t}')
return f(raw_data)
# Duplicate registrations cause ambiguous dispatch exceptions.
if descriptor.name in registries:
return registries[descriptor.name]
register_deserializer(StructProxy, ds_hook)
class Registry:
@classmethod
def has(cls, t: Type) -> bool:
return issubclass(t, StructProxy) and t in dispatcher
registries[descriptor.name] = Registry
return Registry
Functions
def register_struct_family(descriptor: DescriptorInterface) ‑> FamilyRegistry
-
Expand source code
def register_struct_family(descriptor: DescriptorInterface) -> FamilyRegistry: def ds_struct(t: Type, raw_data: Mapping): type_fields = {f.name:f for f in descriptor.get_fields(t)} def pick_type(field: Field, value: Any) -> Type: return field.type or type(value) names_to_type = {k:pick_type(f, raw_data.get(k)) for k, f in type_fields.items()} kwargs = {k: deserialize(names_to_type[k], v) for k, v in raw_data.items() if k in type_fields} return t(**kwargs) def register_specific_type(t: Type): f = dispatcher.get(t) if f: return f def ds(raw_data: Mapping): # pylint: disable=invalid-name return ds_struct(t, raw_data) dispatcher[t] = ds return ds class StructProxy(ABC): @classmethod def __subclasshook__(cls, subclass): if descriptor.is_instance(subclass): register_specific_type(subclass) return True return False def ds_hook(raw_data, **kwargs): # check kwargs for type and dispatch accordingly. t = kwargs.get('type') if not t: raise ValueError('No type argument supplied') f = dispatcher.get(t) if not f: raise NotImplementedError(f'No serializer for type {t}') return f(raw_data) # Duplicate registrations cause ambiguous dispatch exceptions. if descriptor.name in registries: return registries[descriptor.name] register_deserializer(StructProxy, ds_hook) class Registry: @classmethod def has(cls, t: Type) -> bool: return issubclass(t, StructProxy) and t in dispatcher registries[descriptor.name] = Registry return Registry
Classes
class FamilyRegistry
-
Helper class that provides a standard way to create an ABC using inheritance.
Expand source code
class FamilyRegistry(ABC): @classmethod def has(cls, t: Type) -> bool: '''Returns True if the type is serialized by the registry.''' raise NotImplementedError
Ancestors
- abc.ABC
Static methods
def has(t: Type) ‑> bool
-
Returns True if the type is serialized by the registry.
Expand source code
@classmethod def has(cls, t: Type) -> bool: '''Returns True if the type is serialized by the registry.''' raise NotImplementedError