require-pydantic-for-mapping-shape
Declare opaque mapping field shapes in Pydantic instead of probing them by hand.
Why
Fixed-key reads followed by runtime type, shape, or discriminator checks spread a record contract across control flow. An object/Any/JsonValue mapping does not declare those field contracts.
Fix
Parse the raw object with a named Pydantic BaseModel or RootModel before using typed attributes. Prefer strict fields, Field bounds, aliases/AliasPath and discriminated unions to handwritten probes. For an already trusted internal record, declare a precise named record such as TypedDict instead of parsing it again. Preserve rejection, defaults and fail-closed behavior explicitly; bool is an int subclass.
Examples
def verified(raw: dict[str, object]) -> bool: match raw.get("factor_age"): case [int(), int(age)] if not isinstance(age, bool): return age >= 0 case _: return Falsefrom typing import Annotatedfrom pydantic import BaseModel, Field, StrictInt, ValidationError
class FactorClaim(BaseModel): factor_age: tuple[StrictInt, Annotated[StrictInt, Field(ge=0)]]
def verified(raw: object) -> bool: try: FactorClaim.model_validate(raw) except ValidationError: return False return True