about things notes.zzstoatzz.io
notes

pydantic #

pydantic makes python's type hints real at runtime. define a model with annotations, and pydantic validates and coerces data to match.

from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

user = User(name="alice", age="25")  # age coerced to int
user = User(name="alice", age="not a number")  # raises ValidationError

this is why pydantic shows up everywhere — it bridges python's dynamic runtime and the desire for validated, typed data.

when to use what #

tool use when
BaseModel API boundaries, external data, anything you serialize
BaseSettings configuration from env vars / .env files
Annotated[T, ...] types reusable validation bound to the type, not the model
dataclasses internal data you control — no validation overhead
TypedDict typed dict unpacking (**kwargs) with per-key types

pydantic models are heavier than they look — they do real work on instantiation. for internal data:

from dataclasses import dataclass

@dataclass
class BatchResult:
    successful: list[str]
    failed: list[tuple[str, Exception]]

    @property
    def total(self) -> int:
        return len(self.successful) + len(self.failed)

use pydantic at boundaries. use dataclasses for internal structures.

contents #

  • settings — BaseSettings, env loading, splitting config by concern
  • validation — Annotated types, validators, custom types
  • serialization — model_dump, computed fields, JSON round-trips

sources #