Claude Code with Python: The Complete Workflow
Why Python projects benefit from dedicated Claude Code configuration
Claude Code is not Python-naive. It knows pip, Poetry, pytest, virtualenv, and every major framework. The problem is that without project-specific configuration, it uses that knowledge generically. It generates code that runs in isolation but ignores your project's import conventions, skips your test patterns, and produces virtual environment commands that assume a layout you do not have.
The fix is a Python-specific CLAUDE.md that tells Claude Code exactly how your project is structured. This guide covers that configuration layer, the pytest integration that catches bugs automatically, and the refactoring loops that save hours on large codebases. If you are new to Claude Code, start with what is Claude Code before continuing here.
The Python CLAUDE.md
The single highest-leverage configuration for any Python project is a CLAUDE.md that answers four questions: how is the environment managed, how are imports structured, how are tests run, and what is the type posture?
# Python project rules
## Environment
- Virtual environment: `source .venv/bin/activate` (venv in .venv/, not env/ or venv/)
- Package manager: uv (not pip directly)
- Install: `uv pip install -r requirements.txt`
- Python version: 3.12 (see .python-version)
## Imports
- Absolute imports only. Never relative imports outside the src/ tree.
- Internal packages under src/{package_name}/
- src/ added to sys.path via pyproject.toml [tool.pytest.ini_options]
## Tests
- Run: `pytest` from project root
- Coverage: `pytest --cov=src --cov-report=term-missing`
- New tests go in tests/ mirroring src/ structure
- Fixtures defined in tests/conftest.py
## Type checking
- `mypy src/` before committing
- No implicit Any. Annotate all public functions.
- Type stubs for external packages in typings/
## Hard rules
- Never modify .python-version
- Never commit with failing tests
- Never add a bare except: clause
This file loads every session. Claude reads it before writing a single line. The result is code that fits your project rather than code that needs retrofitting.
Virtual environment and dependency management
The most common breakage in Claude Code with Python is environment confusion. Claude generates a command referencing pip when you use uv, or activates the wrong directory, or installs into the global Python installation.
Prevent this with two explicit lines in CLAUDE.md:
- Use `uv pip install`, never `pip install` directly
- Activate with `source .venv/bin/activate` before any pip or python command
If your project uses Poetry instead of uv:
- Use `poetry run pytest` instead of activating the environment directly
- Dependency changes: `poetry add <package>`, never manual requirements.txt edits
Claude Code follows these instructions precisely once they are written. The virtualenv confusion disappears.
Pytest integration that catches bugs inside Claude's loop
The most productive Python workflow with Claude Code runs tests automatically after every change. You do not review code and then run tests. Claude runs them as part of its own loop.
Add this to your CLAUDE.md:
## After every code change
1. Run `pytest tests/unit/` for fast feedback
2. If tests pass, run `pytest` for the full suite
3. If tests fail, fix the failure before considering the task complete
4. Do not ask for review until `pytest --cov=src` passes at >80% coverage
This is the difference between Claude Code as a code generator (produces something that looks right) and Claude Code as a development partner (produces something that is right). The feedback loop is tight enough that most bugs surface and get fixed before you see the output.
Writing tests that Claude can maintain
The other half of this is writing tests in a style Claude understands well. Pytest fixtures work better than unittest setUp/tearDown. Parametrize is well-supported. Mocking with unittest.mock.patch works reliably.
What does not work well: deeply nested class-based test hierarchies that Claude has to reconstruct from context every session. Keep tests flat. One class per module under test. Fixtures in conftest.py, not scattered across test files.
Handling large codebases and multi-file refactoring
Python projects accumulate technical debt fast. Changing a base class propagates through dozens of subclasses. Renaming a module requires updates across imports, tests, and sometimes config files. Claude Code handles this well, but only if you tell it the scope upfront.
The pattern that works:
Start with a plan session: "We are renaming
UserServicetoUserRepositoryacross the codebase. Before making any changes, list every file that imports or instantiates UserService."Review the scope before Claude touches anything.
Approve the plan, then let Claude execute.
Run
pytestandmypy src/after the full refactor.
This is the multi-file editing workflow applied to Python. The failure mode is skipping step one and letting Claude start editing immediately. It will miss imports. The plan pass costs two minutes and saves twenty.
Type annotation workflows
Python's type system is opt-in, which means Claude will happily generate code without annotations unless you ask. And "ask" in this context means CLAUDE.md rules, not per-prompt requests.
With mypy in your CLAUDE.md configuration, Claude Code annotates as it goes. But mypy catches more than missing annotations. It catches:
- Functions returning the wrong type for their annotation
- Dictionary accesses on
Optional[dict]without None-checks - Missing return branches in Union types
Configure mypy to run automatically:
## Type checking
After modifying any .py file in src/, run `mypy src/` and fix all
errors before the task is complete. Use --strict for new modules,
--ignore-missing-imports only as a last resort.
The goal is a clean mypy run in your CI pipeline. Claude Code will get you most of the way there if the rules are explicit.
Debugging workflows
Python debugging with Claude Code works best when you provide error output directly. Not "it's crashing" but the full traceback. Claude Code reads tracebacks the way a senior developer does, identifying the root cause rather than the symptom.
For interactive debugging, the pdb workflow:
## Debugging
When debugging, prefer adding `breakpoint()` to the exact line
of failure and running `pytest -s tests/path_to_test.py::test_name`
rather than adding print statements. Remove breakpoints before
completing any task.
This gives Claude a clear pattern to follow when you ask it to debug. It knows to use breakpoints, run the targeted test, and clean up when done.
For async code (asyncio, aiohttp, FastAPI), add:
## Async debugging
Use `asyncio.run(main())` patterns in debug scripts.
For FastAPI routes, use `httpx.AsyncClient` in tests rather than
the standard requests library.
FastAPI and Django configuration
Two frameworks dominate Python backend development in 2026. Both benefit from explicit Claude Code configuration beyond generic Python rules.
For FastAPI projects:
## FastAPI rules
- Route handlers use async def always
- Pydantic models in models/ directory
- Dependency injection via Depends(), not global state
- Tests use `httpx.AsyncClient(app=app, base_url="http://test")` pattern
- OpenAPI schema must remain valid after every change
For Django projects, the key rules are around management commands, migration handling, and ORM patterns. Our Claude Code Django guide covers that in full.
The weekly refactoring session
One workflow pattern that compounds over time: a weekly refactoring session where Claude Code cleans up the debt accumulated during feature development.
The prompt that works:
"Scan src/ and identify: functions longer than 40 lines, modules with cyclomatic complexity above 10, and any TODO comments older than 7 days. List them with line numbers. Then we will work through them in order."
Claude Code reads the entire src/ tree, produces the inventory, and you work through it methodically. On a project with 20,000 lines of Python, this session takes 90 minutes and keeps the codebase manageable. Without it, complexity accumulates until the velocity cost becomes noticeable.
What Python developers get wrong first
Three mistakes come up consistently when Python developers start using Claude Code:
Not specifying the Python version. Claude may generate code using syntax from a version you are not running. .python-version in the repo root plus an explicit note in CLAUDE.md prevents this.
Letting Claude manage requirements files directly. If you use uv or Poetry, Claude should not touch requirements.txt or pyproject.toml manually unless you instruct it to. These files have lock semantics that manual edits can break. Specify: "Dependency changes require explicit approval before adding to pyproject.toml."
Missing conftest.py. Without a conftest.py that defines shared fixtures, Claude generates standalone test files with duplicated setup. One well-structured conftest.py cuts test file boilerplate by half and keeps Claude's output consistent.
Getting more from your Python workflow
The configuration in this guide produces a Claude Code setup where Python-specific tools run automatically, tests gate every change, and the codebase stays typed. The underlying principle is the same as any Claude Code best practices guide: Claude Code's quality is a direct function of how much information you give it about your project.
Start with the CLAUDE.md template above. Add pytest enforcement. Add mypy rules. Each layer reduces the corrections you need to make and moves Claude Code from a code-generator to a genuine development partner on your Python project.
For the setup and authentication steps before any of this applies, the Claude Code setup guide covers installation from scratch.
More like this
Ready to upgrade your Claude Code setup?
Get Claudify