Module core.constructs.models

Set of utilities for working with immutable data within the framework

Expand source code
"""Set of utilities for working with immutable data within the framework
"""
from collections.abc import Mapping
from enum import Enum
from pydantic import BaseModel

from pydantic.utils import (
    ROOT_KEY,
    ValueItems,
    sequence_like,
)

from pydantic.typing import (
    is_namedtuple,
)

from typing import Any


class frozendict(Mapping):
    def __init__(self, d: dict):
        self._d = d

    def __iter__(self):
        return iter(self._d)

    def __len__(self):
        return len(self._d)

    def __getitem__(self, key):
        return self._d[key]

    def __hash__(self):
        return hash(tuple(sorted(self._d.items())))

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):

        if not (isinstance(v, frozendict)):

            raise TypeError(f"{v} Not Frozen Dict")

        return v

    def __repr__(self) -> str:
        return f"FrozenDict({self._d})"


class ImmutableModel(BaseModel):
    @classmethod
    def _get_value(
        cls,
        v: Any,
        to_dict: bool,
        by_alias: bool,
        include,
        exclude,
        exclude_unset: bool,
        exclude_defaults: bool,
        exclude_none: bool,
    ) -> Any:

        if isinstance(v, BaseModel):
            if to_dict:
                v_dict = frozendict(
                    v.dict(
                        by_alias=by_alias,
                        exclude_unset=exclude_unset,
                        exclude_defaults=exclude_defaults,
                        include=include,
                        exclude=exclude,
                        exclude_none=exclude_none,
                    )
                )
                if ROOT_KEY in v_dict:
                    return v_dict[ROOT_KEY]
                return v_dict
            else:
                return v.copy(include=include, exclude=exclude)

        value_exclude = ValueItems(v, exclude) if exclude else None
        value_include = ValueItems(v, include) if include else None

        if isinstance(v, dict):
            return frozendict(
                {
                    k_: cls._get_value(
                        v_,
                        to_dict=to_dict,
                        by_alias=by_alias,
                        exclude_unset=exclude_unset,
                        exclude_defaults=exclude_defaults,
                        include=value_include and value_include.for_element(k_),
                        exclude=value_exclude and value_exclude.for_element(k_),
                        exclude_none=exclude_none,
                    )
                    for k_, v_ in v.items()
                    if (not value_exclude or not value_exclude.is_excluded(k_))
                    and (not value_include or value_include.is_included(k_))
                }
            )

        elif sequence_like(v):
            seq_args = (
                cls._get_value(
                    v_,
                    to_dict=to_dict,
                    by_alias=by_alias,
                    exclude_unset=exclude_unset,
                    exclude_defaults=exclude_defaults,
                    include=value_include and value_include.for_element(i),
                    exclude=value_exclude and value_exclude.for_element(i),
                    exclude_none=exclude_none,
                )
                for i, v_ in enumerate(v)
                if (not value_exclude or not value_exclude.is_excluded(i))
                and (not value_include or value_include.is_included(i))
            )

            return (
                v.__class__(*seq_args)
                if is_namedtuple(v.__class__)
                else v.__class__(seq_args)
            )

        elif isinstance(v, Enum) and getattr(cls.Config, "use_enum_values", False):
            return v.value

        else:
            return v

    class Config:
        extra = "allow"
        frozen = True


def deep_convert_to_mutable(obj: Any) -> Any:
    """Given a nested data structure of python types, frozensets, and frozendicts, return a mutable object with the same data.

    Frozendicts are converted to standard python dicts and frozensets are converted to standard python lists

    Args:
        obj (Any): original object

    Returns:
        Any: mutable copy
    """
    if isinstance(obj, frozenset) or isinstance(obj, list) or isinstance(obj, set):
        return [deep_convert_to_mutable(x) for x in obj]
    elif isinstance(obj, frozendict) or isinstance(obj, dict):
        return {k: deep_convert_to_mutable(v) for k, v in obj.items()}
    else:
        return obj

Functions

def deep_convert_to_mutable(obj: Any) ‑> Any

Given a nested data structure of python types, frozensets, and frozendicts, return a mutable object with the same data.

Frozendicts are converted to standard python dicts and frozensets are converted to standard python lists

Args

obj : Any
original object

Returns

Any
mutable copy
Expand source code
def deep_convert_to_mutable(obj: Any) -> Any:
    """Given a nested data structure of python types, frozensets, and frozendicts, return a mutable object with the same data.

    Frozendicts are converted to standard python dicts and frozensets are converted to standard python lists

    Args:
        obj (Any): original object

    Returns:
        Any: mutable copy
    """
    if isinstance(obj, frozenset) or isinstance(obj, list) or isinstance(obj, set):
        return [deep_convert_to_mutable(x) for x in obj]
    elif isinstance(obj, frozendict) or isinstance(obj, dict):
        return {k: deep_convert_to_mutable(v) for k, v in obj.items()}
    else:
        return obj

Classes

class ImmutableModel (**data: Any)

Create a new model by parsing and validating input data from keyword arguments.

Raises ValidationError if the input data cannot be parsed to form a valid model.

Expand source code
class ImmutableModel(BaseModel):
    @classmethod
    def _get_value(
        cls,
        v: Any,
        to_dict: bool,
        by_alias: bool,
        include,
        exclude,
        exclude_unset: bool,
        exclude_defaults: bool,
        exclude_none: bool,
    ) -> Any:

        if isinstance(v, BaseModel):
            if to_dict:
                v_dict = frozendict(
                    v.dict(
                        by_alias=by_alias,
                        exclude_unset=exclude_unset,
                        exclude_defaults=exclude_defaults,
                        include=include,
                        exclude=exclude,
                        exclude_none=exclude_none,
                    )
                )
                if ROOT_KEY in v_dict:
                    return v_dict[ROOT_KEY]
                return v_dict
            else:
                return v.copy(include=include, exclude=exclude)

        value_exclude = ValueItems(v, exclude) if exclude else None
        value_include = ValueItems(v, include) if include else None

        if isinstance(v, dict):
            return frozendict(
                {
                    k_: cls._get_value(
                        v_,
                        to_dict=to_dict,
                        by_alias=by_alias,
                        exclude_unset=exclude_unset,
                        exclude_defaults=exclude_defaults,
                        include=value_include and value_include.for_element(k_),
                        exclude=value_exclude and value_exclude.for_element(k_),
                        exclude_none=exclude_none,
                    )
                    for k_, v_ in v.items()
                    if (not value_exclude or not value_exclude.is_excluded(k_))
                    and (not value_include or value_include.is_included(k_))
                }
            )

        elif sequence_like(v):
            seq_args = (
                cls._get_value(
                    v_,
                    to_dict=to_dict,
                    by_alias=by_alias,
                    exclude_unset=exclude_unset,
                    exclude_defaults=exclude_defaults,
                    include=value_include and value_include.for_element(i),
                    exclude=value_exclude and value_exclude.for_element(i),
                    exclude_none=exclude_none,
                )
                for i, v_ in enumerate(v)
                if (not value_exclude or not value_exclude.is_excluded(i))
                and (not value_include or value_include.is_included(i))
            )

            return (
                v.__class__(*seq_args)
                if is_namedtuple(v.__class__)
                else v.__class__(seq_args)
            )

        elif isinstance(v, Enum) and getattr(cls.Config, "use_enum_values", False):
            return v.value

        else:
            return v

    class Config:
        extra = "allow"
        frozen = True

Ancestors

  • pydantic.main.BaseModel
  • pydantic.utils.Representation

Subclasses

Class variables

var Config
class frozendict (d: dict)
Expand source code
class frozendict(Mapping):
    def __init__(self, d: dict):
        self._d = d

    def __iter__(self):
        return iter(self._d)

    def __len__(self):
        return len(self._d)

    def __getitem__(self, key):
        return self._d[key]

    def __hash__(self):
        return hash(tuple(sorted(self._d.items())))

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):

        if not (isinstance(v, frozendict)):

            raise TypeError(f"{v} Not Frozen Dict")

        return v

    def __repr__(self) -> str:
        return f"FrozenDict({self._d})"

Ancestors

  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container

Static methods

def validate(v)
Expand source code
@classmethod
def validate(cls, v):

    if not (isinstance(v, frozendict)):

        raise TypeError(f"{v} Not Frozen Dict")

    return v