Python has enough ways to do things that Claude will make choices based on what's most common in its training data, not what's right for your project. Old-style string formatting, different testing frameworks, varying import styles, type annotation inconsistency — all of these create drift.
Here's the CLAUDE.md setup that keeps Python projects consistent.
Core CLAUDE.md for a Python project
# Python project rules
## Environment
- Python 3.11+
- Virtual environment: .venv/ (do not reference system Python)
- Package manager: uv (not pip, not poetry)
- Run commands: uv run python, uv run pytest
## Code style
- Type annotations on all functions (parameters and return type)
- No untyped function signatures
- f-strings for string formatting (not .format() or %)
- dataclasses or Pydantic models for structured data (not plain dicts)
- Named arguments for any function call with more than 2 arguments
## Project structure
- Source code: src/[package_name]/
- Tests: tests/ (mirrors src/ structure)
- Config: pyproject.toml (not setup.py, not setup.cfg)
- One public interface per module via __all__
## Imports
- Absolute imports only (no relative imports)
- Import order: stdlib → third-party → local (enforced by ruff)
- No wildcard imports (from module import *)
## Error handling
- Custom exceptions in exceptions.py
- Never catch Exception silently — log and re-raise or handle specifically
- Context managers for resource management (not try/finally manually)
## Testing
- Framework: pytest
- Test files: test_*.py
- Use fixtures, not setUp/tearDown
- No unittest classes unless modifying existing unittest tests
## Rules
- Minimal footprint. Only modify files required for the task.
- Run tests after every change: uv run pytest tests/ -x
- Do not add print() debug statements to committed code
- Never claim work is done without showing test output
The sections that do the most work
Package manager specification — Without this, Claude will default to pip. If you're using uv or poetry, say so explicitly.
Type annotations — Claude will omit them if you don't require them. Requiring them consistently is worth it.
dataclasses/Pydantic vs dicts — Plain dicts for structured data are a Python habit that makes type checking harder. Specifying the preference keeps code consistent.
Testing framework — Claude knows both pytest and unittest. Specifying pytest and "no unittest classes" prevents test file drift.
Adding async context
If your project uses async:
## Async
- Framework: asyncio (not trio or curio)
- Use async/await consistently — no mixing with synchronous blocking calls
- Background tasks: [specify your approach — asyncio.create_task, Celery, etc.]
Full CLAUDE.md templates for Python, Django, FastAPI, and more: builtbyzac.com/claudemd-templates.html.
Top comments (0)