Skip to content

Module omnipy.modules.general.models

Overview

View Source
from typing import Generic, Hashable, TypeAlias, TypeVar

from omnipy.data.model import Model

from omnipy.modules.general.typedefs import FrozenDict

from omnipy.util.helpers import is_iterable

class NotIterableExceptStrOrBytesModel(Model[object | None]):

    """

    Model describing any object that is not iterable, except for `str` and `bytes` types.

    As strings and bytes are iterable (over the characters/bytes) but also generally useful and

    often considered singular (or scalar) types, they are specifically allowed by this model.

    Examples:

        >>> from omnipy import NotIterableExceptStrOrBytesModel, print_exception

        >>>

        >>> NotIterableExceptStrOrBytesModel(1234)

        NotIterableExceptStrOrBytesModel(1234)

        >>> NotIterableExceptStrOrBytesModel('1234')

        NotIterableExceptStrOrBytesModel(1234)

        >>> with print_exception:

        ...     NotIterableExceptStrOrBytesModel((1, 2, 3, 4))

        ValidationError: 1 validation error for NotIterableExceptStrOrBytesModel

    Note:

        JsonScalarModel is a strict submodel of NotIterableExceptStrOrBytesModel in that all objects

        allowed by JsonScalarModel are also allowed by NotIterableExceptStrOrBytesModel.

    """

    @classmethod

    def _parse_data(cls, data: object) -> object:

        assert isinstance(data, str) or isinstance(data, bytes) or not is_iterable(data), \

            f'Data of type {type(data)} is iterable'

        return data

# TODO: Follow pydantic topic https://github.com/pydantic/pydantic/issues/6868 on MappingProxyType.

#       Used way too much energy to implement (and test) recursive frozen models, only to discover

#       that pydantic actually does not support MappingProxyType, which was hugely surprising.

#       Add tests on the immutability part once there is support for this.

# Note: see comments in omnipy.modules.json.models for more information on the basic organisation of

#       nested models.

#

# Private models

#

# Basic building block models

_KeyT = TypeVar('_KeyT', bound=str | Hashable)

_ValT = TypeVar('_ValT', bound=NotIterableExceptStrOrBytesModel | object)

_FrozenBaseT = TypeVar('_FrozenBaseT')

# class _FrozenScalarM(NotIterableExceptStrOrBytesModel):

#     ...

class _FrozenScalarM(Model[_ValT], Generic[_ValT]):

    _parse_data = NotIterableExceptStrOrBytesModel._parse_data

class _FrozenTupleBaseM(Model[tuple[_FrozenBaseT, ...]], Generic[_FrozenBaseT]):

    ...

class _FrozenDictBaseM(Model[FrozenDict[_KeyT, _FrozenBaseT]], Generic[_KeyT, _FrozenBaseT]):

    ...

class _FrozenTupleM(_FrozenTupleBaseM['_FrozenAnyUnion'], Generic[_ValT]):

    ...

#

# class _FrozenDictM(_FrozenDictBaseM[_KeyT, '_FrozenAnyUnion'], Generic[_KeyT, _ValT]):

#     ...

class _FrozenDictM(_FrozenDictBaseM[str | Hashable, '_FrozenAnyUnion'], Generic[_KeyT, _ValT]):

    ...

class _FrozenNoDictsM(_FrozenTupleBaseM['_FrozenNoDictsUnion'], Generic[_ValT]):

    ...

# class _FrozenNoTuplesM(_FrozenDictBaseM['_KeyT', '_FrozenNoTuplesUnion'], Generic[_KeyT, _ValT]):

#     ...

class _FrozenNoTuplesM(_FrozenDictBaseM[str | Hashable, '_FrozenNoTuplesUnion'],

                       Generic[_KeyT, _ValT]):

    ...

# TypeAliases

_FrozenAnyUnion: TypeAlias = \

    _FrozenScalarM[_ValT] | _FrozenTupleM[_ValT] | _FrozenDictM[_KeyT, _ValT]

_FrozenNoDictsUnion: TypeAlias = _FrozenScalarM[_ValT] | _FrozenNoDictsM[_ValT]

_FrozenNoTuplesUnion: TypeAlias = _FrozenScalarM[_ValT] | _FrozenNoTuplesM[_KeyT, _ValT]

# Basic models needs to update their forward_refs with type aliases declared above

_FrozenTupleM.update_forward_refs()

_FrozenDictM.update_forward_refs()

_FrozenNoDictsM.update_forward_refs()

_FrozenNoTuplesM.update_forward_refs()

#

# Exportable models

#

# General

class NestedFrozenDictsOrTuplesModel(Model[_FrozenAnyUnion], Generic[_KeyT, _ValT]):

    """

    Recursive model for nested immutable containers (FrozenDict and tuples). Not functional.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

class NestedFrozenTuplesModel(Model[_FrozenNoDictsM[_ValT]], Generic[_ValT]):

    """

    Recursive model for nested tuples.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

class NestedFrozenDictsModel(Model[_FrozenNoTuplesM[_KeyT, _ValT]], Generic[_KeyT, _ValT]):

    """

    Recursive model for nested FrozenDicts.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

Classes

NestedFrozenDictsModel

class NestedFrozenDictsModel(
    value: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    *,
    __root__: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    **data: Any
)

Recursive model for nested FrozenDicts.

Awaiting support for MappingProxyType in pydantic for the immutability to actually work. Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

View Source
class NestedFrozenDictsModel(Model[_FrozenNoTuplesM[_KeyT, _ValT]], Generic[_KeyT, _ValT]):

    """

    Recursive model for nested FrozenDicts.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

Class variables

Config

Static methods

to_json_schema
def to_json_schema(
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    @classmethod

    def to_json_schema(cls, pretty=False) -> str:

        schema = cls.schema()

        if pretty:

            return cls._pretty_print_json(schema)

        else:

            return json.dumps(schema)
validate
def validate(
    value: Any
) -> Model

Hack to allow overwriting of iter method without compromising pydantic validation. Part

of the pydantic API and not the Omnipy API.

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
Model
View Source
    @classmethod

    def validate(cls: Type['Model'], value: Any) -> 'Model':

        """

        Hack to allow overwriting of __iter__ method without compromising pydantic validation. Part

        of the pydantic API and not the Omnipy API.

        """

        if isinstance(value, Model):

            with AttribHolder(value, '__iter__', GenericModel.__iter__, on_class=True):

                return super().validate(value)

        else:

            return super().validate(value)

Instance variables

contents

Methods

delitem
def __delitem__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
eq
def __eq__(
    self,
    other: object
) -> bool

Return self==value.

Parameters:

Name Type Description Default
other object

Returns:

Type Description
bool
View Source
    def __eq__(self, other: object) -> bool:

        return isinstance(other, Model) \

            and self.__class__ == other.__class__ \

            and self.contents == other.contents \

            and self.to_data() == other.to_data()  # last is probably unnecessary, but just in case
getattr
def __getattr__(
    self,
    attr: str
) -> Any

Parameters:

Name Type Description Default
attr str

Returns:

Type Description
Any
View Source
    def __getattr__(self, attr: str) -> Any:

        ret = self._getattr_from_contents(attr)

        if callable(ret):

            ret = add_callback_after_call(ret, self.validate_contents)

        return ret
iter
def __iter__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
setattr
def __setattr__(
    self,
    attr: str,
    value: Any
) -> None

Implement setattr(self, name, value).

Parameters:

Name Type Description Default
attr str
value Any

Returns:

Type Description
NoneType
View Source
    def __setattr__(self, attr: str, value: Any) -> None:

        if attr in self.__dict__ and attr not in [ROOT_KEY]:

            super().__setattr__(attr, value)

        else:

            if attr in ['contents']:

                contents_prop = getattr(self.__class__, attr)

                contents_prop.__set__(self, value)

            else:

                raise RuntimeError('Model does not allow setting of extra attributes')
setitem
def __setitem__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
from_data
def from_data(
    self,
    value: Any
) -> None

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
NoneType
View Source
    def from_data(self, value: Any) -> None:

        self.contents = value
from_json
def from_json(
    self,
    json_contents: str
) -> None

Parameters:

Name Type Description Default
json_contents str

Returns:

Type Description
NoneType
View Source
    def from_json(self, json_contents: str) -> None:

        new_model = self.parse_raw(json_contents, proto=pydantic_protocol.json)

        self._set_contents_without_validation(new_model)
inner_type
def inner_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def inner_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=False, with_args=with_args)
is_nested_type
def is_nested_type(
    self
) -> bool

Returns:

Type Description
bool
View Source
    def is_nested_type(self) -> bool:

        return not self.inner_type(with_args=True) == self.outer_type(with_args=True)
outer_type
def outer_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def outer_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=True, with_args=with_args)
to_data
def to_data(
    self
) -> Any

Returns:

Type Description
Any
View Source
    def to_data(self) -> Any:

        return self.dict()[ROOT_KEY]
to_json
def to_json(
    self,
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    def to_json(self, pretty=False) -> str:

        json_content = self.json()

        if pretty:

            return self._pretty_print_json(json.loads(json_content))

        else:

            return json_content
validate_contents
def validate_contents(
    self
)
View Source
    def validate_contents(self):

        self.contents = self.contents

NestedFrozenDictsOrTuplesModel

class NestedFrozenDictsOrTuplesModel(
    value: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    *,
    __root__: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    **data: Any
)

Recursive model for nested immutable containers (FrozenDict and tuples). Not functional.

Awaiting support for MappingProxyType in pydantic for the immutability to actually work. Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

View Source
class NestedFrozenDictsOrTuplesModel(Model[_FrozenAnyUnion], Generic[_KeyT, _ValT]):

    """

    Recursive model for nested immutable containers (FrozenDict and tuples). Not functional.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

Class variables

Config

Static methods

to_json_schema
def to_json_schema(
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    @classmethod

    def to_json_schema(cls, pretty=False) -> str:

        schema = cls.schema()

        if pretty:

            return cls._pretty_print_json(schema)

        else:

            return json.dumps(schema)
validate
def validate(
    value: Any
) -> Model

Hack to allow overwriting of iter method without compromising pydantic validation. Part

of the pydantic API and not the Omnipy API.

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
Model
View Source
    @classmethod

    def validate(cls: Type['Model'], value: Any) -> 'Model':

        """

        Hack to allow overwriting of __iter__ method without compromising pydantic validation. Part

        of the pydantic API and not the Omnipy API.

        """

        if isinstance(value, Model):

            with AttribHolder(value, '__iter__', GenericModel.__iter__, on_class=True):

                return super().validate(value)

        else:

            return super().validate(value)

Instance variables

contents

Methods

delitem
def __delitem__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
eq
def __eq__(
    self,
    other: object
) -> bool

Return self==value.

Parameters:

Name Type Description Default
other object

Returns:

Type Description
bool
View Source
    def __eq__(self, other: object) -> bool:

        return isinstance(other, Model) \

            and self.__class__ == other.__class__ \

            and self.contents == other.contents \

            and self.to_data() == other.to_data()  # last is probably unnecessary, but just in case
getattr
def __getattr__(
    self,
    attr: str
) -> Any

Parameters:

Name Type Description Default
attr str

Returns:

Type Description
Any
View Source
    def __getattr__(self, attr: str) -> Any:

        ret = self._getattr_from_contents(attr)

        if callable(ret):

            ret = add_callback_after_call(ret, self.validate_contents)

        return ret
iter
def __iter__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
setattr
def __setattr__(
    self,
    attr: str,
    value: Any
) -> None

Implement setattr(self, name, value).

Parameters:

Name Type Description Default
attr str
value Any

Returns:

Type Description
NoneType
View Source
    def __setattr__(self, attr: str, value: Any) -> None:

        if attr in self.__dict__ and attr not in [ROOT_KEY]:

            super().__setattr__(attr, value)

        else:

            if attr in ['contents']:

                contents_prop = getattr(self.__class__, attr)

                contents_prop.__set__(self, value)

            else:

                raise RuntimeError('Model does not allow setting of extra attributes')
setitem
def __setitem__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
from_data
def from_data(
    self,
    value: Any
) -> None

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
NoneType
View Source
    def from_data(self, value: Any) -> None:

        self.contents = value
from_json
def from_json(
    self,
    json_contents: str
) -> None

Parameters:

Name Type Description Default
json_contents str

Returns:

Type Description
NoneType
View Source
    def from_json(self, json_contents: str) -> None:

        new_model = self.parse_raw(json_contents, proto=pydantic_protocol.json)

        self._set_contents_without_validation(new_model)
inner_type
def inner_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def inner_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=False, with_args=with_args)
is_nested_type
def is_nested_type(
    self
) -> bool

Returns:

Type Description
bool
View Source
    def is_nested_type(self) -> bool:

        return not self.inner_type(with_args=True) == self.outer_type(with_args=True)
outer_type
def outer_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def outer_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=True, with_args=with_args)
to_data
def to_data(
    self
) -> Any

Returns:

Type Description
Any
View Source
    def to_data(self) -> Any:

        return self.dict()[ROOT_KEY]
to_json
def to_json(
    self,
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    def to_json(self, pretty=False) -> str:

        json_content = self.json()

        if pretty:

            return self._pretty_print_json(json.loads(json_content))

        else:

            return json_content
validate_contents
def validate_contents(
    self
)
View Source
    def validate_contents(self):

        self.contents = self.contents

NestedFrozenTuplesModel

class NestedFrozenTuplesModel(
    value: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    *,
    __root__: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    **data: Any
)

Recursive model for nested tuples.

Awaiting support for MappingProxyType in pydantic for the immutability to actually work. Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

View Source
class NestedFrozenTuplesModel(Model[_FrozenNoDictsM[_ValT]], Generic[_ValT]):

    """

    Recursive model for nested tuples.

    Awaiting support for MappingProxyType in pydantic for the immutability to actually work.

    Also use as generic types awaits Python 3.13. Way ahead of the crowd here!

    """

Class variables

Config

Static methods

to_json_schema
def to_json_schema(
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    @classmethod

    def to_json_schema(cls, pretty=False) -> str:

        schema = cls.schema()

        if pretty:

            return cls._pretty_print_json(schema)

        else:

            return json.dumps(schema)
validate
def validate(
    value: Any
) -> Model

Hack to allow overwriting of iter method without compromising pydantic validation. Part

of the pydantic API and not the Omnipy API.

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
Model
View Source
    @classmethod

    def validate(cls: Type['Model'], value: Any) -> 'Model':

        """

        Hack to allow overwriting of __iter__ method without compromising pydantic validation. Part

        of the pydantic API and not the Omnipy API.

        """

        if isinstance(value, Model):

            with AttribHolder(value, '__iter__', GenericModel.__iter__, on_class=True):

                return super().validate(value)

        else:

            return super().validate(value)

Instance variables

contents

Methods

eq
def __eq__(
    self,
    other: object
) -> bool

Return self==value.

Parameters:

Name Type Description Default
other object

Returns:

Type Description
bool
View Source
    def __eq__(self, other: object) -> bool:

        return isinstance(other, Model) \

            and self.__class__ == other.__class__ \

            and self.contents == other.contents \

            and self.to_data() == other.to_data()  # last is probably unnecessary, but just in case
getattr
def __getattr__(
    self,
    attr: str
) -> Any

Parameters:

Name Type Description Default
attr str

Returns:

Type Description
Any
View Source
    def __getattr__(self, attr: str) -> Any:

        ret = self._getattr_from_contents(attr)

        if callable(ret):

            ret = add_callback_after_call(ret, self.validate_contents)

        return ret
iter
def __iter__(
    self,
    *args: object,
    **kwargs: object
) -> object

Parameters:

Name Type Description Default
args object
kwargs object

Returns:

Type Description
object
View Source
        def _method(cls_or_self, /, *args, **keywords):

            keywords = {**self.keywords, **keywords}

            return self.func(cls_or_self, *self.args, *args, **keywords)
setattr
def __setattr__(
    self,
    attr: str,
    value: Any
) -> None

Implement setattr(self, name, value).

Parameters:

Name Type Description Default
attr str
value Any

Returns:

Type Description
NoneType
View Source
    def __setattr__(self, attr: str, value: Any) -> None:

        if attr in self.__dict__ and attr not in [ROOT_KEY]:

            super().__setattr__(attr, value)

        else:

            if attr in ['contents']:

                contents_prop = getattr(self.__class__, attr)

                contents_prop.__set__(self, value)

            else:

                raise RuntimeError('Model does not allow setting of extra attributes')
from_data
def from_data(
    self,
    value: Any
) -> None

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
NoneType
View Source
    def from_data(self, value: Any) -> None:

        self.contents = value
from_json
def from_json(
    self,
    json_contents: str
) -> None

Parameters:

Name Type Description Default
json_contents str

Returns:

Type Description
NoneType
View Source
    def from_json(self, json_contents: str) -> None:

        new_model = self.parse_raw(json_contents, proto=pydantic_protocol.json)

        self._set_contents_without_validation(new_model)
inner_type
def inner_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def inner_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=False, with_args=with_args)
is_nested_type
def is_nested_type(
    self
) -> bool

Returns:

Type Description
bool
View Source
    def is_nested_type(self) -> bool:

        return not self.inner_type(with_args=True) == self.outer_type(with_args=True)
outer_type
def outer_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def outer_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=True, with_args=with_args)
to_data
def to_data(
    self
) -> Any

Returns:

Type Description
Any
View Source
    def to_data(self) -> Any:

        return self.dict()[ROOT_KEY]
to_json
def to_json(
    self,
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    def to_json(self, pretty=False) -> str:

        json_content = self.json()

        if pretty:

            return self._pretty_print_json(json.loads(json_content))

        else:

            return json_content
validate_contents
def validate_contents(
    self
)
View Source
    def validate_contents(self):

        self.contents = self.contents

NotIterableExceptStrOrBytesModel

class NotIterableExceptStrOrBytesModel(
    value: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    *,
    __root__: Union[Any, pydantic.fields.UndefinedType] = PydanticUndefined,
    **data: Any
)

Model describing any object that is not iterable, except for str and bytes types.

As strings and bytes are iterable (over the characters/bytes) but also generally useful and often considered singular (or scalar) types, they are specifically allowed by this model.

View Source
class NotIterableExceptStrOrBytesModel(Model[object | None]):

    """

    Model describing any object that is not iterable, except for `str` and `bytes` types.

    As strings and bytes are iterable (over the characters/bytes) but also generally useful and

    often considered singular (or scalar) types, they are specifically allowed by this model.

    Examples:

        >>> from omnipy import NotIterableExceptStrOrBytesModel, print_exception

        >>>

        >>> NotIterableExceptStrOrBytesModel(1234)

        NotIterableExceptStrOrBytesModel(1234)

        >>> NotIterableExceptStrOrBytesModel('1234')

        NotIterableExceptStrOrBytesModel(1234)

        >>> with print_exception:

        ...     NotIterableExceptStrOrBytesModel((1, 2, 3, 4))

        ValidationError: 1 validation error for NotIterableExceptStrOrBytesModel

    Note:

        JsonScalarModel is a strict submodel of NotIterableExceptStrOrBytesModel in that all objects

        allowed by JsonScalarModel are also allowed by NotIterableExceptStrOrBytesModel.

    """

    @classmethod

    def _parse_data(cls, data: object) -> object:

        assert isinstance(data, str) or isinstance(data, bytes) or not is_iterable(data), \

            f'Data of type {type(data)} is iterable'

        return data

Class variables

Config

Static methods

to_json_schema
def to_json_schema(
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    @classmethod

    def to_json_schema(cls, pretty=False) -> str:

        schema = cls.schema()

        if pretty:

            return cls._pretty_print_json(schema)

        else:

            return json.dumps(schema)
validate
def validate(
    value: Any
) -> Model

Hack to allow overwriting of iter method without compromising pydantic validation. Part

of the pydantic API and not the Omnipy API.

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
Model
View Source
    @classmethod

    def validate(cls: Type['Model'], value: Any) -> 'Model':

        """

        Hack to allow overwriting of __iter__ method without compromising pydantic validation. Part

        of the pydantic API and not the Omnipy API.

        """

        if isinstance(value, Model):

            with AttribHolder(value, '__iter__', GenericModel.__iter__, on_class=True):

                return super().validate(value)

        else:

            return super().validate(value)

Instance variables

contents

Methods

eq
def __eq__(
    self,
    other: object
) -> bool

Return self==value.

Parameters:

Name Type Description Default
other object

Returns:

Type Description
bool
View Source
    def __eq__(self, other: object) -> bool:

        return isinstance(other, Model) \

            and self.__class__ == other.__class__ \

            and self.contents == other.contents \

            and self.to_data() == other.to_data()  # last is probably unnecessary, but just in case
getattr
def __getattr__(
    self,
    attr: str
) -> Any

Parameters:

Name Type Description Default
attr str

Returns:

Type Description
Any
View Source
    def __getattr__(self, attr: str) -> Any:

        ret = self._getattr_from_contents(attr)

        if callable(ret):

            ret = add_callback_after_call(ret, self.validate_contents)

        return ret
setattr
def __setattr__(
    self,
    attr: str,
    value: Any
) -> None

Implement setattr(self, name, value).

Parameters:

Name Type Description Default
attr str
value Any

Returns:

Type Description
NoneType
View Source
    def __setattr__(self, attr: str, value: Any) -> None:

        if attr in self.__dict__ and attr not in [ROOT_KEY]:

            super().__setattr__(attr, value)

        else:

            if attr in ['contents']:

                contents_prop = getattr(self.__class__, attr)

                contents_prop.__set__(self, value)

            else:

                raise RuntimeError('Model does not allow setting of extra attributes')
from_data
def from_data(
    self,
    value: Any
) -> None

Parameters:

Name Type Description Default
value Any

Returns:

Type Description
NoneType
View Source
    def from_data(self, value: Any) -> None:

        self.contents = value
from_json
def from_json(
    self,
    json_contents: str
) -> None

Parameters:

Name Type Description Default
json_contents str

Returns:

Type Description
NoneType
View Source
    def from_json(self, json_contents: str) -> None:

        new_model = self.parse_raw(json_contents, proto=pydantic_protocol.json)

        self._set_contents_without_validation(new_model)
inner_type
def inner_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def inner_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=False, with_args=with_args)
is_nested_type
def is_nested_type(
    self
) -> bool

Returns:

Type Description
bool
View Source
    def is_nested_type(self) -> bool:

        return not self.inner_type(with_args=True) == self.outer_type(with_args=True)
outer_type
def outer_type(
    self,
    with_args: bool = False
) -> type | None

Parameters:

Name Type Description Default
with_args bool

Returns:

Type Description
type None
View Source
    def outer_type(self, with_args: bool = False) -> type | None:

        return self.__class__._get_root_type(outer=True, with_args=with_args)
to_data
def to_data(
    self
) -> Any

Returns:

Type Description
Any
View Source
    def to_data(self) -> Any:

        return self.dict()[ROOT_KEY]
to_json
def to_json(
    self,
    pretty=False
) -> str

Parameters:

Name Type Description Default
pretty

Returns:

Type Description
str
View Source
    def to_json(self, pretty=False) -> str:

        json_content = self.json()

        if pretty:

            return self._pretty_print_json(json.loads(json_content))

        else:

            return json_content
validate_contents
def validate_contents(
    self
)
View Source
    def validate_contents(self):

        self.contents = self.contents