Python Development
Comprehensive guide for modern Python 3.12+ development with FastAPI ecosystem.
When to Use This Skill
- Starting or configuring Python projects
- Building REST APIs with FastAPI
- Defining data models with Pydantic
- Implementing async/await patterns
- Adding type hints and mypy configuration
- Writing tests with pytest
- Working with databases (SQLAlchemy 2.0)
- Building data pipelines with Polars
- Integrating external APIs
- Deploying to production with Docker
Stack Overview
| Layer | Default | Alternatives |
|---|---|---|
| Runtime | Python 3.12+ | - |
| Package Manager | uv | rye, poetry |
| Linter/Formatter | ruff | black + flake8 |
| Type Checker | mypy | pyright |
| Web Framework | FastAPI | Flask, Django |
| Validation | Pydantic v2 | - |
| ORM | SQLAlchemy 2.0 | - |
| Data Processing | Polars | Pandas |
| HTTP Client | httpx | aiohttp |
| Testing | pytest | - |
| Containerization | Docker | - |
Core Philosophy
Follows foundations principles. Python-specific emphasis:
- Async by default — non-blocking I/O for web services
- Strict typing — catch errors at development time with mypy
- Pydantic everywhere — validate at trust boundaries
- 12-factor methodology — environment-based configuration
Quick Reference
Project Setup with uv
uv init my-project --python 3.12
uv add fastapi uvicorn pydantic-settings
uv add --dev pytest ruff mypy
uv run pytest
pyproject.toml Essentials
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
[tool.ruff]
target-version = "py312"
select = ["E", "F", "I", "N", "W", "UP"]
[tool.mypy]
python_version = "3.12"
strict = true
FastAPI Endpoint
from fastapi import FastAPI, Depends, HTTPException, status
from pydantic import BaseModel, EmailStr, Field
app = FastAPI()
class UserCreate(BaseModel):
email: EmailStr
username: str = Field(..., min_length=3, max_length=50)
class UserResponse(BaseModel):
id: int
email: EmailStr
username: str
model_config = {"from_attributes": True}
@app.post("/users", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate, db: AsyncSession = Depends(get_db)):
db_user = User(**user.model_dump())
db.add(db_user)
await db.commit()
await db.refresh(db_user)
return db_user
Pydantic Model with Validation
from pydantic import BaseModel, Field, field_validator
class UserRegistration(BaseModel):
email: EmailStr
password: str = Field(..., min_length=8)
@field_validator("password")
@classmethod
def password_strength(cls, v: str) -> str:
if not any(c.isupper() for c in v):
raise ValueError("Must contain uppercase")
return v
Async Database Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
async def get_user(session: AsyncSession, user_id: int) -> User | None:
result = await session.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
pytest Test
@pytest.mark.asyncio
async def test_create_user(client: AsyncClient):
response = await client.post("/users", json={"email": "test@example.com", "username": "test"})
assert response.status_code == 201
assert response.json()["email"] == "test@example.com"
Topics
| Topic | Use For |
|---|---|
| Core | Project setup, pyproject.toml, modern Python features |
| FastAPI | REST APIs, routing, dependency injection, middleware |
| Pydantic | Data models, validation, settings management |
| Async | async/await, TaskGroup, context managers |
| Types | Type hints, mypy, Protocol, generics |
| Testing | pytest, fixtures, mocking, async tests |
| Database | SQLAlchemy 2.0, Alembic migrations, transactions |
| Data | Polars, ETL pipelines, schema validation |
| API Clients | httpx, retries, rate limiting, error handling |
| Deployment | Docker, logging, OpenTelemetry, health checks |
| Debugging | pdb, structlog, pytest debugging, remote debugging |
Critical Rules
Always
- Use
async deffor I/O-bound operations - Use Pydantic models for external input validation
- Use
pathlib.Pathfor file operations - Run mypy in CI/CD pipeline
Never
- Block the event loop with sync I/O in async code
- Use mutable default arguments (
def foo(items=[])) - Skip validation on external input
- Hardcode configuration values (use pydantic-settings)
