Python Engineering
Load this skill when working on Python projects.
Modern Toolchain
- •Python 3.13+ with strict type hints and modern syntax (
typestatements,match/case) - •uv for package management, virtual environments, and lockfiles
- •ruff for linting and formatting (replaces flake8, isort, black) -- configure with strict rules
- •basedpyright (preferred) or mypy for static type checking in strict mode
- •pytest with coverage, hypothesis for property-based testing
- •pre-commit hooks for automated quality gates (ruff, pyright, pytest)
Type Safety
Principles
- •Type-hint every function signature, including return types
- •Use
TypedDictfor structured dicts,dataclassor PydanticBaseModelover raw dicts - •Prefer
Literal["a", "b"]overstrfor known value sets - •Use
Protocolfor structural subtyping (duck-typing with type safety) - •Use
TypeVarandGenericfor reusable typed containers - •
from __future__ import annotationsfor forward references
Common Patterns
python
from dataclasses import dataclass, field
from typing import Protocol, TypeVar
# Immutable config with validation
@dataclass(frozen=True, slots=True)
class AppConfig:
host: str
port: int = 8080
debug: bool = False
def __post_init__(self) -> None:
if not 1 <= self.port <= 65535:
raise ValueError(f"Invalid port: {self.port}")
# Protocol for duck-typing with type safety
class Serializable(Protocol):
def to_dict(self) -> dict[str, object]: ...
# Pydantic for external data validation
from pydantic import BaseModel, Field, ConfigDict
class UserCreate(BaseModel):
model_config = ConfigDict(str_strip_whitespace=True, strict=True)
name: str = Field(min_length=1, max_length=100)
email: str = Field(pattern=r'^[\w.-]+@[\w.-]+\.\w+$')
Production Stack
FastAPI
- •Async endpoints for I/O-bound operations
- •Pydantic models for request/response validation
- •Dependency injection for DB sessions, auth, config
- •
lifespancontext manager for startup/shutdown (not deprecatedon_event) - •Exception handlers for consistent error responses
- •OpenAPI schema generation with proper descriptions
SQLAlchemy 2.0+
- •
mapped_column()with type annotations (not legacyColumn()) - •Async sessions with
async_sessionmaker - •Alembic for migrations -- one concern per migration, test downgrades
- •Eager loading (
selectinload,joinedload) to prevent N+1 queries - •
expire_on_commit=Falsewhen returning objects after commit
Async Patterns
python
# Proper async context management
from contextlib import asynccontextmanager
from collections.abc import AsyncGenerator
@asynccontextmanager
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session_factory() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
# Concurrency with semaphore control
async def fetch_all(urls: list[str], max_concurrent: int = 10) -> list[Response]:
semaphore = asyncio.Semaphore(max_concurrent)
async def fetch(url: str) -> Response:
async with semaphore:
return await client.get(url)
return await asyncio.gather(*(fetch(u) for u in urls))
Observability
- •structlog for structured JSON logging with bound context
- •Sentry for error tracking with proper DSN and environment config
- •Correlation IDs propagated through request lifecycle
- •Prometheus metrics via
prometheus-clientorstarlette-prometheus
python
import structlog
logger = structlog.get_logger()
# Bind context once, use everywhere in the request
log = logger.bind(request_id=request_id, user_id=user.id)
log.info("processing_order", order_id=order.id, total=order.total)
Code Standards
Naming & Style
- •snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants
- •Descriptive names over abbreviations (
user_repositorynotusr_repo) - •Private methods with single underscore prefix (
_validate_input) - •Module-level
__all__to control public API surface
Error Handling
python
# Custom exception hierarchy
class AppError(Exception):
"""Base application error."""
class NotFoundError(AppError):
"""Resource not found."""
def __init__(self, resource: str, id: str) -> None:
super().__init__(f"{resource} {id} not found")
self.resource = resource
self.id = id
# Never catch bare Exception unless re-raising
try:
result = await process(data)
except NotFoundError:
return Response(status_code=404)
except ValidationError as e:
logger.warning("validation_failed", errors=e.errors())
return Response(status_code=422)
Security
- •Parameterized queries always -- never f-string SQL
- •Input validation via Pydantic before any processing
- •Secrets via environment variables, never hardcoded
- •
banditfor static security analysis - •
secretsmodule for token generation, notrandom
Quality Gates
Before code is production-ready:
- •
ruff check-- zero violations - •
basedpyright --strict-- zero type errors - •
pytest --cov-- 90%+ coverage target - •
bandit -r src/-- zero high-severity issues - •All public APIs have docstrings
Project Structure
code
src/
myapp/
__init__.py
main.py # FastAPI app factory, lifespan
config.py # Settings via pydantic-settings
models/ # SQLAlchemy models
schemas/ # Pydantic request/response models
routes/ # API route handlers
services/ # Business logic layer
repositories/ # Data access layer
exceptions.py # Custom exception hierarchy
tests/
conftest.py # Shared fixtures
test_routes/
test_services/
pyproject.toml # Single config file (ruff, pytest, pyright)
pyproject.toml Essentials
toml
[tool.ruff] line-length = 88 target-version = "py313" select = ["E", "W", "F", "I", "B", "C4", "UP", "ARG", "SIM", "TCH", "PTH", "PERF", "RUF"] [tool.basedpyright] typeCheckingMode = "strict" pythonVersion = "3.13" [tool.pytest.ini_options] addopts = "-ra -q --strict-markers --strict-config" asyncio_mode = "auto"
When to Use This Skill
- •Writing or reviewing Python code
- •Setting up Python project structure and tooling
- •Building FastAPI services or async applications
- •Configuring linting, type checking, or testing pipelines
- •Debugging Python-specific issues (async, imports, type errors)