Modern Python Standards
Development practices for Python 3.10+ focusing on type safety, modern idioms, and efficient tooling.
Core Defaults
# Always use modern patterns
from pathlib import Path
from typing import Any
from dataclasses import dataclass
def process(items: list[dict[str, Any]]) -> dict[str, int] | None:
config_path = Path("config.json")
return {"count": len(items)} if items else None
Recommended Stack
| Category | Tool |
|---|---|
| Package Management | uv (preferred) or Poetry |
| Linting/Formatting | Ruff |
| Type Checking | mypy (strict mode) |
| Testing | pytest with coverage |
| Web APIs | FastAPI |
| Data Processing | Polars or Pandas |
Key Patterns
Type Hints
- All public functions must have type hints
- Use
X | Nonefor nullable values (3.10+) - Prefer
list[X]overList[X](3.9+) - Use
TypeVarfor generic functions
Async
- Use
asynciowith modern patterns - Avoid blocking in async contexts
asyncio.gather()for concurrent operationsasyncio.TaskGroupfor structured concurrency (3.11+)
Path Handling
- Always
pathlib.Pathoveros.path - Use
.read_text(),.write_text() - Proper path resolution, no hardcoding
Error Handling
- Specific exceptions, never bare
except: - Context managers for resources
- Proper logging with structlog
Pydantic Settings Validation
Validator timing determines when validation executes:
| Decorator | Timing | Use Case |
|---|---|---|
@property |
Lazy (on access) | Computed values |
@field_validator |
Per-field (during parse) | Single-field rules |
@model_validator |
Initialization (after parse) | Cross-field security controls |
Security controls typically use @model_validator to fail fast:
from pydantic import model_validator
class Settings(BaseSettings):
environment: str = "development"
auth_database_url: str | None = None
@model_validator(mode="after")
def validate_production_requirements(self) -> "Settings":
if self.environment == "production" and not self.auth_database_url:
raise ValueError("AUTH_DATABASE_URL required in production")
return self
Pydantic Value Object Comparison
When comparing Pydantic models or value objects, use str() on both sides:
# WRONG - type mismatch causes silent failures
session.visitor_id.value != visitor_id
# RIGHT - explicit string conversion
str(session.visitor_id) != str(visitor_id)
Anti-Patterns to Avoid
| Bad | Good |
|---|---|
os.path.join() |
Path() / "file" |
% formatting |
f-strings |
pip install |
uv add |
flake8 |
Ruff |
List[str] |
list[str] |
Optional[X] |
X | None |
| Mutable default args | field(default_factory=list) |
time.time() for elapsed |
time.perf_counter() |
See reference.md for detailed patterns and examples.md for code samples.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.