Modern Python Development
Overview
This skill provides modern Python development guidance for 2025, specializing in:
- •LLM Applications: Structured outputs with Pydantic/Instructor
- •API Development: FastAPI with type safety and dependency injection
- •Clean Architecture: Thin, pragmatic application of hexagonal patterns
- •Modern Tooling: uv, Ruff, mypy, pytest-watch
Designed for TypeScript developers who value simplicity and type safety.
Core Philosophy
Apply these principles to all Python development:
- •KISS (Keep It Simple): Simple is better than complex
- •YAGNI (You Aren't Gonna Need It): Implement only what's needed now
- •Boy Scout Rule: Leave code cleaner than you found it
- •Reader-Friendly Code: The next engineer should understand immediately
When to Use This Skill
Claude should automatically use this skill when:
- •Setting up new Python projects
- •Designing architecture for LLM applications
- •Making decisions about project structure
- •Choosing between architectural patterns
- •Configuring development tooling (uv, Ruff, mypy)
- •Implementing FastAPI endpoints
- •Structuring tests (unit/integration/functional)
- •Advising TypeScript developers on Python equivalents
Architecture Decision Framework
Step 1: Assess Complexity
Choose structure based on project complexity:
| Complexity | Structure | When to Use |
|---|---|---|
| Script/PoC | Flat (single file) | Quick experiments, one-off scripts |
| Small App | 2-layer (domain + adapters) | MVPs, simple APIs |
| Production | 3-layer (domain + ports + adapters) | Multiple integrations, complex business logic |
Step 2: Apply Thin Clean Architecture
Only add layers when complexity warrants it.
domain/ → Pure business logic (Pydantic models, services) ports/ → Interfaces (Protocol classes) - add when needed adapters/ → External integrations (API, DB, LLM clients)
Key principle: Start simple, refactor when pain points emerge.
Step 3: Choose Project Structure
- •Single Package: Use for most projects (PoC, small-medium apps)
- •Monorepo (uv workspaces): Use when sharing code across multiple services
See REFERENCE.md for detailed structures.
Development Workflow
Initial Setup
# 1. Initialize project uv init my-project && cd my-project # 2. Add dependencies uv add fastapi pydantic uvicorn uv add --dev pytest pytest-watch ruff mypy # 3. Configure tools # See REFERENCE.md for pyproject.toml configs
TDD Workflow
# Terminal 1: Watch tests (auto-run on changes) uv run ptw -- tests/unit -v # Terminal 2: Write code # Follow Red -> Green -> Refactor cycle
Quality Checks
uv run ruff check --fix . # Lint & auto-fix uv run mypy src/ # Type check uv run pytest --cov=src # Test with coverage
LLM Application Patterns
Type-Safe Structured Outputs
Always use Pydantic for LLM outputs to ensure type safety:
from pydantic import BaseModel, Field
class ExtractedInfo(BaseModel):
summary: str = Field(description="Brief summary")
key_points: list[str]
sentiment: Literal["positive", "neutral", "negative"]
Use Instructor for type-safe LLM calls:
import instructor
from openai import OpenAI
client = instructor.from_openai(OpenAI())
response = client.chat.completions.create(
model="gpt-4o",
response_model=ExtractedInfo,
messages=[{"role": "user", "content": text}]
)
# response is typed as ExtractedInfo ✓
See EXAMPLES.md for more patterns.
FastAPI Best Practices
Dependency Injection Pattern
from fastapi import FastAPI, Depends
def get_service() -> UserService:
# Initialize dependencies here
return UserService(repo=get_repo())
@app.post("/users")
async def create_user(
request: CreateUserRequest,
service: UserService = Depends(get_service)
):
return service.create(request)
See EXAMPLES.md for complete examples.
Testing Strategy
3-Layer Test Structure
tests/ ├── unit/ # Fast, isolated, no I/O ├── integration/ # With real dependencies (DB, cache) └── functional/ # E2E API tests
Coverage targets:
- •Unit: 80%+ (business logic)
- •Integration: Key flows only
- •Functional: Critical user journeys
See EXAMPLES.md for test code.
Do's and Don'ts
✅ Do
- •Use type hints everywhere (
-> None,list[str],dict[str, Any]) - •Prefer
ProtocoloverABCfor interfaces - •Use
pydantic.BaseModelfor data classes with validation - •Run
ruff check --fixbefore commits - •Keep functions small and focused
❌ Don't
- •Over-engineer with unnecessary abstraction layers
- •Use
Anytype unless absolutely necessary - •Skip type hints "for now"
- •Create classes when functions suffice
- •Add dependencies without clear need
TypeScript Developer Quick Reference
| TypeScript | Python Equivalent |
|---|---|
interface | Protocol or BaseModel |
type | TypeAlias or Literal |
zod | pydantic |
npm/pnpm/yarn | uv |
eslint + prettier | ruff |
jest/vitest | pytest |
express/fastify | fastapi |
NestJS DI | FastAPI Depends |
See EXAMPLES.md for detailed mapping.
Output Guidelines
When providing guidance:
- •Explain the "why" - Rationale behind recommendations
- •Show concrete examples - Runnable code snippets
- •Suggest next steps - What to implement/consider next
- •Flag complexity decisions - When to add vs skip abstraction
Always prioritize working code over perfect architecture.
References
- •REFERENCE.md - Tool configurations, project structures, commands
- •EXAMPLES.md - Code examples, patterns, TypeScript mapping
Checklist for New Projects
- • Project initialized with
uv init - • Dependencies added via
uv add - •
pyproject.tomlconfigured (Ruff, mypy, pytest) - • Project structure matches complexity level
- • Type hints added to all functions
- • Tests written (at least unit tests)
- • TDD workflow established (
pytest-watch) - • Pre-commit hooks considered (optional)