Skip to content

pydantic

The pydantic adaptor reads any subclass of pydantic.BaseModel, and its members are instances of the model. Membership is the model's own model_validate, so a validator you wrote on the model counts, and a non-member is explained in pydantic's own words. The adaptor decides whether an object is a model without importing pydantic: if pydantic was never imported, nothing can be a model. It needs pydantic 2.0 or later, pip install "mathema-language[pydantic]", and is tested at 2.0 and at the latest release.

What it reads

pydantic spelling Neutral model Notes
a field's annotation as for a dataclass field read off model_fields
Field(ge=1, le=10), Field(gt=..., lt=...) min, max, exclusive_min, exclusive_max from the field's metadata
Field(min_length=..., max_length=...) min_len, max_len
Field(pattern=...) regex generation draws matching strings; the model decides membership
Field(multiple_of=...) multiple_of
a default the field's default, the field not required a default_factory is not called at adaptation
model_config = ConfigDict(extra="forbid") the exact column policy an extra field is then a non-member
@field_validator, @model_validator not read enforced by model_validate, so generation may draw a record the model refuses, and the refusal filters it out

A worked claim

The shop's signup form, from examples/shop/forms.py:

from pydantic import BaseModel, ConfigDict, Field


class SignupForm(BaseModel):
    model_config = ConfigDict(extra="forbid")

    username: str = Field(min_length=3, max_length=32)
    age: int = Field(ge=13, le=120)


def years_until_eighteen(form: SignupForm) -> int:
    """How many years until the user turns 18."""
    return max(0, 18 - form.age)
Function Claim Verdict Why
years_until_eighteen for form in L[shop.forms.SignupForm], 0 <= f(form) <= 5 proven The lift reads the age's bounds off the model's fields, so the wait is between none and five years.
years_until_eighteen for form in L[shop.forms.SignupForm], f(form) <= 4 falsified A thirteen-year-old waits five years.

Enforcing the schema

A function that guards a boundary should refuse a record its schema rejects. excluded_outside_domain feeds it records just outside the language, and the witness names the value and why it is outside, in the library's own words. This function trusts its input, so a record the schema rejects goes straight through:

def welcome_message(form: SignupForm) -> str:
    """The first line of the welcome email."""
    return f"Welcome, {form.username}!"
f = welcome_message
for form in L[shop.forms.SignupForm], excluded_outside_domain(form)
    falsified   form = SignupForm(username='aaa', age=12) (outside L[shop.forms.SignupForm] at .age: Input should be greater than or equal to 13)

The same claim over the function that loads the record, from a request or a database, is the one that should hold.