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

57 lines
3.3 KiB
Markdown

# 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