Complete worked example
python
from typing import Any, Generic, TypeVar
from pydantic import BaseModel, Field, ValidationError
T = TypeVar("T")
class Role(BaseModel):
id: int
title: str
class Page(BaseModel, Generic[T]):
items: list[T]
total: int = Field(ge=0)
def inspect_example(payload):
try:
return {"value": Page[Role].model_validate(payload).model_dump()}
except ValidationError as error:
return {"error": sorted({e["type"] for e in error.errors()})}- Reasoning
- The type variable appears in the items field, and the concrete parameter is supplied at the validation call. A numeric string ID becomes an integer under the Role contract. Missing titles and malformed integer IDs produce nested validation errors instead of silently passing through a dictionary list. The fixture compares the ordinary dumped page, including normalized item values. Page[Any] is deliberately not equivalent: it keeps arbitrary item values and can retain a string ID. The counterexample uses that weaker parameter to demonstrate why explicitly selecting the generic argument is part of the boundary design.