Skip to main content

typing-validation

Python versions PyPI version PyPI status Checked with Mypy Documentation Status

A library to perform runtime validation of Python objects using type hints.

Install

Install the latest release from PyPI:

$ pip install --upgrade typing-validation

Usage

Validate a value against a type hint. validate returns True on success and raises on failure:

>>> from typing_validation import validate
>>> validate([1, 2, 3], list[int])
True

The True return exists so that validation can be gated behind an assertion, and compiled out entirely under -O:

assert validate(val, t)

When a value does not conform, the error says where:

>>> validate({"a": [1, "b"]}, dict[str, list[int]])
Traceback (most recent call last):
  ...
typing_validation.errors.ValidationError: For type dict[str, list[int]]: a component failed
  For type list[int] value at key 'a': a component failed
    For type <class 'int'> index 1: not an instance, got 'b'

The structured explanation is on the exception, for reading programmatically:

>>> try:
...     validate([1, "b"], list[int])
... except ValidationError as e:
...     print(e.failure.causes[0].location.at)
1

Validating the same type repeatedly

validate analyses the type on every call. When you validate many values against one type, validator analyses it once and hands back a function:

>>> from typing_validation import validator
>>> check = validator(list[int])
>>> check([1, 2, 3])
True

Same contract, same verdict, 2.7× faster per call, and it repays the cost of building it within a handful of values.

And when the values keep coming in very large numbers, compiled_validator emits Python specialised to the type and compiles it:

>>> from typing_validation import compiled_validator
>>> check = compiled_validator(list[int])
>>> check([1, 2, 3])
True

That runs at 11.5 ns per type-node against a hand-written check's 11.1 — it is, within a few percent, the code you would have written yourself. It costs more to build, and it only helps where there is structure to unroll: for a recursive alias or a NumPy array it stops unrolling and hands back a validator, and the table says never rather than pretending otherwise.

So: validate for one-off checks, validator when the type is fixed and the values keep coming, compiled_validator when there are very many of them.

Type validate validator compiled_validator hand-written
list[int] (1000 items) 58.1 µs 21.4 µs 13.5 µs 12.4 µs
list[int] (20 items) 1.5 µs 540 ns 287 ns 284 ns
dict[str, int] (20 items) 2.7 µs 1.0 µs 559 ns 548 ns
tuple[int, str] 428 ns 215 ns 80 ns 64 ns
int 49 ns 46 ns 46 ns 27 ns

benchmark/RESULTS.md has the full table — every case, both outcomes, construction costs, and the break-even points that say exactly how many values each mechanism needs before it repays — with the machine it was measured on. Run python -m benchmark for your own numbers, or python -m benchmark --write to regenerate it.

One difference, and it is deliberate. Both validator and compiled_validator analyse the whole type before seeing any value, so they reject an unsupported type immediately:

validator(list[Callable[[int], int]])     # UnsupportedTypeError, at once
validate([], list[Callable[[int], int]])  # True — no value reached the Callable

The rest of the surface

from typing_validation import is_valid, validated, validated_iter

is_valid([1, "a"], list[int])       # False — a boolean, at boolean prices
validated(payload, list[int])       # returns payload, for use in an expression
validated_iter(stream, Iterator[int])  # checks each item as it is yielded

is_valid deliberately builds no explanation: a caller who wants one calls validate and catches the exception.

validated_iter is not a convenience wrapper. Determining the items of a one-shot iterator consumes it, so Iterator[int] cannot check its items eagerly without destroying the value — checking them on the way past is the only honest way.

Asking about a type

Support is all-or-nothing: if any component of a type is unsupported, the whole type is. can_validate answers up front:

>>> from typing_validation import can_validate, inspect_type
>>> can_validate(list[int])
True
>>> can_validate(tuple[int, Callable[[int], int]])   # poisoned by the Callable
False

inspect_type returns the whole structure and names precisely what poisoned it, so "unsupported" is never opaque:

>>> node = inspect_type(tuple[int, Callable[[int], int]])
>>> [c.t for c in node.unsupported_components()]
[typing.Callable[[int], int]]

NumPy

NumPy array types are supported by an extension, which you enable by importing:

import typing_validation.numpy   # required
from numpy.typing import NDArray

validate(np.array([1, 2], dtype=np.uint8), NDArray[np.uint8])

The import is required rather than automatic, so that the supported surface never depends on whether some unrelated dependency happened to import NumPy.

Extending

A parametrised class can say how its own type arguments are validated:

class Box[T]:
    @classmethod
    def __validate__(cls, val, args):
        return is_valid(val.item, args[0])

For classes you do not own, use register_validator(cls, check).

API

The full API documentation is available at typing-validation.readthedocs.io.

Structure

  • typing_validation/ — the package source.
  • knowledge/ — design documents: the architecture, and the catalogue of supported type forms.
  • test/ — the conformance suite, with the case corpus in test/cases.py.
  • benchmark/ — the benchmark suite; run it with python -m benchmark.
  • docs/ — the Sphinx documentation pipeline.

License

LGPL-3.0-or-later © Hashberg Ltd

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

typing_validation-2.2.0.tar.gz (59.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

typing_validation-2.2.0-py3-none-any.whl (68.9 kB view details)

Uploaded Python 3

File details

Details for the file typing_validation-2.2.0.tar.gz.

File metadata

  • Download URL: typing_validation-2.2.0.tar.gz
  • Upload date:
  • Size: 59.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for typing_validation-2.2.0.tar.gz
Algorithm Hash digest
SHA256 cd872327a2dbca15f2999828b76ce515b564f0acfa61237a0f2aec7dbb3b16c4
MD5 c6305290d7b6b3fea6bde013634f72c8
BLAKE2b-256 0005dc4f3dfb82264d9cb5c0ee1f5b4126c489ad651048dcd0a0c1830ca4fcfe

See more details on using hashes here.

File details

Details for the file typing_validation-2.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for typing_validation-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2523e354185a45bc1035a72e2ed810ba25230196ec627b7a0f3024c578ae499a
MD5 e27f644db789283402ab53928f8d7921
BLAKE2b-256 f3f8e3d41a75f065f9f5bd1415720a8c807e96c98dbfd46fa702d39c13b2646d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page