Files
python-patterns/sources/pydantic.md
T
2026-06-01 21:42:05 +00:00

3.3 KiB

Pydantic source notes

Repo: pydantic/pydantic Local checkout: /home/ubuntu/repos/rodin-sources/pydantic

Why this repo is useful

  • Pydantic is a strong source for boundary-object patterns: validating incoming data, preserving typed state, and serializing back out explicitly.
  • It is also useful for validation-hook design because the docs distinguish several validator phases and call out their tradeoffs clearly.

Models are explicit validation + serialization boundaries

Repeated evidence

  • pydantic/main.py:119-145 defines BaseModel as the central abstraction and documents that models carry schema, field metadata, and decorator metadata.
  • pydantic/main.py:201-205 explicitly exposes model-level serializer and validator machinery as core parts of the abstraction.
  • docs/index.md:68-82 shows external data entering through model construction.
  • docs/index.md:82-89 immediately turns the model back into a plain data structure with model_dump().
  • docs/index.md:109-152 shows invalid boundary data raising ValidationError with structured per-field errors instead of silently degrading.

Why it matters

Repeated signal: Pydantic models are meant to sit at I/O boundaries. Input is validated/coerced at construction time; output is serialized through an explicit dump step.

Caveat / counterexample

The strong pattern is not "models are your whole domain model." The evidence here is boundary-oriented: construct from external data, then call model_dump() when leaving the boundary again.

Validators are narrow and phase-aware

Repeated evidence

  • docs/concepts/validators.md:91-114 shows an after field validator that checks one parsed field and must return the validated value.
  • docs/concepts/validators.md:160-167 explains that before validators run prior to internal parsing and therefore receive raw input.
  • docs/concepts/validators.md:220-252 demonstrates a before validator that reshapes raw input and then lets normal item validation continue.

Why it matters

Repeated signal: the best validator hooks are small in scope and explicit about phase:

  • before for raw-input normalization
  • after for post-parse invariants

This prevents validation logic from becoming an opaque second parser.

Validator mode choice has real behavioral consequences

Repeated evidence

  • docs/concepts/validators.md:160-164 warns that before validators should avoid careless mutation when raising later, especially with unions.
  • docs/concepts/validators.md:254-255 states that plain validators terminate validation immediately.
  • docs/concepts/validators.md:273-283 shows the consequence directly: a PlainValidator can return 'invalid' for a field annotated as int, and Pydantic will accept it.

Why it matters

Repeated signal: validator mode is not just an implementation detail. It changes whether core type validation still runs.

Caveat / counterexample

This is the sharpest anti-pattern in the repo: plain validators are powerful, but they can bypass the type guarantee a reader expects from the annotation. Use them only when terminating validation is the actual goal.

Pattern candidates supported by this repo

  • use typed models at I/O boundaries
  • serialize explicitly with model_dump()
  • keep validators field-scoped and phase-aware
  • treat plain validators as an escape hatch, not the default