"""
Contains implementations for Abstract Base Classes
"""
from __future__ import annotations
import json
from abc import ABC, abstractmethod
from dataclasses import dataclass, InitVar, Field
from typing import Type, TypeVar, Dict, Generic, TYPE_CHECKING
from .models import Extras
from .type_def import T, TT
# Create a generic variable that can be 'AbstractJSONWizard', or any subclass.
W = TypeVar('W', bound='AbstractJSONWizard')
if TYPE_CHECKING:
from .v1.models import Extras as V1Extras, TypeInfo
[docs]
class AbstractEnvWizard(ABC):
"""
Abstract class that defines the methods a sub-class must implement at a
minimum to be considered a "true" Environment Wizard.
"""
__slots__ = ()
# Extends the `__annotations__` attribute to return only the fields
# (variables) of the `EnvWizard` subclass.
#
# .. NOTE::
# This excludes fields marked as ``ClassVar``, or ones which are
# not type-annotated.
__fields__: dict[str, Field]
[docs]
@abstractmethod
def to_dict(self):
...
[docs]
@abstractmethod
def to_json(self, indent=None):
...
[docs]
class AbstractJSONWizard(ABC):
__slots__ = ()
[docs]
@classmethod
@abstractmethod
def from_json(cls, string):
...
[docs]
@classmethod
@abstractmethod
def from_list(cls, o):
...
[docs]
@classmethod
@abstractmethod
def from_dict(cls, o):
...
[docs]
@abstractmethod
def to_dict(self):
...
[docs]
@abstractmethod
def to_json(self, *,
encoder=json.dumps,
indent=None,
**encoder_kwargs):
...
[docs]
@classmethod
@abstractmethod
def list_to_json(cls,
instances,
encoder=json.dumps,
indent=None,
**encoder_kwargs):
...
[docs]
@dataclass
class AbstractParser(ABC, Generic[T, TT]):
__slots__ = ('base_type', )
# Please see `abstractions.pyi` for documentation on each field.
cls: InitVar[Type]
extras: InitVar[Extras]
base_type: type[T]
def __contains__(self, item):
return type(item) is self.base_type
@abstractmethod
def __call__(self, o) -> TT:
...
[docs]
class AbstractLoader(ABC):
__slots__ = ()
[docs]
@staticmethod
@abstractmethod
def default_load_to(o, _):
...
[docs]
@staticmethod
@abstractmethod
def load_after_type_check(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_str(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_int(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_float(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_bool(o, _):
...
[docs]
@staticmethod
@abstractmethod
def load_to_enum(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_uuid(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_iterable(
o, base_type,
elem_parser):
...
[docs]
@staticmethod
@abstractmethod
def load_to_tuple(
o, base_type,
elem_parsers):
...
[docs]
@staticmethod
@abstractmethod
def load_to_named_tuple(
o, base_type,
field_to_parser,
field_parsers):
...
[docs]
@staticmethod
@abstractmethod
def load_to_named_tuple_untyped(
o, base_type,
dict_parser, list_parser):
...
[docs]
@staticmethod
@abstractmethod
def load_to_dict(
o, base_type,
key_parser,
val_parser):
...
[docs]
@staticmethod
@abstractmethod
def load_to_defaultdict(
o, base_type,
default_factory,
key_parser,
val_parser):
...
[docs]
@staticmethod
@abstractmethod
def load_to_typed_dict(
o, base_type,
key_to_parser,
required_keys,
optional_keys):
...
[docs]
@staticmethod
@abstractmethod
def load_to_decimal(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_datetime(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_time(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_date(o, base_type):
...
[docs]
@staticmethod
@abstractmethod
def load_to_timedelta(o, base_type):
...
# @staticmethod
# @abstractmethod
# def load_func_for_dataclass(
# cls: Type[T],
# config: Optional[META],
# ) -> Callable[[JSONObject], T]:
# """
# Generate and return the load function for a (nested) dataclass of
# type `cls`.
# """
[docs]
@classmethod
@abstractmethod
def get_parser_for_annotation(cls, ann_type,
base_cls=None,
extras=None):
...
[docs]
class AbstractDumper(ABC):
__slots__ = ()
[docs]
class AbstractLoaderGenerator(ABC):
"""
Abstract code generator which defines helper methods to generate the
code for deserializing an object `o` of a given annotated type into
the corresponding dataclass field during dynamic function construction.
"""
__slots__ = ()
[docs]
@staticmethod
@abstractmethod
def is_none(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate the condition to determine if a value is None.
"""
[docs]
@staticmethod
@abstractmethod
def load_fallback(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code for the fallback load handler when no specialized type matches.
The default fallback implementation is typically an identity / passthrough,
but subclasses may override this behavior.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_str(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to load a value into a string field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_int(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to load a value into an integer field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_float(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a float field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_bool(_: str, extras: V1Extras) -> str:
"""
Generate code to load a value into a boolean field.
Adds a helper function `as_bool` to the local context.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_bytes(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a bytes field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_bytearray(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a bytearray field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_none(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to load a value into a None.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_literal(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to confirm a value is equivalent to one
of the provided literals.
"""
[docs]
@classmethod
@abstractmethod
def load_to_union(cls, tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a `Union[X, Y, ...]` (one of [X, Y, ...] possible types)
"""
[docs]
@staticmethod
@abstractmethod
def load_to_enum(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into an Enum field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_uuid(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a UUID field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_iterable(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into an iterable field (list, set, etc.).
"""
[docs]
@staticmethod
@abstractmethod
def load_to_tuple(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a tuple field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_named_tuple(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a named tuple field.
"""
[docs]
@classmethod
@abstractmethod
def load_to_named_tuple_untyped(cls, tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into an untyped named tuple.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_dict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a dictionary field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_defaultdict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a defaultdict field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_typed_dict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a typed dictionary field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_decimal(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a Decimal field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_path(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a Decimal field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_datetime(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to load a value into a datetime field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_time(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to load a value into a time field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_date(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a date field.
"""
[docs]
@staticmethod
@abstractmethod
def load_to_timedelta(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a timedelta field.
"""
[docs]
@staticmethod
def load_to_dataclass(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to load a value into a `dataclass` type field.
"""
[docs]
@classmethod
@abstractmethod
def load_dispatcher_for_annotation(cls,
tp: TypeInfo,
extras: V1Extras) -> 'str | TypeInfo':
"""
Resolve the load dispatcher for a given annotation type.
Returns either a string reference to a dispatcher or a TypeInfo object,
depending on how the annotation is handled.
`base_cls` is the original class object, useful when the annotated
type is a :class:`typing.ForwardRef` object.
"""
[docs]
class AbstractDumperGenerator(ABC):
"""
Abstract code generator which defines helper methods to generate the
code for deserializing an object `o` of a given annotated type into
the corresponding dataclass field during dynamic function construction.
"""
__slots__ = ()
[docs]
@staticmethod
@abstractmethod
def dump_fallback(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code for the fallback dump handler when no specialized type matches.
The default fallback implementation is typically an identity / passthrough,
but subclasses may override this behavior.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_str(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to dump a value from a string field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_int(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to dump a value from an integer field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_float(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a float field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_bool(_: str, extras: V1Extras) -> str:
"""
Generate code to dump a value from a boolean field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_bytes(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a bytes field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_bytearray(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a bytearray field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_none(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to dump a value from a None.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_literal(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a literal.
"""
[docs]
@classmethod
@abstractmethod
def dump_from_union(cls, tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a `Union[X, Y, ...]` (one of [X, Y, ...] possible types)
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_enum(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from an Enum field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_uuid(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a UUID field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_iterable(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from an iterable field (list, set, etc.).
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_tuple(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a tuple field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_named_tuple(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a named tuple field.
"""
[docs]
@classmethod
@abstractmethod
def dump_from_named_tuple_untyped(cls, tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from an untyped named tuple.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_dict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a dictionary field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_defaultdict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a defaultdict field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_typed_dict(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a typed dictionary field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_decimal(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a Decimal field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_path(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a Decimal field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_datetime(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to dump a value from a datetime field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_time(tp: TypeInfo, extras: V1Extras) -> str:
"""
Generate code to dump a value from a time field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_date(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a date field.
"""
[docs]
@staticmethod
@abstractmethod
def dump_from_timedelta(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a timedelta field.
"""
[docs]
@staticmethod
def dump_from_dataclass(tp: TypeInfo, extras: V1Extras) -> 'str | TypeInfo':
"""
Generate code to dump a value from a `dataclass` type field.
"""
[docs]
@classmethod
@abstractmethod
def dump_dispatcher_for_annotation(cls,
tp: TypeInfo,
extras: V1Extras) -> 'str | TypeInfo':
"""
Resolve the dump dispatcher for a given annotation type.
Returns either a string reference to a dispatcher or a TypeInfo object,
depending on how the annotation is handled.
`base_cls` is the original class object, useful when the annotated
type is a :class:`typing.ForwardRef` object.
"""