valid8r.integrations.pydantic
Pydantic integration for valid8r parsers.
This module provides utilities to convert valid8r parsers (which return Maybe[T]) into Pydantic field validators, enabling seamless integration with FastAPI and other Pydantic-based frameworks.
The integration supports: - Simple field validation with type parsing and validation - Nested model validation with field path error reporting - List[Model] validation with per-item error reporting - Dict[K, V] validation with per-value validation - Optional fields and complex structures
- Example - Simple Field Validation:
>>> from pydantic import BaseModel, field_validator >>> from valid8r.core import parsers, validators >>> from valid8r.integrations.pydantic import validator_from_parser >>> >>> class User(BaseModel): ... age: int ... ... @field_validator('age', mode='before') ... @classmethod ... def validate_age(cls, v): ... return validator_from_parser( ... parsers.parse_int & validators.between(0, 120) ... )(v)
- Example - Nested Model Validation:
>>> from valid8r.core.parsers import PhoneNumber >>> >>> class Address(BaseModel): ... phone: PhoneNumber ... ... @field_validator('phone', mode='before') ... @classmethod ... def validate_phone(cls, v): ... return validator_from_parser(parsers.parse_phone)(v) >>> >>> class User(BaseModel): ... name: str ... address: Address >>> >>> # Validation errors include full field path (e.g., 'address.phone') >>> user = User(name='Alice', address={'phone': '(206) 234-5678'})
- Example - List of Models:
>>> class LineItem(BaseModel): ... quantity: int ... ... @field_validator('quantity', mode='before') ... @classmethod ... def validate_quantity(cls, v): ... def parser(value): ... return parsers.parse_int(value).bind(validators.minimum(1)) ... return validator_from_parser(parser)(v) >>> >>> class Order(BaseModel): ... items: list[LineItem] >>> >>> # Validation errors include list index (e.g., 'items[1].quantity') >>> order = Order(items=[{'quantity': '5'}, {'quantity': '10'}])
- Example - Dict Value Validation:
>>> class Config(BaseModel): ... ports: dict[str, int] ... ... @field_validator('ports', mode='before') ... @classmethod ... def validate_ports(cls, v): ... if not isinstance(v, dict): ... raise ValueError('ports must be a dict') ... return {k: validator_from_parser(parsers.parse_int)(val) for k, val in v.items()} >>> >>> config = Config(ports={'http': '80', 'https': '443'})
Functions
|
Convert a valid8r parser into a Pydantic field validator. |
|
Create a Pydantic AfterValidator from a valid8r parser. |
|
Create a Pydantic WrapValidator from a valid8r parser. |
Module Contents
- valid8r.integrations.pydantic.validator_from_parser(parser, *, error_prefix=None)[source]
Convert a valid8r parser into a Pydantic field validator.
This function takes a valid8r parser (any callable that returns Maybe[T]) and converts it into a function suitable for use with Pydantic’s field_validator decorator.
Works seamlessly with: - Simple fields (str, int, custom types) - Nested models (User -> Address -> phone) - Lists of models (Order with list[LineItem]) - Dicts with validated values (Config with dict[str, int]) - Optional fields (field: Model | None)
Pydantic automatically handles field path reporting for nested structures, so validation errors will include the full path (e.g., ‘address.phone’ or ‘items[1].quantity’).
- Parameters:
parser (collections.abc.Callable[[Any], valid8r.core.maybe.Maybe[T]]) – A valid8r parser function that returns Maybe[T].
error_prefix (str | None) – Optional prefix to prepend to error messages.
- Returns:
A validator function that returns T on success or raises ValueError on failure.
- Raises:
ValueError – When the parser returns a Failure with the error message.
- Return type:
collections.abc.Callable[[Any], T]
Example
>>> from valid8r.core import parsers >>> validator = validator_from_parser(parsers.parse_int) >>> validator('42') 42 >>> validator('invalid') Traceback (most recent call last): ... ValueError: ...
>>> # With custom error prefix >>> validator = validator_from_parser(parsers.parse_int, error_prefix='User ID') >>> validator('invalid') Traceback (most recent call last): ... ValueError: User ID: ...
>>> # Nested model validation >>> from pydantic import BaseModel, field_validator >>> from valid8r.core.parsers import EmailAddress >>> >>> class Contact(BaseModel): ... email: EmailAddress ... ... @field_validator('email', mode='before') ... @classmethod ... def validate_email(cls, v): ... return validator_from_parser(parsers.parse_email)(v) >>> >>> contact = Contact(email='user@example.com')
- valid8r.integrations.pydantic.make_after_validator(parser)[source]
Create a Pydantic AfterValidator from a valid8r parser.
AfterValidator runs after Pydantic’s type conversion, allowing you to use valid8r parsers with Pydantic’s Annotated type system for cleaner model definitions.
This function wraps a valid8r parser (which returns Maybe[T]) into a function suitable for use with Pydantic’s AfterValidator. For optional fields (e.g.,
str | None),Nonevalues are passed through without validation.- Parameters:
parser (collections.abc.Callable[[Any], valid8r.core.maybe.Maybe[T]]) – A valid8r parser function that returns Maybe[T].
- Returns:
A validator function that returns T on success, None for None inputs, or raises ValueError on failure.
- Raises:
ValueError – When the parser returns a Failure with the error message.
- Return type:
collections.abc.Callable[[Any], T | None]
Example
>>> from pydantic import BaseModel, AfterValidator >>> from typing_extensions import Annotated >>> from valid8r.core import parsers >>> >>> email_validator = make_after_validator(parsers.parse_email) >>> >>> class User(BaseModel): ... email: Annotated[str, AfterValidator(email_validator)] >>> >>> user = User(email='alice@example.com')
>>> # Optional field example >>> class Contact(BaseModel): ... email: Annotated[str | None, AfterValidator(email_validator)] = None >>> >>> contact = Contact(email=None) >>> contact.email is None True
- valid8r.integrations.pydantic.make_wrap_validator(parser)[source]
Create a Pydantic WrapValidator from a valid8r parser.
WrapValidator runs before Pydantic’s type conversion, receiving raw input values. This allows full control over validation and pre-processing.
This function wraps a valid8r parser (which returns Maybe[T]) into a function suitable for use with Pydantic’s WrapValidator.
- Parameters:
parser (collections.abc.Callable[[Any], valid8r.core.maybe.Maybe[T]]) – A valid8r parser function that returns Maybe[T].
- Returns:
A wrap validator function that returns T on success or raises ValueError on failure. The function signature is (value, handler) -> T, though handler is not used since the parser handles all validation.
- Raises:
ValueError – When the parser returns a Failure with the error message.
- Return type:
collections.abc.Callable[[Any, Any], T]
Example
>>> from pydantic import BaseModel, WrapValidator >>> from typing_extensions import Annotated >>> from valid8r.core import parsers >>> >>> int_validator = make_wrap_validator(parsers.parse_int) >>> >>> class Data(BaseModel): ... value: Annotated[int, WrapValidator(int_validator)] >>> >>> data = Data(value='42')