modelity.base

class modelity.base.Constraint

Bases: ABC

Base class for constraints.

Constraints are used to define parsing- and validation-time criteria that must be met for successful parsing/validation. Instances of this base class are used with types wrapped with typing.Annotated.

Added in version 0.36.0: Replaced modelity.interface.IConstraint used earlier.

__abstractmethods__ = frozenset({'__call__', '__repr__'})
abstractmethod __call__(errors: list[Error], loc: Loc, value: Any) bool

Run all checks against given value.

Returns True and does not modify error list if value satisfies the constraint.

Returns False and adds one or more errors to error list if value does not satisfy the constraint.

Parameters:
  • errors – Mutable list of errors.

  • loc – The current location in the model.

  • value – The validated value.

abstractmethod __repr__() str

Return text representation of the constraint.

This is used when rendering constraints in error messages.

class modelity.base.Field(name: str, typ: Any, type_handler: TypeHandler, *, field_info: FieldInfo | None = None, construction_required: bool = False, validation_required: bool = False, unsettable: bool = False)

Bases: object

Dataclass containing data parsed from field’s type annotation.

__eq__(other)

Return self==value.

__hash__ = None
__init__(name: str, typ: Any, type_handler: TypeHandler, *, field_info: FieldInfo | None = None, construction_required: bool = False, validation_required: bool = False, unsettable: bool = False) None
__match_args__ = ('name', 'typ', 'type_handler')
__repr__()

Return repr(self).

compute_default() Any | UnsetType

Compute default value for this field.

construction_required: bool = False

Flag telling if this field is required during model construction.

Fields that are construction-required will cause model construction failure (with modelity.error.ErrorCode.REQUIRED_MISSING error code) if those are missing in model’s constructor and have no default values set.

Note

Fields that are construction-required are also implicitly validation-required; if construction-required fields are removed from a model object after it was successfully created, the validation step will still report same error.

Added in version 0.37.0.

field_info: FieldInfo | None = None

The additional metadata assigned for this field.

Everything declared using field_info() goes into here.

has_default() bool

Check if this field has default value set.

Added in version 0.16.0.

name: str

The name of this field.

This is also the name of an attribute in the model.

property required: bool

Flag telling if this field is required.

A field is required if at least one of construction_required and validation_required attributes is set to True.

typ: Any

The type annotation set for this field.

type_handler: TypeHandler

The type handler set for this field.

It is derived from field’s type annotation set as typ.

unsettable: bool = False

Flag telling if modelity.unset.Unset is a valid value for this field.

This is used both during construction and validation stages and will eventually cause modelity.error.ErrorCode.UNSET_NOT_ALLOWED error if field is left unset. For example, fields marked with typing.Optional cannot be unset; you have to initialize with either value, or a None.

Changed in version 0.37.0: Now this is also checked during model construction in addition to validation.

validation_required: bool = False

Flag telling if this field is required during model validation.

Such fields can be skipped during model construction (the model construction will not fail), but are required to be set before validation takes place. This is used by modelity.typing.Deferred type wrapper.

Note

This flag is automatically set to True for construction-required fields.

Added in version 0.37.0.

class modelity.base.FieldInfo(default: ~typing.Any = Unset, default_factory: ~typing.Callable[[], ~typing.Any] | ~modelity.unset.UnsetType = Unset, title: str | None = None, description: str | None = None, examples: list | None = None, type_opts: dict = <factory>)

Bases: object

Class for setting field metadata.

__eq__(other)

Return self==value.

__hash__ = None
__init__(default: ~typing.Any = Unset, default_factory: ~typing.Callable[[], ~typing.Any] | ~modelity.unset.UnsetType = Unset, title: str | None = None, description: str | None = None, examples: list | None = None, type_opts: dict = <factory>) None
__match_args__ = ('default', 'default_factory', 'title', 'description', 'examples', 'type_opts')
__repr__()

Return repr(self).

default: Any = Unset

Default field value.

default_factory: Callable[[], Any] | UnsetType = Unset

Default value factory function.

Allows to create default values that are evaluated each time the model is created, and therefore producing different default values for different model instances.

description: str | None = None

The description of this field.

This is a long description, to be used when title is not sufficient.

Added in version 0.19.0.

examples: list | None = None

The example values for this field.

This is not used directly in any way by the library, but 3rd party tools may use it f.e. to create random valid objects for tests.

Added in version 0.19.0.

title: str | None = None

The title of this field.

This should be relatively short.

Added in version 0.19.0.

type_opts: dict

Additional options for type descriptors.

This can be used to pass additional type-specific settings, like input/output formats and more. The actual use of these options depends on the field type.

class modelity.base.Model(**kwargs)

Bases: object

Base class for data models.

All models created using Modelity must inherit from this base class and provide zero or more fields using type annotations in similar way as when using Python dataclasses.

Here’s a simple example:

from typing import Optional

from modelity.api import Model, Deferred, LooseOptional, StrictOptional, Unset, validate

class Dummy(Model):
    foo: int  # <- required; must be given in constructor
    xyz: float = 3.14  # <- required; optional in constructor, as it has default value set
    bar: Deferred[bool] = Unset  # <- deferred; must be set before validation
    baz: Optional[str] = None  # <- optional; can be `None` but cannot be `Unset`
    spam: LooseOptional[str] = Unset  # <- optional; can be set to `None` or `Unset`
    more_spam: StrictOptional[str] = Unset  # <- optional; can be `Unset` but cannot be `None`
>>> dummy = Dummy(foo='123')  # Construct model instance; Modelity will try to parse input to expected type
>>> dummy
Dummy(foo=123, xyz=3.14, bar=Unset, baz=None, spam=Unset, more_spam=Unset)
>>> validate(dummy)  # Validation will fail; deferred field `bar` is missing
Traceback (most recent call last):
    ...
modelity.exc.ValidationError: Found 1 validation error for model 'Dummy':
  bar:
    This field is required [code=modelity.REQUIRED_MISSING]
>>> dummy.bar = True  # Now let's set a value to `bar` field (models are mutable)
>>> validate(dummy)  # And now the model is valid
>>> dummy
Dummy(foo=123, xyz=3.14, bar=True, baz=None, spam=Unset, more_spam=Unset)
__contains__(name)
__delattr__(name)

Implement delattr(self, name).

__eq__(value)

Return self==value.

__hash__ = None
__init__(**kwargs) None
__iter__()
__model_fields__: Mapping[str, Field] = {}

A per-instance view of the ModelMeta.__model_fields__ attribute.

__repr__()

Return repr(self).

__setattr__(name: str, value: Any) None

Implement setattr(self, name, value).

__slots__ = ()
accept(visitor: ModelVisitor, loc: Loc)

Accept visitor on this model.

Parameters:
  • visitor – The visitor to accept.

  • loc – The location of this model or empty location if this is the root model.

class modelity.base.ModelMeta(name: str, bases: tuple, attrs: dict)

Bases: type

Metaclass for models.

The role of this metaclass is to provide field initialization, type descriptor lookup and inheritance handling.

It is used as a metaclass by Model base class and all methods and properties it provides can be accessed via __class__ attribute of the Model class instances.

__model_fields__: Mapping[str, Field]

Mapping containing all fields declared for a model.

The name of a field is used as a key, while Field class instance is used as a value. The order reflects order of annotations in the created model class.

static __new__(cls, name: str, bases: tuple, attrs: dict)
class modelity.base.ModelVisitor

Bases: ABC

Base class for model data visitors.

This mechanism allows to traverse through Modelity models in a deterministic way and, depending on the implementation, serialize or validate it.

Added in version 0.36.0: Replaced modelity.interface.IModelVisitor used earlier.

__abstractmethods__ = frozenset({'visit_any', 'visit_mapping_begin', 'visit_mapping_end', 'visit_model_begin', 'visit_model_end', 'visit_model_field_begin', 'visit_model_field_end', 'visit_none', 'visit_scalar', 'visit_sequence_begin', 'visit_sequence_end', 'visit_set_begin', 'visit_set_end', 'visit_unset'})
abstractmethod visit_any(loc: Loc, value: Any)

Visit any value.

This is called for values from untyped containers, fields marked with typing.Any or typed containers where typing.Any is used as a type hint.

This method, unlike visit_scalar(), can also be called with elements that are containers, not scalars.

Implementations are responsible for deciding whether to recurse into the value if it is a container.

Parameters:
  • loc – The location of the visited value.

  • value – The visited value.

abstractmethod visit_mapping_begin(loc: Loc, value: Mapping) bool | None

Start visiting a mapping object.

Parameters:
  • loc – The location of the visited mapping object.

  • value – The visited mapping object.

abstractmethod visit_mapping_end(loc: Loc, value: Mapping)

Finish visiting a mapping object.

Parameters:
  • loc – The location of the visited mapping object.

  • value – The visited mapping object.

abstractmethod visit_model_begin(loc: Loc, value: Model) bool | None

Start visiting model object.

Parameters:
  • loc – The location of the visited model.

  • value – The visited model object.

abstractmethod visit_model_end(loc: Loc, value: Model)

Finish visiting model object.

Parameters:
  • loc – The location of the visited model.

  • value – The visited model object.

abstractmethod visit_model_field_begin(loc: Loc, value: Any, field: Field) bool | None

Start visiting model field.

This is called for every field in a model no matter if the field is set or not.

Parameters:
  • loc – The location of the visited value.

  • value – The visited field value.

  • field – The visited field metadata.

abstractmethod visit_model_field_end(loc: Loc, value: Any, field: Field)

Finish visiting model field.

Parameters:
  • loc – The location of the visited value.

  • value – The visited field value.

  • field – The visited field metadata.

abstractmethod visit_none(loc: Loc, value: None)

Visit a None value.

Called when None object is found.

Parameters:
  • loc – The location of the visited value.

  • value – The visited value.

abstractmethod visit_scalar(loc: Loc, value: Any)

Visit scalar object.

Scalars are primitive objects that are neither containers, nor model objects. All Python primitive types (ints, floats, strings, booleans, enums, datetimes etc.) are scalars from the Modelity point of view.

Parameters:
  • loc – The location of the visited value.

  • value – The visited value.

abstractmethod visit_sequence_begin(loc: Loc, value: Sequence) bool | None

Start visiting a sequence object.

Parameters:
  • loc – The location of the visited sequence object.

  • value – The visited sequence object.

abstractmethod visit_sequence_end(loc: Loc, value: Sequence)

Finish visiting a sequence object.

Parameters:
  • loc – The location of the visited sequence object.

  • value – The visited sequence object.

abstractmethod visit_set_begin(loc: Loc, value: Set) bool | None

Start visiting a set object.

Parameters:
  • loc – The location of the visited set object.

  • value – The visited set object.

abstractmethod visit_set_end(loc: Loc, value: Set)

Finish visiting a set object.

Parameters:
  • loc – The location of the visited set object.

  • value – The visited set object.

abstractmethod visit_unset(loc: Loc, value: UnsetType)

Visit an Unset value.

Called when modelity.unset.Unset object is found.

Parameters:
  • loc – The location of the visited value.

  • value – The visited value.

class modelity.base.TypeHandler

Bases: ABC

Base class for type handlers.

Type handlers are used by Modelity to provide type-specific runtime logic to models. Type handlers are constructed from type object or type annotations when model type is created and then used by model instances to handle user data.

Added in version 0.36.0: Replaced modelity.interface.ITypeDescriptor used earlier.

__abstractmethods__ = frozenset({'accept', 'parse'})
abstractmethod accept(visitor: ModelVisitor, loc: Loc, value: Any, /)

Accept given model visitor.

This method is meant to provide visitor accepting logic for handled type. Basically, this method will call the most adequate visitor method, or (for complex types) sequence of visitor methods. See ModelVisitor for more details.

Parameters:
  • visitor – The visitor to accept.

  • loc – The visited location in the model.

  • value

    The value to process.

    It can be assumed that this value has the right type already.

abstractmethod parse(errors: list[Error], loc: Loc, value: Any, /) Any | UnsetType

Parse given value as instance of handled type.

Successful parsing must return instance of handled type, which can be unchanged value if it already has desired type.

Failure must be reported by one or more errors added to errors list, and modelity.unset.Unset value returned.

Parameters:
  • errors – Mutable list of errors.

  • loc – The current location in the model.

  • value – The input value.

class modelity.base.TypeHandlerFactory(*args, **kwargs)

Bases: Protocol

Protocol describing type handler factories.

Added in version Replaced: modelity.interface.ITypeDescriptorFactory used earlier.

__abstractmethods__ = frozenset({})
__call__(typ: Any, /, **type_opts) TypeHandler

Create a type handler for the provided type and options.

Parameters:
  • typ – The type or special form to create a handler for.

  • type_opts – Optional type-specific options passed to the handler.

__init__(*args, **kwargs)
__parameters__ = ()
__protocol_attrs__ = {'__call__'}
classmethod __subclasshook__(other)

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

class modelity.base.TypeHandlerWithValidation

Bases: TypeHandler

Base class for type handlers that need to run additional type-specific validation when model is validated.

For example, this base class is used by type handler for typing.Annotated types to ensure that constraints are still satisfied when model is validated, which is impossible to ensure only during parsing stage for mutable types.

Added in version 0.36.0: Replaced modelity.interface.IValidatableTypeDescriptor used earlier.

__abstractmethods__ = frozenset({'accept', 'parse', 'validate'})
abstractmethod validate(errors: list[Error], loc: Loc, value: Any) bool

Validate the value.

Returns True and does not modify error list if the value is valid.

Returns False and adds one or more errors to the errors list if the value is not valid.

Parameters:
  • errors – Mutable list of errors.

  • loc – The current location in the model.

  • value – The validated value.

modelity.base.create_type_handler(typ: Any, /, **type_opts)

Create type handler for provided type.

This method is using cache internally so it returns same handler if called again with same type.

Parameters:
  • typ – The type to create or get handler for.

  • **type_opts – The optional type options to use.

modelity.base.field_info(*, default: T | UnsetType = Unset, default_factory: Callable[[], T] | UnsetType = Unset, title: str | None = None, description: str | None = None, examples: list | None = None, **type_opts) T

Helper for creating FieldInfo objects in a way that will satisfy code linters.

Check FieldInfo class documentation to get help on available parameters.

Changed in version 0.19.0: Added title, description and examples parameters.

Added in version 0.16.0.

modelity.base.register_type_handler_factory(typ: Any, factory: TypeHandlerFactory)

Register custom type handler factory for given type.

This method can be used to register custom types so Modelity could understand those, or to overwrite built-in type handlers.

Parameters:
  • typ – The type to register type handler for.

  • factory – The type handler factory function to use for provided type.