Source code for svarog.svarog

import sys
from functools import lru_cache
from typing import Any
from typing import Dict
from typing import Type
from typing import TypeVar

from .checks import has_annotated_init
from .checks import is_list
from .checks import is_mapping
from .checks import is_union
from .compat import ForwardRef
from .dispatchers.multi import MultiDispatcher
from .forges import _clean_annotations
from .forges import forge_annotated_init
from .forges import forge_list
from .forges import forge_mapping
from .forges import forge_none
from .forges import forge_union
from .types import CannotDispatch
from .types import Check
from .types import Forge
from .types import NoneType

T = TypeVar("T")


[docs]class Svarog: _refs_owners: Dict[ForwardRef, Type] def __init__(self): self._refs_owners = {} self._dispatcher = MultiDispatcher() self._dispatcher.register_cls(NoneType, forge_none) self._dispatcher.register_func(has_annotated_init, forge_annotated_init) self._dispatcher.register_func(is_list, forge_list) self._dispatcher.register_func(is_mapping, forge_mapping) self._dispatcher.register_func(is_union, forge_union)
[docs] def register_forge(self, type_: Type, forge: Forge) -> None: self._dispatcher.register_cls(type_, forge)
[docs] def register_mold(self, check: Check, forge: Forge) -> None: self._dispatcher.register_func(check, forge)
@lru_cache(None) def _update_forward_ref_owners_registry(self, type_: Type) -> None: def update_subtype(sub_type: Type) -> None: if isinstance(sub_type, ForwardRef): self._refs_owners[sub_type] = type_ if ( not isinstance(sub_type, NoneType) # type: ignore and sub_type is not Any and hasattr(sub_type, "__args__") ): for sub_type in annotation.__args__: update_subtype(sub_type) for _, annotation in _clean_annotations(type_.__init__): update_subtype(annotation)
[docs] def forge(self, type_: Type[T], data: Any) -> T: if isinstance(type_, ForwardRef): type_ = self._resolve_forward_ref(type_) if has_annotated_init(type_): self._update_forward_ref_owners_registry(type_) if type_ is Any: return data handler = self._dispatcher.dispatch(type_) try: return handler(type_, data, self.forge) except CannotDispatch: return type_(data) # type: ignore
def _resolve_forward_ref(self, type_: ForwardRef) -> Type: try: owner: Type = self._refs_owners[type_] except KeyError: raise RuntimeError(f"Unknown forward ref: {type_}") return type_._evaluate( # type: ignore vars(sys.modules[owner.__module__]), getattr(owner, "__dict__", {}) )