57 lines
3.3 KiB
Markdown
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
|