pytypehint 1.2.0
Define data with Python type hints. Validate input, build nested dataclasses, inspect their fields or export a portable schema.
Use @immutable for deeply immutable models that validate themselves and
reuse validated children without checking their contents again.
Exact types, no implicit coercion. Python 3.11+, standard library only. The schema and validation core of FuncToWeb.
pip install pytypehint
Validate input into ordinary dataclasses
from dataclasses import dataclass
from typing import Annotated
from pytypehint import Min, struct_of
@dataclass
class Item:
name: str
quantity: Annotated[int, Min(1)] = 1
schema = struct_of(Item)
item = schema.build({"name": "Pen"}) # Item(name='Pen', quantity=1)
schema.build({"name": "Pen", "quantity": 0}) # SchemaValueError: quantity
Compile once and reuse. Errors include the failing field or index in their path.
Immutable models
Declare constraints once. Normal construction and dataclasses.replace validate
automatically; nested instances keep their identity.
from dataclasses import replace
from typing import Annotated
from pytypehint import Max, Min, immutable
Positive = Annotated[int, Min(1)]
Channel = Annotated[float, Min(0.0), Max(1.0)]
@immutable
class Exposure:
stops: float = 0.0
@immutable
class Grayscale:
pass
@immutable
class Layer:
name: Annotated[str, Min(1)]
effect: Exposure | Grayscale
color: tuple[Channel, Channel, Channel, Channel] = (0.0, 0.0, 0.0, 1.0)
@immutable
class Document:
size: tuple[Positive, Positive]
layers: tuple[Layer, ...] = ()
photo = Layer(name="Photo", effect=Exposure(stops=1.5))
original = Document(size=(1920, 1080), layers=(photo,))
resized = replace(original, size=(3840, 2160))
assert resized.layers[0] is photo
assert original.size == (1920, 1080)
The new document checks its size and layer references, without revisiting the existing layer's fields. Tuples are checked; existing immutable children are reused.
replace(photo, color=(1.0, 0.0, 0.0, 2.0)) # SchemaValueError, path: ('color', 3)
Exposure(stops="1.5") # SchemaTypeError
original.size = (800, 600) # FrozenInstanceError
Allowed fields are immutable scalars, tuples and other @immutable models.
Mutable containers, ordinary dataclasses and enums are rejected. The guarantee
covers declared fields through normal Python use; deliberate low-level mutation
can bypass it. Full contract, inheritance and defaults.
Load portable data and inspect the same definition
The models above also work with the existing schema API:
from pytypehint import struct_of
schema = struct_of(Document)
loaded = schema.build(schema.decode({
"size": [1920, 1080],
"layers": [{
"name": "Photo",
"effect": {"$type": "Exposure", "stops": 1.5},
}],
}))
assert loaded == original
contract = schema.to_dict() # Portable description for a UI or another process
Type constraints and interface metadata live on the same field:
from pytypehint import Label, Slider, Step
@immutable
class Brush:
size: Annotated[int, Min(1), Max(256), Label("Brush size"), Step(1), Slider()] = 32
size_field, = struct_of(Brush).fields
size_shape, = size_field.shape
assert size_field.label.value == "Brush size"
assert size_shape.max.value == 256
| Method | Result |
|---|---|
build(data) |
Dataclass instance; signature_of(fn) returns kwargs for fn(**kwargs) |
resolve(data) |
Validated dictionary with missing defaults filled at this level |
decode(data) |
Portable values restored to Python types |
to_dict() |
Portable schema description |
Documentation
Metadata
Release files for pytypehint 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pytypehint-1.2.0.tar.gz | 283.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pytypehint-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 310.3 kB
Release files / pytypehint-1.2.0.tar.gz
| Download URL | pytypehint-1.2.0.tar.gz |
|---|---|
| Size | 283.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dab4baaa751f8983a421e2c9b63d9d699d4c6ac134327424c301e10a519f2fdb
|
|
BLAKE2b-256 checksum How to use checksums |
f968bfedead2327c8a2e228de52939757204de6d85b86e22c25e7decec575ada
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / pytypehint-1.2.0-py3-none-any.whl
| Download URL | pytypehint-1.2.0-py3-none-any.whl |
|---|---|
| Size | 26.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
757706baa81ccbd6ff8c9782c2cf97a3671dde588b707e0cf43914d79623dfd4
|
|
BLAKE2b-256 checksum How to use checksums |
7d6725a17c5cfd0ee5378869428e6ac3c51a9c1f44f3b758cbdcce4b385c5697
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log