modelity.api

An all-in-one import helper.

class modelity.api.Comparable(*args, **kwargs)

Bases: Protocol

Protocol describing generic comparable type.

Added in version 0.33.0.

__abstractmethods__ = frozenset({})
__ge__(other: Any, /) bool

Return self>=value.

__gt__(other: Any, /) bool

Return self>value.

__init__(*args, **kwargs)
__le__(other: Any, /) bool

Return self<=value.

__lt__(other: Any, /) bool

Return self<value.

__parameters__ = ()
__protocol_attrs__ = {'__ge__', '__gt__', '__le__', '__lt__'}
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.api.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.api.DumpVisitor(out: dict)

Bases: EmptyVisitor

Visitor that dumps model to dict without type narrowing or any kind of value formatting.

It basically produces same structure as the model has, but based on Python collection types (dicts, lists, tuples and sets) instead of Modelity built-in ones.

Important

This visitor assumes that use of its API is done by modelity.model.Model.accept() method that keeps the right order of method calling. It may not work correctly if used manually.

Added in version 0.31.0.

__abstractmethods__ = frozenset({})
__init__(out: dict)
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.

visit_mapping_begin(loc: Loc, value: Mapping)

Start visiting a mapping object.

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

  • value – The visited mapping object.

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.

visit_model_begin(loc: Loc, value: Model)

Start visiting model object.

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

  • value – The visited model object.

visit_model_end(loc: Loc, value: Model)

Finish visiting model object.

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

  • value – The visited model object.

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.

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.

visit_sequence_begin(loc: Loc, value: Sequence)

Start visiting a sequence object.

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

  • value – The visited sequence object.

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.

visit_set_begin(loc: Loc, value: Set)

Start visiting a set object.

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

  • value – The visited set object.

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.

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.api.EmptyVisitor

Bases: ModelVisitor

A visitor that simply implements modelity.interface.IModelVisitor interface with methods doing nothing.

It is meant to be used as a base for other visitors, especially ones that do not need to overload all methods.

Changed in version 0.34.0: Restored the whole set of modelity.interface.IModelVisitor interface methods to get rid of linter warnings in subclasses.

__abstractmethods__ = frozenset({})
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.

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.

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.

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.

visit_model_end(loc: Loc, value: Model)

Finish visiting model object.

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

  • value – The visited model object.

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.

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.

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.

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.

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.

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.

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.

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.

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.api.Error(loc: ~modelity.loc.Loc, code: str, msg: str, value: ~typing.Any = Unset, data: dict = <factory>)

Bases: object

Object containing details of the single error.

It is used for both parsing and validation stages of the model processing.

__eq__(other)

Return self==value.

__hash__ = None
__init__(loc: ~modelity.loc.Loc, code: str, msg: str, value: ~typing.Any = Unset, data: dict = <factory>) None
__match_args__ = ('loc', 'code', 'msg', 'value', 'data')
__repr__()

Return repr(self).

code: str

Error code.

This is a short description of the error. Check ErrorCode for the list of Modelity built-in error code constants and their meaning.

data: dict

Additional error data.

This property, along with code, can be used to render custom error messages. It is recommended to always use same structure for same error code.

For built-in errors, this property will get filled with any extra arguments passed to factory functions defined in ErrorFactory class.

loc: Loc

Error location in the model.

msg: str

Formatted error message.

Contains human-readable error description based on code and data.

value: Any = Unset

The incorrect value, if present, or modelity.unset.Unset otherwise.

property value_type: type

The type of the incorrect value.

class modelity.api.ErrorCode

Bases: object

Class defining all built-in error codes.

CONVERSION_ERROR = 'modelity.CONVERSION_ERROR'

Used when it was not possible to automatically convert allowed input value type into expected type.

For example, a set cannot be created from list if the list contains unhashable elements.

Use by ErrorFactory.conversion_error() to create errors with this code.

DECODE_ERROR = 'modelity.DECODE_ERROR'

Used when bytes could not be decoded into string using any of the provided encoding.

Use ErrorFactory.decode_error() to create errors with this code.

EXCEPTION = 'modelity.EXCEPTION'

Used to wrap user exception caught during parsing or validation stage.

This error code is used to wrap TypeError (and its subclasses) raised during parsing stage or ValueError (and its subclasses) raised during validation stage by user-defined hook.

Use ErrorFactory.exception() to create errors with this code.

INVALID_DATETIME_FORMAT = 'modelity.INVALID_DATETIME_FORMAT'

Used when datetime field gets text input that has invalid datetime format.

Used ErrorFactory.invalid_datetime_format() to create errors with this code.

INVALID_DATE_FORMAT = 'modelity.INVALID_DATE_FORMAT'

Same as for INVALID_DATETIME_FORMAT, but for dates.

Use ErrorFactory.invalid_date_format() to create errors with this code.

INVALID_ENUM_VALUE = 'modelity.INVALID_ENUM_VALUE'

Similar to INVALID_VALUE, but used with enumerated values and enum.Enum type.

Use ErrorFactory.invalid_enum_value() to create errors with this code.

INVALID_LENGTH = 'modelity.INVALID_LENGTH'

Used to signal value length range errors.

Use invalid_length() to create errors with this code.

INVALID_STRING_FORMAT = 'modelity.INVALID_STRING_FORMAT'

Used to inform that the input value string has incorrect format.

For example, input expects data matching some regular expression pattern, but the input value does not match the pattern.

Use invalid_string_format() to create errors with this code.

INVALID_TUPLE_LENGTH = 'modelity.INVALID_TUPLE_LENGTH'

Used for fixed-length tuple types where input value is a tuple that does not have the exact number of elements.

Use ErrorFactory.invalid_tuple() to create errors with this code.

INVALID_TYPE = 'modelity.INVALID_TYPE'

Used when type of the input value does not match the expected type and it cannot be automatically converted.

Use ErrorFactory.invalid_type() to create errors with this code.

INVALID_VALUE = 'modelity.INVALID_VALUE'

Used when input value was not one of the expected values.

For example, field accepts literals Literal[1, 2, "3"], but the input was "2" which is not one of the allowed literals.

Use ErrorFactory.invalid_value() to create errors with this code.

NONE_NOT_ALLOWED = 'modelity.NONE_NOT_ALLOWED'

Reported during parsing of modelity.typing.StrictOptional wrapped fields if None is used as input value.

Strict optional fields require the field to either be set to instance of type T, or not set at all (unlike typing.Optional, which allows None). Modelity needs to provide such clean separation to make sure that model satisfies all type constraints after validation.

Important

This error is reserved for modelity.typing.StrictOptional wrapper and should not be used elsewhere.

Use ErrorFactory.none_not_allowed() to create errors with this code.

Added in version 0.29.0.

OUT_OF_RANGE = 'modelity.OUT_OF_RANGE'

Used to signal value range errors.

Use out_of_range() to create error with this code.

PARSE_ERROR = 'modelity.PARSE_ERROR'

Used when Modelity could not parse input value to an expected type.

For example, string “abc” cannot be parsed as integer number.

Use ErrorFactory.parse_error() to create errors with this code.

REQUIRED_MISSING = 'modelity.REQUIRED_MISSING'

Signals that the field is required but is not present in the model.

Use ErrorFactory.required_missing() to create errors with this code.

UNSET_NOT_ALLOWED = 'modelity.UNSET_NOT_ALLOWED'

Reported during validation for typing.Optional fields that remain unset during validation.

To allow usage of Unset please use modelity.typing.StrictOptional or modelity.typing.LooseOptional type wrappers. Check their docs for more details.

This error can be avoided by setting default values for optional fields.

Use ErrorFactory.unset_not_allowed() to create errors with this code.

Added in version 0.29.0.

USER_ERROR = 'modelity.USER_ERROR'

Default error code for the modelity.exc.UserError exception.

Added in version 0.30.0.

class modelity.api.ErrorFactory

Bases: object

Class grouping factory methods for creating built-in errors.

static conversion_error(loc: Loc, value: Any, expected_type: type, /, reason: str | None = None, *, msg: str | None = None, **extra_data) Error

Create conversion error.

This signals that value could not be converted into instance of expected_type due to the reason explained in error message.

Important

This error is reserved only for failing conversion where input value is non-string. If input value is string or bytes then it is better to use parse_error() factory instead.

Parameters:
  • loc – Error location in the model.

  • value – Input value that could not be converted.

  • expected_type – Expected value type.

  • reason – The optional reason text.

  • msg

    The optional message to override built-in one.

    Added in version 0.33.0.

  • **extra_data

    The optional extra error data.

    This will be placed inside modelity.error.Error.data dict of a created error object.

    Added in version 0.33.0.

static decode_error(loc: Loc, value: bytes, expected_encodings: list[str], /) Error

Create decode error.

Parameters:
  • loc – Error location in the model.

  • value – Input bytes that could not be decoded into string.

  • expected_encodings – List of expected encodings.

static exception(loc: Loc, value: Any, exc: Exception, /) Error

Create error from a user exception.

Parameters:
  • loc – Error location in the model.

  • value – The incorrect value.

  • exc – The exception object.

static invalid_date_format(loc: Loc, value: str, expected_formats: list[str], /)

Create invalid date format error.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input string.

  • expected_formats – List with expected date formats.

static invalid_datetime_format(loc: Loc, value: str, expected_formats: list[str], /) Error

Create invalid datetime format error.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input string.

  • expected_formats – List with expected datetime formats.

static invalid_enum_value(loc: Loc, value: Any, expected_enum_type: type[Enum], /) Error

Create invalid enum value error.

Parameters:
  • loc – Error location in the model.

  • value – Input value from outside of expected enumerated values set.

  • expected_enum_type – Expected enum type.

static invalid_length(loc: Loc, value: Sized, /, min_length: int | None = None, max_length: int | None = None, *, msg: str | None = None) Error

Create invalid length error.

This error is reported for containers or other sized types when length constraints are not satisfied.

Important

The built-in message composer requires at least one length range parameter to be provided.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input value.

  • min_length – Minimum length.

  • max_length – Maximum length.

  • msg

    The optional message to override built-in one.

    When custom message is provided then length range parameters, although still recommended, become optional.

    Added in version 0.33.0.

static invalid_string_format(loc: Loc, value: str, expected_pattern: str, /, *, msg: str | None = None) Error

Create invalid string format error.

Changed in version 0.33.0: Now loc, value and expected_pattern are positional-only arguments, while msg is keyword-only argument. This was changed for compliance with other methods.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input string.

  • expected_pattern – Expected string pattern (f.e. regex pattern).

  • msg – Optional user-defined message to use instead of built-in one.

static invalid_tuple_length(loc: Loc, value: tuple, expected_tuple: tuple[type, ...], /) Error

Create invalid tuple length error.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input tuple.

  • expected_tuple – Expected tuple shape.

static invalid_type(loc: Loc, value: Any, expected_types: list[type], /, allowed_types: list[type] | None = None, forbidden_types: list[type] | None = None, *, msg: str | None = None, **extra_data) Error

Create invalid type error.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input value.

  • expected_types – List with expected type or types.

  • allowed_types

    Optional list with allowed types.

    This is information that if one of these types is used as type of the input value then it will be accepted and converted to one of expected types.

    For example, a set can be constructed from set, list or tuple of items.

  • forbidden_types

    Optional list of forbidden types.

    This is used to specify types that are arbitrary forbidden and will fail value processing immediately when encountered.

  • msg

    The optional message to override built-in one.

    Added in version 0.33.0.

  • **extra_data

    The optional extra error data.

    This will be placed inside modelity.error.Error.data dict of a created error object.

    Added in version 0.33.0.

static invalid_value(loc: Loc, value: Any, expected_values: list, /, *, msg: str | None = None, **extra_data) Error

Create invalid value error.

Parameters:
  • loc – Error location in the model.

  • value – Input value from outside of expected values set.

  • expected_values – List with expected values.

  • msg

    The optional message to override built-in one.

    Added in version 0.32.0.

  • **extra_data

    The optional extra error data.

    This will be placed inside modelity.error.Error.data dict of a created error object.

    Added in version 0.33.0.

static none_not_allowed(loc: Loc, expected_type: Any, /) Error

Create NONE_NOT_ALLOWED error.

See ErrorCode.NONE_NOT_ALLOWED for more details.

Added in version 0.29.0.

Parameters:
  • loc – Error location in the model.

  • expected_types – The expected type.

static out_of_range(loc: Loc, value: T, /, min_inclusive: T | None = None, min_exclusive: T | None = None, max_inclusive: T | None = None, max_exclusive: T | None = None, *, msg: str | None = None) Error

Create out of range error.

This is a generic error factory for all kind of value range errors.

Important

The built-in message composer requires at least one range parameter to be provided.

Parameters:
  • loc – Error location in the model.

  • value – Incorrect input value.

  • min_inclusive – Minimum value (inclusive).

  • min_exclusive – Minimum value (exclusive).

  • max_inclusive – Maximum value (inclusive).

  • max_exclusive – Maximum value (exclusive).

  • msg

    The optional message to override built-in one.

    When custom message is provided then range parameters, although still recommended, become optional.

    Added in version 0.33.0.

static parse_error(loc: Loc, value: Any, expected_type: type, /, *, msg: str | None = None, **extra_data) Error

Create parse error.

Parameters:
  • loc – Error location in the model.

  • value – Input value that could not be parsed.

  • expected_type – Expected value type.

  • msg – The optional message to override built-in one.

  • **extra_data

    The optional extra error data.

    This will be placed inside modelity.error.Error.data dict of a created error object.

static required_missing(loc: Loc, /)

Create required missing error.

Parameters:

loc – The location of a missing field.

static unset_not_allowed(loc: Loc, expected_type: Any, /) Error

Create UNSET_NOT_ALLOWED error.

See ErrorCode.UNSET_NOT_ALLOWED for more details.

Added in version 0.29.0.

Parameters:
  • loc – Error location in the model.

  • expected_types – The expected type.

class modelity.api.ErrorWriter(out: TextIO, indent_string: str = '  ', indent_level: int = 0, show_code: bool = False, show_value: bool = False, show_value_type: bool = False, show_data: bool = False)

Bases: object

Class that formats errors as string and appends to the end of provided text buffer.

Parameters:
  • out – The output text buffer.

  • indent_string – Indentation string.

  • indent_level – Indentation level.

  • show_code – Display error code.

  • show_value – Display input value.

  • show_value_type – Display input value type.

  • show_data – Display additional error data.

Added in version 0.28.0.

__init__(out: TextIO, indent_string: str = '  ', indent_level: int = 0, show_code: bool = False, show_value: bool = False, show_value_type: bool = False, show_data: bool = False)
write(obj: Error)

Format given error object and write to the end of the text buffer provided in the constructor.

Parameters:

obj – The error object.

class modelity.api.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.api.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.api.FixupVisitor(root: Model, ctx: Any = None)

Bases: EmptyVisitor

Visitor performing model fixups.

It is implicitly used by modelity.helpers.fixup() helper.

Added in version 0.36.0.

__abstractmethods__ = frozenset({})
__init__(root: Model, ctx: Any = None) None
visit_model_end(loc: Loc, value: Model)

Finish visiting model object.

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

  • value – The visited model object.

class modelity.api.Ge(min_inclusive: int | float)

Bases: Constraint

Greater-or-equal constraint.

Used to specify minimum inclusive value for a numeric field.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(min_inclusive: int | float) None
__match_args__ = ('min_inclusive',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

min_inclusive: int | float

The minimum inclusive value set for this constraint.

class modelity.api.Gt(min_exclusive: int | float)

Bases: Constraint

Greater-than constraint.

Used to specify minimum exclusive value for a numeric field.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(min_exclusive: int | float) None
__match_args__ = ('min_exclusive',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

min_exclusive: int | float

The minimum exclusive value set for this constraint.

class modelity.api.JsonDumpVisitorProxy(target: ModelVisitor, /, exclude_unset: bool = False, exclude_none: bool = False, bytes_format: str | Literal['base64'] = 'utf-8', datetime_format: str = 'YYYY-MM-DDThh:mm:ss.ffffffZZZZ', date_format: str = 'YYYY-MM-DD', default_encoder: Callable[[Loc, Any], Any] | None = None)

Bases: object

Proxy visitor that narrows down value types to closest JSON-compatible type: dict, list, str, int, float, bool or None.

Added in version 0.31.0.

Parameters:
  • target – Target dump visitor, e.g. DumpVisitor object.

  • exclude_unset – Exclude model fields equal to modelity.unset.Unset object.

  • exclude_none

    Exclude model fields equal to None.

    This does not affect None values used in nested containers, only model fields, typed with e.g. Optional[T], are affected.

  • bytes_format

    The format used to encode bytes objects.

    Supports either encoding name (f.e. utf-8 or ascii) or one of predefined encodings (f.e. base64).

  • datetime_format

    The format to use to encode datetime.datetime objects.

    Following placeholders are supported:

    • YYYY for 4-digit years

    • MM for 2-digit months in range [01..12]

    • DD for 2-digit days in range [01..31]

    • hh for 2-digit hours in range [00..23]

    • mm for 2-digit minutes in range [00..59]

    • ss for 2-digit seconds in range [00..59]

    • ffffff for 6-digit microseconds in range [000000..999999]

    • ZZZZ for timezone

  • date_format

    The format to use to encode datetime.date objects.

    Following placeholders are supported:

    • YYYY for 4-digit years

    • MM for 2-digit months in range [01..12]

    • DD for 2-digit days in range [01..31]

  • default_encoder

    The default encoder to use if there is no dedicated type encoder found.

    If not given, then str is used as a default.

    Changed in version 0.34.0: Parameter was renamed from default_converter.

__getattr__(name)
__init__(target: ModelVisitor, /, exclude_unset: bool = False, exclude_none: bool = False, bytes_format: str | Literal['base64'] = 'utf-8', datetime_format: str = 'YYYY-MM-DDThh:mm:ss.ffffffZZZZ', date_format: str = 'YYYY-MM-DD', default_encoder: Callable[[Loc, Any], Any] | None = None)
register_type_encoder(typ: type[T], func: Callable[[Loc, T], Any])

Register or override type encoder.

Important

Only model field values, nested model instances or container elements encoding can be customized using this method. Containers like dicts, sets or lists cannot be customized.

Added in version 0.34.0.

Parameters:
  • typ – The type to set converter function for.

  • func

    The conversion function.

    Takes (loc, value) as input and returns encoded value.

visit_any(loc: Loc, value: Any)
visit_model_begin(loc: Loc, value: Model)
visit_none(loc: Loc, value: None)
visit_scalar(loc: Loc, value: Any)
visit_sequence_begin(loc: Loc, value: Sequence)
visit_sequence_end(loc: Loc, value: Sequence)
visit_set_begin(loc: Loc, value: Set)
visit_set_end(loc: Loc, value: Set)
visit_unset(loc: Loc, value: UnsetType)
class modelity.api.Le(max_inclusive: Any)

Bases: Constraint

Less-or-equal constraint.

Used to set maximum inclusive value for a numeric field.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(max_inclusive: Any) None
__match_args__ = ('max_inclusive',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

max_inclusive: Any

The maximum inclusive value set for this constraint.

class modelity.api.LenRange(min_length: int, max_length: int)

Bases: Constraint

Length range constraint.

Combines both minimum and maximum length constraints.

Added in version 0.28.0.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(min_length: int, max_length: int) None
__match_args__ = ('min_length', 'max_length')
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

max_length: int

Maximum length.

min_length: int

Minimum length.

class modelity.api.Loc(*path: Any)

Bases: Sequence

A tuple-like type that stores location of the value (or error) in the model tree.

Examples:

>>> from modelity.loc import Loc
>>> root = Loc("root")
>>> nested = root + Loc("nested")
>>> nested
Loc('root', 'nested')
>>> nested += Loc(0)
>>> nested
Loc('root', 'nested', 0)
>>> str(nested)
'root.nested.0'
>>> nested[0]
'root'
>>> nested[-1]
0
Parameters:

*args – The positional arguments composing location’s path.

__abstractmethods__ = frozenset({})
__add__(other)
__eq__(value: object) bool

Return self==value.

__getitem__(index)
__hash__() int

Return hash(self).

__init__(*path: Any)
__len__() int
__lt__(value: object) bool

Return self<value.

__orig_bases__ = (typing.Sequence,)
__parameters__ = ()
__repr__() str

Return repr(self).

__slots__ = ('_data',)
__str__() str

Return str(self).

classmethod irrelevant() Loc

Return a special location value indicating that the exact location is irrelevant.

This is equivalent to Loc("_") and is typically used in containers like sets or unordered structures, where the concept of position or path does not apply.

For example, when comparing or storing elements where their precise placement is not semantically meaningful, this sentinel location can be used to fulfill API requirements without implying an actual location.

Added in version 0.17.0.

is_empty() bool

Check if this is an empty location object.

is_parent_of(other: Loc) bool

Check if this location is parent (prefix) of given other location.

Parameters:

other – The other location object.

property last: Any

Return last component of the location.

suffix_match(pattern: Loc) bool

Check if suffix of this location matches given pattern.

Examples:

>>> Loc("foo").suffix_match(Loc("foo"))
True
>>> Loc("foo").suffix_match(Loc("foo", "bar"))
False
>>> Loc("foo", "bar").suffix_match(Loc("foo", "bar"))
True
>>> Loc("foo", "bar").suffix_match(Loc("foo", "*"))
True
>>> Loc("foo", 3, "bar").suffix_match(Loc("foo", "*", "bar"))
True
>>> Loc("foo", 3, "bar").suffix_match(Loc("foo", "*", "baz"))
False

Added in version 0.27.0.

to_tuple() tuple

Convert this location into tuple object.

Added in version 0.36.0.

class modelity.api.Lt(max_exclusive: Any)

Bases: Constraint

Less-than constraint.

Used to set maximum exclusive value for a numeric field.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(max_exclusive: Any) None
__match_args__ = ('max_exclusive',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

max_exclusive: Any

The maximum exclusive value set for this constraint.

class modelity.api.MaxLen(max_length: int)

Bases: Constraint

Maximum length constraint.

Can be used with sized types, like containers, byte or str.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(max_length: int) None
__match_args__ = ('max_length',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

max_length: int

Maximum length.

class modelity.api.MinLen(min_length: int)

Bases: Constraint

Minimum length constraint.

Can be used with sized types, like containers, byte or str.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(min_length: int) None
__match_args__ = ('min_length',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

min_length: int

Minimum length.

class modelity.api.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.

exception modelity.api.ModelError(typ: type, errors: tuple[Error, ...])

Bases: ModelityError

Common base class for errors raised during either data parsing or model validation stages.

It can be used by library clients to catch both parsing and validation errors in one place, which can help avoid unexpected leaking of exceptions the user was not aware of.

Parameters:
  • typ – The type for which this error has happened.

  • errors – Tuple of errors to initialize exception with.

__init__(typ: type, errors: tuple[Error, ...])
errors: tuple[Error, ...]

Tuple with either parsing, or validation errors.

typ: type

The type for which this error has happened.

Changed in version 0.28.0: Moved from ParsingError class and now made available for all subclasses for ease of use.

property typ_name: str

Return the name of the type.

class modelity.api.ModelFieldPruningVisitorProxy(target: ModelVisitor, /, exclude_if: Callable[[Loc, Any], bool])

Bases: object

Visitor proxy that skips model fields if provided exclude function returns True.

Important

This proxy only skips model fields and does not affect container elements in any way.

Parameters:
  • target – The wrapped model visitor.

  • exclude_if

    The exclusion function.

    Takes (loc, value) as arguments and must return True to skip the matched model field or False to leave it.

__getattr__(name)
__init__(target: ModelVisitor, /, exclude_if: Callable[[Loc, Any], bool])
visit_model_field_begin(loc: Loc, value: Any, field: Field) bool | None
class modelity.api.ModelLoader(model_type: type[MT], ctx: Any = None)

Bases: Generic[MT]

Similar to load() function, but allows to create loader for given model type and then create instances of that model using keyword args.

Example use:

from modelity.base import Model
from modelity.helpers import ModelLoader

class Dummy(Model):
    a: int
    b: str

DummyLoader = ModelLoader(Dummy)
>>> one = DummyLoader(a=1, b="spam")
>>> one
Dummy(a=1, b='spam')

Added in version 0.17.0.

Parameters:
  • model_type – The model type.

  • ctx – The user-defined validation context.

__call__(**kwargs) MT

Create and validate instance of the given model type.

On success, valid model instance is returned.

On failure, modelity.exc.ModelError exception is raised.

Parameters:

**kwargs – Named arguments for model’s constructor.

__init__(model_type: type[MT], ctx: Any = None)
__orig_bases__ = (typing.Generic[~MT],)
__parameters__ = (~MT,)
class modelity.api.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.api.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.

exception modelity.api.ModelityError

Bases: Exception

Base class for every Modelity-specific exception.

__message_template__: str | None = None

Message template string.

Used as default error message when specified. Properties of the current exception object can be provided via self placeholder.

__str__() str

Return str(self).

exception modelity.api.ParsingError(typ: type, errors: tuple[Error, ...])

Bases: ModelError

Exception raised at parsing stage when input data could not be parsed into model instance.

When this exception is raised, no model is created.

__str__() str

Return str(self).

class modelity.api.Range(min: Gt | Ge, max: Lt | Le)

Bases: Constraint

Range constraint.

Used to set allowed value range for a numeric field using one of Lt or Gt for minimum value, and one of Lt or Le for maximum value.

Added in version 0.28.0.

__abstractmethods__ = frozenset({})
__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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(min: Gt | Ge, max: Lt | Le) None
__match_args__ = ('min', 'max')
__repr__() str

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

max: Lt | Le

The maximum value.

min: Gt | Ge

The minimum value.

class modelity.api.Regex(pattern: str)

Bases: Constraint

Regular expression constraint.

Allows values matching given regular expression and reject all other. Can only operate on strings.

__abstractmethods__ = frozenset({})
__call__(errors: list[Error], loc: Loc, value: str) 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.

__delattr__(name)

Implement delattr(self, name).

__eq__(other)

Return self==value.

__hash__()

Return hash(self).

__init__(pattern: str) None
__match_args__ = ('pattern',)
__repr__()

Return text representation of the constraint.

This is used when rendering constraints in error messages.

__setattr__(name, value)

Implement setattr(self, name, value).

pattern: str

Regular expression pattern.

class modelity.api.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.api.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.api.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.

class modelity.api.UnsetType

Bases: object

Singleton type for representing unset or undefined values.

It has only one global instance to allow fast is-a tests in the code and always evaluates to False.

__bool__()
static __new__(cls)
__repr__()

Return repr(self).

__slots__: list = []
exception modelity.api.UnsupportedTypeError(typ: type)

Bases: ModelityError

Raised when model is declared with a field of a type that is not supported by the current version of Modelity library.

__init__(typ: type)
__message_template__: str | None = 'unsupported type used: {self.typ!r}'

Message template string.

Used as default error message when specified. Properties of the current exception object can be provided via self placeholder.

typ: type

The type that is not supported.

exception modelity.api.UserError(msg: str, *, code: str = 'modelity.USER_ERROR', loc: Loc | None = None, value: Any = Unset, data: dict | None = None, skip: bool = False)

Bases: ModelityError

Exception raised by user-defined hooks to report a single error.

When raised inside a hook, this exception is intercepted by Modelity and converted into a modelity.error.Error instance during the parsing or validation stage (depending on the hook type; see modelity.hooks).

Using this exception is optional - hooks may also report errors using other supported mechanisms.

Added in version 0.30.0.

__init__(msg: str, *, code: str = 'modelity.USER_ERROR', loc: Loc | None = None, value: Any = Unset, data: dict | None = None, skip: bool = False)
__message_template__: str | None = '{self.msg} [code={self.code!r}, loc={self.loc!r}, value={self.value!r}, data={self.data!r}, skip={self.skip!r}]'

Message template string.

Used as default error message when specified. Properties of the current exception object can be provided via self placeholder.

code: str

Error code.

By default, modelity.error.ErrorCode.USER_ERROR is used.

data: dict | None

Additional error data.

Optional dictionary with extra context (e.g. {"min": 0, "max": 10}).

loc: Loc | None

Error location.

If not set, then the current location from the hook context is used.

msg: str

Error message.

skip: bool

Skipping flag.

Some validators (e.g. modelity.hooks.model_prevalidator()) can return boolean True to skip other validators for the current model instance. This flag allows to enable that feature.

value: Any

Invalid input value.

If not set, then the current value from the hook context is used.

exception modelity.api.ValidationError(model: Any, errors: tuple[Error, ...])

Bases: ModelError

Exception raised at model validation stage when one or model specific constraint are broken.

This exception may only be raised for existing models.

Parameters:
  • model

    The model for which validation has failed.

    This will be the root model, i.e. the one for which modelity.model.Model.validate() method was called.

  • errors – Tuple containing all validation errors.

__init__(model: Any, errors: tuple[Error, ...])
__str__() str

Return str(self).

model: Any

The model object for which validation has failed.

class modelity.api.ValidationVisitor(root: Model, errors: list[Error], ctx: Any = None)

Bases: EmptyVisitor

Visitor that performs model validation.

Added in version 0.31.0: Replaced DefaultValidationVisitor used earlier.

Parameters:
  • root – The root model.

  • errors

    The list of errors.

    Will be populated with validation errors (if any).

  • ctx

    User-defined validation context.

    It is shared across all validation hooks and can be used as a source of external data needed during validation but not directly available in the model.

__abstractmethods__ = frozenset({})
__init__(root: Model, errors: list[Error], ctx: Any = None)
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.

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.

visit_model_begin(loc: Loc, value: Model)

Start visiting model object.

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

  • value – The visited model object.

visit_model_end(loc: Loc, value: Model)

Finish visiting model object.

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

  • value – The visited model object.

visit_model_field_begin(loc: Loc, value: Any, field: Field)

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.

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.

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.

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.

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.

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.

modelity.api.after_field_set(*field_names: str)

Decorate method to be executed after any of given fields (or all, if no name was provided) is set or updated in the model with a successfully parsed value.

This hook can be used to set derived field(-s) in the model, e.g. to also set modified when created is set. However, if field is set to an incorrect value, this hook will not be called.

The decorated method can be defined with no arguments, or with any subsequence of the following arguments:

cls

The current model type.

self

The current model object.

loc

The location in the model.

Useful to check which field is currently being set when hook is meant to be used for several fields.

value

The final value of a field set.

This will be the output of type parser for a current field, or a last field postprocessor (if any).

Added in version 0.36.0.

modelity.api.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.api.dump(model: Model, /, exclude_unset: bool = False, exclude_none: bool = False, exclude_if: Callable[[Loc, Any], bool] | None = None, datetime_format: str = 'YYYY-MM-DDThh:mm:ss.ffffffZZZZ', date_format: str = 'YYYY-MM-DD') dict

Serialize given model to a dict.

This helper is designed to handle most common dump scenarios, like skipping unset fields or optional field set to None. More advanced behavior can be achieved by implementing custom modelity.interface.IModelVisitor interface and running modelity.model.Model.accept() method directly.

Parameters:
  • model – The model to serialize.

  • exclude_unset – Exclude unset fields.

  • exclude_none – Exclude fields set to None.

  • exclude_if

    Conditional function executed for every model location and value.

    Should return True to drop the value from resulting dict, or False to leave it. Can be used to achieve exclusion based on location and/or value.

  • datetime_format

    The format to use for datetime.datetime objects.

    Added in version 0.31.0.

  • date_format

    The format to use for datetime.date objects.

    Added in version 0.31.0.

modelity.api.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.api.field_postprocessor(*field_names: str)

Decorate model’s method as a field-level postprocessing hook.

Field postprocessors are only executed after successful preprocessing and parsing stages for the field they are declared for. Use this hook to perform additional per-field validation (executed when field is set or modified), or data normalization. Input value received by this hook is already parsed to a valid type and no other checking regarding this matter needs to take place.

Value returned by this kind of hook is either passed to a next postprocessor (if any), or stored as model’s field final value. No additional type checking takes place after postprocessing stage, so the user must pay attention to this.

The decorated method can be defined with no arguments, or with any subsequence of the following arguments:

cls

The model type.

errors

Mutable list of errors.

Can be extended by the postprocessor if postprocessing phase fails. Alternatively, postprocessor can raise TypeError exception that will automatically be converted into error and added to this list.

loc

The currently preprocessed model location.

This is instance of the modelity.loc.Loc type.

value

The input value for this postprocessor.

This will either be the output value of the type parser, or the output value of previous postprocessor (if any).

Here’s an example use:

from modelity.base import Model
from modelity.hooks import field_postprocessor

class FieldPostprocessorExample(Model):
    foo: str

    @field_postprocessor("foo")
    def _strip_white_characters(value):
        return value.strip()  # The 'value' is guaranteed to be str when this gets called
Parameters:

*field_names

List of field names.

This can be left empty if the hook needs to be run for every field.

Since hooks are inherited, this also includes subclasses of the model the hook was declared in and it is not checked in any way if field names are correct.

Changed in version 0.37.0: Removed self argument; use field_fixup() hook instead.

modelity.api.field_preprocessor(*field_names: str)

Decorate model’s method as a field-level preprocessing hook.

Field preprocessors are used to filter input value on a field-specific basis before it is parsed to a target type. For example, this hook can be used to strip string input from white characters.

Value returned by preprocessor is either passed to the next preprocessor (if any) or to the type parser assigned for the field that is being set or modified.

The decorated method can be defined with no arguments, or with any subsequence of the following arguments:

cls

The model type.

errors

Mutable list of errors.

Can be extended by the preprocessor if preprocessing phase fails. Alternatively, preprocessor can raise TypeError exception that will automatically be converted into error and added to this list.

loc

The currently preprocessed model location.

This is instance of the modelity.loc.Loc type.

value

The input value for this preprocessor.

This will either be user’s input value, or the output value of previous preprocessor (if any).

Here’s an example use:

from modelity.base import Model
from modelity.hooks import field_preprocessor

class Dummy(Model):
    foo: str

    @field_preprocessor("foo")
    def _strip_white_characters(value):
        if isinstance(value, str):
            return value.strip()
        return value
>>> dummy = Dummy(foo='  spam  ')
>>> dummy
Dummy(foo='spam')
Parameters:

*field_names

List of field names.

This can be left empty if the hook needs to be run for every field.

Since hooks are inherited, this also includes subclasses of the model the hook was declared in and it is not checked in any way if field names are correct.

modelity.api.field_validator(*field_names: str)

Decorate model’s method as a field-level validator.

This hook is executed for given field names only (or all fields, if the list of names is empty), if and only if the field is set and always in between model-level pre- and postvalidators.

cls

The model type.

self

The current model.

Different than root means that this is a nested model.

root

The root model instance.

This is the model for which modelity.helpers.validate() was called. Can be used to access entire model when performing validation.

ctx

The user-defined validation context.

Check guide-validation-using_context for more details.

errors

Mutable list of errors.

Can be extended by this hook to signal validation errors. Alternatively, ValueError exception can be raised and will automatically be converted into error and added to this list.

loc

The location of the currently validated model.

Will be empty if this is a root model, or non-empty if this model is nested inside another model.

This is instance of the modelity.loc.Loc type.

value

Field’s value to validate.

modelity.api.fixup(model: Model, ctx: Any = None)

Perform fixup on given model.

This helper runs all modelity.hooks.model_fixup() hooks defined for a model and also recurses into nested models. Performing fixup allows to run some post-parsing and pre-validation user-defined logic to fill in the model with derived or missing information.

Parameters:
  • model – The model to fixup.

  • ctx

    The user-defined context object to be shared by all fixup hooks.

    Can be used to pass some additional data to model, like results of API calls etc.

Changed in version 0.37.0: Added ctx argument.

Added in version 0.36.0.

modelity.api.has_fields_set(model: Model) bool

Check if model has at least one field set.

Parameters:

model – The model object.

modelity.api.is_any_optional(typ: Any) bool

Check if given type is any of the optional types supported by Modelity.

Parameters:

tp – The type to check.

modelity.api.is_deferred(typ: Any) bool

Check if given type is a deferred type.

Deferred types in Modelity are used to declare model fields as required but only during validation stage. This means that the field can be unset when model is created, but must later be set to pass validation.

Added in version 0.35.0.

Parameters:

tp – The type to check.

modelity.api.is_loose_optional(typ: Any) bool

Check if given type is LooseOptional[T].

Added in version 0.36.0.

Parameters:

tp – The type to check.

modelity.api.is_optional(typ: Any) bool

Check if given type is Optional[T].

Added in version 0.36.0.

Parameters:

tp – The type to check.

modelity.api.is_strict_optional(typ: Any) bool

Check if given type is StrictOptional[T].

Added in version 0.36.0.

Parameters:

tp – The type to check.

modelity.api.is_unset(obj: object) TypeIs[UnsetType]

Check if obj is instance of UnsetType type.

Changed in version 0.31.0: Now uses typing_extensions.TypeIs for type narrowing.

Added in version 0.17.0.

modelity.api.is_unsettable(typ: Any) bool

Check if given type annotation allows modelity.unset.Unset as valid value.

Added in version 0.35.0.

Parameters:

typ – The type to investigate.

modelity.api.load(model_type: type[MT], data: dict, ctx: Any = None) MT

Parse and validate given raw data using provided model type.

This is a helper function meant to be used to create models from data that is coming from an untrusted source, like API request, JSON file etc.

On success, this function returns new instance of the given model_type.

On failure, this function raises modelity.exc.ModelError.

Here’s an example:

from modelity.base import Model
from modelity.helpers import load

class Example(Model):
    foo: int
    bar: int
>>> untrusted_data = {"foo": "123", "bar": "456"}
>>> example = load(Example, untrusted_data)
>>> example
Example(foo=123, bar=456)
Parameters:
  • model_type – The model type to parse data with.

  • data – The data to be parsed.

  • ctx – The user-defined validation context.

modelity.api.location_validator(*patterns: str)

Decorate model’s method as a location validator.

This validator is meant to be used when model validation requires access to nested models, collections of models etc. It runs for every value that is set in the model and its location suffix matches given pattern, which also supports wildcards via * (star) character.

For example:

from modelity.api import Model, location_validator, validate

class Dummy(Model):

    class Nested(Model):
        foo: int

    nested: Nested

    @location_validator("nested.foo")  # This is matched to location's suffix
    def _validate_nested_foo(loc, value):
        if value < 0:
            raise ValueError(f"value at {loc} must be >= 0")
>>> dummy = Dummy(nested=Dummy.Nested(foo=-1))
>>> validate(dummy)
Traceback (most recent call last):
  ...
modelity.exc.ValidationError: Found 1 validation error for model 'Dummy':
  nested.foo:
    value at nested.foo must be >= 0 [code=modelity.EXCEPTION, exc_type=ValueError]

Thanks to this validator it is now possible to define entire validation logic for a model in one place without affecting nested models which may have different constraints if are used in another parent model.

Following arguments can be used in decorated function:

cls

The model type.

This is the type this decorator is declared in.

self

The instance of cls for which this decorator runs.

root

The root model instance.

If different than self then this validator runs for a nested model.

ctx

The user-defined validation context.

Check guide-validation-using_context for more details.

errors

Mutable list of errors.

Can be extended by this hook to signal validation errors. Alternatively, ValueError exception can be raised and will automatically be converted into error and added to this list.

loc

The location of the currently validated value.

This validator runs if and only if the suffix of this location matches one of patterns defined.

value

The validated value.

Added in version 0.27.0.

Parameters:

*patterns

Location patterns to run this validator for.

These are relative to the model where this decorator was used, so first element in each pattern refers to model’s fields, second (if any) to nested models or collection items etc.

Following wildcards are supported:

  • ? - matches exactly one location element (e.g. foo.?.bar will match foo.0.bar, but not foo.0.0.bar)

  • * - matches one or more location elements (e.g. foo.*.baz will match foo.bar.0.baz, but not foo.baz)

  • ** - matches zero or more location elements (e.g. foo.**.baz will match both foo.bar.0.baz and foo.baz)

modelity.api.model_fixup()

Decorate model’s method as a model-level fixup function.

Fixup hooks can be run for a given model using modelity.helpers.fixup() helper. This functionality can be used to perform some user-defined updates in the model tree before validation takes place and only after successful parsing. Fixup hooks can be fed with user-defined context object, and therefore it is possible to pass external data to set in the model before validation takes place.

The decorated method can be defined with no arguments, or with any subsequence of the following arguments:

cls

The current model type.

self

The current model object.

root

The root model.

This is the one for which modelity.helpers.fixup() was originally called.

ctx

The user-defined fixup context.

This can be used to pass some external data (e.g. API call results) to the model and use those during fixup. The type and structure is completely up to the user, Modelity will simply pass this to the user-defined fixup hooks and will not perform any additional checks.

loc

The location in the model tree.

Will be empty for root model, or non-empty for nested one.

Changed in version 0.37.0:

  • Now these hooks can only be called on demand via modelity.helpers.fixup() helper or dedicated visitor.

  • Added root and ctx arguments.

Added in version 0.36.0.

modelity.api.model_postvalidator()

Decorate model’s method as a model-level postvalidation hook.

Model postvalidators are executed as the final validation step, after model prevalidators, built-in validators and field-level validators.

The arguments for the decorated method are exactly the same as for model_prevalidator() hook.

modelity.api.model_prevalidator()

Decorate model’s method as a model-level prevalidation hook.

Model prevalidators are executed as the initial validation step, before any other validators, including built-in ones.

Model prevalidators can be used to skip other validators for the current model. This feature can be used either conditionally disable validation, or to replace it with custom one. To skip other validators, True must be returned. Returning True only applies to the instances of the model where model prevalidator returning True is defined.

Important

Returning True and skipping other validators also applies to built-in ones. For example, required fields validation will also be skipped if True is returned.

The decorated method can be defined with no arguments, or with any subsequence of the following arguments:

cls

The model type.

self

The current model.

Different than root means that this is a nested model.

root

The root model instance.

This is the model for which modelity.helpers.validate() was called. Can be used to access entire model when performing validation.

ctx

The user-defined validation context.

Check guide-validation-using_context for more details.

errors

Mutable list of errors.

Can be extended by this hook to signal validation errors. Alternatively, ValueError exception can be raised and will automatically be converted into error and added to this list.

loc

The location of the currently validated model.

Will be empty if this is a root model, or non-empty if this model is nested inside another model.

This is instance of the modelity.loc.Loc type.

modelity.api.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.

modelity.api.validate(model: Model, ctx: Any = None)

Validate provided model.

On success, this method raises no exception and returns None.

On failure, modelity.exc.ValidationError exception is raised.

Parameters:
  • model – The model to validate.

  • ctx – The user-defined validation context.