Jak używać
- Skopiuj polecenie instalacji i sprawdź źródła przed instalacją we własnym środowisku agenta.
- W oryginale sprawdź wymagane narzędzia, dane dostępowe i obsługiwane środowiska.
- Opisz dane wejściowe i oczekiwany rezultat; porównaj wynik ze źródłami.
npx skills add https://github.com/TerminalSkills/skills --skill pydanticPrzed rozpoczęciem
- Instalacja nie obejmuje subskrypcji modelu, limitu API ani uprawnień do plików.
- Gwiazdki i instalacje pokazują aktywność, a nie niezależny test jakości lub bezpieczeństwa.
Treść z repozytorium z zachowaniem nagłówków, przykładów, kodu, tabel, linków i obrazów.
Pydantic
Overview
Pydantic is a data validation library built on Python type hints. A model class validates inputs, coerces types ("28" becomes 28 in the default lax mode), and serializes outputs. The core is written in Rust (pydantic-core), and the library underlies FastAPI, LangChain and most modern Python frameworks. This skill targets Pydantic v2 (2.14.1 checked, October 2026) and pydantic-settings 2.16; every snippet below was run against those versions.
Instructions
Step 1: Install
pip install pydantic # core
pip install "pydantic[email]" # adds email-validator, required by EmailStr
pip install pydantic-settings # BaseSettings lives in this separate packageStep 2: Basic models
# schemas.py
from datetime import datetime
from pydantic import BaseModel, ConfigDict, EmailStr, Field, ValidationError
class UserCreate(BaseModel):
name: str = Field(min_length=2, max_length=100)
email: EmailStr
age: int = Field(ge=13, le=120)
role: str = Field(default="member", pattern=r"^(admin|member|viewer)$")
class UserResponse(BaseModel):
model_config = ConfigDict(from_attributes=True) # build from ORM objects
id: str
name: str
role: str
created_at: datetime
user = UserCreate(name="Maria Santos", email="maria@acme-bakery.com", age=28)
print(user.model_dump()) # {'name': 'Maria Santos', 'email': '...', 'age': 28, 'role': 'member'}
print(user.model_dump_json()) # JSON string
try:
UserCreate(name="A", email="nope", age=5)
except ValidationError as e:
print(e.error_count()) # 3
print([(x["type"], x["loc"]) for x in e.errors()])
# [('string_too_short', ('name',)), ('value_error', ('email',)), ('greater_than_equal', ('age',))]
row = db.get_user(7) # any object with matching attributes
response = UserResponse.model_validate(row) # needs from_attributes=TrueValidationError must be imported from pydantic. Parse JSON text directly with UserCreate.model_validate_json(raw), which is faster and stricter than json.loads followed by model_validate.
Step 3: Custom validators
from datetime import datetime
from pydantic import BaseModel, field_validator, model_validator
class ProjectCreate(BaseModel):
name: str
slug: str
start_date: datetime
end_date: datetime | None = None
@field_validator("slug")
@classmethod
def validate_slug(cls, v: str) -> str:
if not v.replace("-", "").isalnum():
raise ValueError("Slug must contain only letters, numbers, and hyphens")
return v.lower()
@model_validator(mode="after")
def validate_dates(self):
if self.end_date and self.end_date <= self.start_date:
raise ValueError("End date must be after start date")
return selfRaise ValueError (or AssertionError); Pydantic wraps it as a value_error with the message prefixed "Value error, ". A mode="after" model validator is an instance method and must return self.
Step 4: Settings from the environment
# config.py
from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
database_url: str
secret_key: SecretStr
redis_url: str = "redis://localhost:6379"
debug: bool = False
allowed_origins: list[str] = ["http://localhost:3000"]
settings = Settings() # reads environment variables first, then .envVariable names match field names case-insensitively (DATABASE_URL). Complex types are passed as JSON: ALLOWED_ORIGINS='["https://shop.example.org","https://admin.example.org"]'. A missing required field raises ValidationError at startup, which is the point. SecretStr prints as **********; call .get_secret_value() to use it. By default .env entries that match no field raise an error; extra="ignore" skips them.
Step 5: Discriminated unions
from typing import Annotated, Literal
from pydantic import BaseModel, Field, TypeAdapter
class TaskCreated(BaseModel):
type: Literal["task.created"] = "task.created"
task_id: str
title: str
class TaskCompleted(BaseModel):
type: Literal["task.completed"] = "task.completed"
task_id: str
duration_hours: float
class CommentAdded(BaseModel):
type: Literal["comment.added"] = "comment.added"
comment_id: str
body: str
WebhookEvent = Annotated[TaskCreated | TaskCompleted | CommentAdded, Field(discriminator="type")]
event_adapter = TypeAdapter(WebhookEvent)
event = event_adapter.validate_json('{"type": "task.completed", "task_id": "T-123", "duration_hours": 2.5}')
# TaskCompleted(type='task.completed', task_id='T-123', duration_hours=2.5)A plain union (A | B | C) has no model_validate; wrap it in TypeAdapter. With Field(discriminator=...) Pydantic reads the tag and validates against one model only, so the error for an unknown tag is a single union_tag_invalid instead of one error per member. TypeAdapter also validates non-model types: TypeAdapter(list[int]).validate_python(["1", "2"]) returns [1, 2].
Step 6: Strictness and extra fields
from pydantic import BaseModel, ConfigDict
class Payment(BaseModel):
model_config = ConfigDict(strict=True, extra="forbid")
amount_cents: intBy default Pydantic coerces ("1" to 1) and ignores unknown keys. strict=True rejects the string (int_type); extra="forbid" rejects unknown keys (extra_forbidden). Use both for security-sensitive inputs. Export a JSON Schema with UserCreate.model_json_schema().
Examples
"Validate the signup body in my FastAPI endpoint." Declare def signup(body: UserCreate); FastAPI runs the model and returns HTTP 422 with the e.errors() list when validation fails. Input {"name": "A", "email": "nope", "age": 5} yields three errors located at name, email and age.
"Load config and fail fast if something is missing." Use the Settings class from Step 4. With SECRET_KEY set and DATABASE_URL unset, Settings() raises ValidationError: 1 validation error for Settings ... database_url Field required, so the process exits before serving traffic.
Guidelines
- Pydantic v1 names are gone or renamed:
.dict()is.model_dump(),.json()is.model_dump_json(),parse_objismodel_validate,@validatoris@field_validator,@root_validatoris@model_validator,class Configismodel_config,orm_modeisfrom_attributes,regex=ispattern=.BaseSettingsmoved topydantic-settings. Thepydantic.v1namespace exists only as a bridge. EmailStrneeds theemailextra; without it, import fails with a message pointing toemail-validator.- Mutable defaults like
[]are safe in Pydantic (copied per instance), unlike in plain classes. - Validators run on input, not on attribute assignment, unless
validate_assignment=True. - Never use
model_construct()on untrusted data; it skips validation. - Keep request models (
UserCreate) and response models (UserResponse) separate so secrets such as password hashes cannot leak into responses.

