Python mit Claude Code: Praxisguide für uv, pytest, Ruff und FastAPI
Baue ein prüfbares Python-Projekt mit Claude Code, uv, pyproject.toml, pytest, Ruff, FastAPI und sicherer Iteration.
Bei Python mit Claude Code ist der erste generierte Code selten das eigentliche Problem. Schwieriger ist die Frage, ob das Projekt wirklich gesund ist: Ist die Umgebung reproduzierbar, funktionieren die Imports, laufen Tests, ist das Format konsistent und kann die nächste Änderung sauber geprüft werden?
Dieser Guide zeigt einen kleinen, anfängerfreundlichen Ablauf. Wir verwenden uv oder das eingebaute venv, sammeln Projektregeln in pyproject.toml, bauen eine minimale FastAPI-App, ergänzen optional eine CLI, schreiben Tests mit pytest und prüfen den Code mit ruff. Claude Code arbeitet dabei in einem klaren Rahmen statt eine große Architektur zu erraten.
Nutze primäre Dokumentation: Claude Code, Python Packaging zum Schreiben von pyproject.toml, uv Installation, pytest Einstieg, Ruff und FastAPI First Steps.
Erst ein kleines Ziel definieren
Bitte Claude Code am Anfang nicht gleichzeitig um Authentifizierung, Datenbank, Docker, CI und Hintergrundjobs. Für den ersten Schritt reicht ein Ergebnis, das jeder prüfen kann.
uv run pytestläuft erfolgreichuv run ruff check .unduv run ruff format .laufen- FastAPI kann eine Aufgabe erstellen und auflisten
- Die CLI kann eine Aufgabe im Terminal hinzufügen
- Claude Code meldet die ausgeführten Befehle
flowchart LR
A["Arbeitsbrief"] --> B["uv oder venv"]
B --> C["pyproject.toml"]
C --> D["Implementierung in src"]
D --> E["pytest"]
E --> F["ruff"]
F --> G["Kleine Claude-Code-Iteration"]
Der Arbeitsbrief ist die Aufgabenbeschreibung für den Coding-Agenten. Er nennt Ziel, erlaubte Dateien, Python-Version und Prüfbefehle. Für dauerhafte Repository-Regeln lohnt sich zusätzlich CLAUDE.md Best Practices. Wenn die API größer wird, lies API-Entwicklung mit Claude Code und Teststrategien.
Der erste Prompt
Dieser Prompt ist bewusst konkret und begrenzt.
Füge diesem Repository eine kleine Task-Management-API für Python 3.12 hinzu.
Bedingungen:
- Nutze uv für Abhängigkeiten und sammle Einstellungen in pyproject.toml.
- Lege Code unter src/task_api/ und Tests unter tests/ ab.
- Implementiere POST /tasks und GET /tasks mit FastAPI.
- Schreibe pytest-Tests für den Erfolgsfall und einen 404-Fall.
- ruff check und ruff format müssen laufen.
- Zeige vor dem Editieren den Plan und berichte danach die ausgeführten Befehle.
Erlaubte Dateien:
- pyproject.toml
- src/task_api/**
- tests/**
So wird Claude Code zu einem Umsetzungspartner mit Nachweis, nicht nur zu einem Generator. Wenn die Änderung andere Ordner berührt oder keine Tests ausführt, ist der Fehler im Review sofort sichtbar.
Umgebung mit uv oder venv
Für neue Lernprojekte ist uv praktisch, weil es schnell ist und kurze Befehle bietet. Wenn auf einem Firmenrechner keine neuen Tools installiert werden dürfen, funktioniert venv genauso. Wichtig ist, die gewählte Methode nicht zu mischen.
macOS oder Linux:
mkdir task-api
cd task-api
uv init --app --python 3.12
uv add "fastapi[standard]"
uv add --dev pytest ruff
mkdir -p src/task_api tests
touch src/task_api/__init__.py
Windows PowerShell:
mkdir task-api
cd task-api
uv init --app --python 3.12
uv add "fastapi[standard]"
uv add --dev pytest ruff
New-Item -ItemType Directory -Force src/task_api, tests
New-Item -ItemType File -Force src/task_api/__init__.py
Fallback mit venv:
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "fastapi[standard]" pytest ruff
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install "fastapi[standard]" pytest ruff
pyproject.toml zentral halten
Für Anfänger ist es verwirrend, wenn Abhängigkeiten, Testpfade und Lint-Regeln in mehreren Dateien liegen. Diese Version bündelt die wichtigsten Regeln.
[project]
name = "task-api"
version = "0.1.0"
description = "Small FastAPI and CLI sample for Claude Code practice"
requires-python = ">=3.11"
dependencies = [
"fastapi[standard]>=0.115.0",
]
[project.scripts]
task-api = "task_api.cli:main"
[dependency-groups]
dev = [
"pytest>=8.0.0",
"ruff>=0.8.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/task_api"]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "B", "UP"]
FastAPI und CLI implementieren
Lege diesen Code in src/task_api/main.py ab. Die Speicherung im Speicher ist kein Produktionsdesign, aber ideal zum Lernen von Routing, Validierung, Antwortmodellen und Fehlern.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
app = FastAPI(title="Task API")
class TaskCreate(BaseModel):
title: str = Field(min_length=1, max_length=80)
class Task(BaseModel):
id: int
title: str
done: bool = False
_tasks: dict[int, Task] = {}
_next_id = 1
@app.post("/tasks", response_model=Task, status_code=201)
def create_task(payload: TaskCreate) -> Task:
global _next_id
task = Task(id=_next_id, title=payload.title)
_tasks[task.id] = task
_next_id += 1
return task
@app.get("/tasks", response_model=list[Task])
def list_tasks() -> list[Task]:
return list(_tasks.values())
@app.patch("/tasks/{task_id}/done", response_model=Task)
def mark_done(task_id: int) -> Task:
task = _tasks.get(task_id)
if task is None:
raise HTTPException(status_code=404, detail="Task not found")
updated = task.model_copy(update={"done": True})
_tasks[task_id] = updated
return updated
uv run fastapi dev src/task_api/main.py
Für eine CLI erstelle src/task_api/cli.py.
import argparse
import json
from pathlib import Path
DB_PATH = Path("tasks.json")
def load_tasks() -> list[dict[str, object]]:
if not DB_PATH.exists():
return []
return json.loads(DB_PATH.read_text(encoding="utf-8"))
def save_tasks(tasks: list[dict[str, object]]) -> None:
DB_PATH.write_text(json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8")
def add_task(title: str) -> dict[str, object]:
tasks = load_tasks()
task = {"id": len(tasks) + 1, "title": title, "done": False}
tasks.append(task)
save_tasks(tasks)
return task
def main() -> None:
parser = argparse.ArgumentParser(description="Task CLI")
subparsers = parser.add_subparsers(dest="command", required=True)
add_parser = subparsers.add_parser("add")
add_parser.add_argument("title")
args = parser.parse_args()
if args.command == "add":
task = add_task(args.title)
print(f"Added #{task['id']}: {task['title']}")
if __name__ == "__main__":
main()
uv run task-api add "write pytest"
Mit pytest und Ruff absichern
Erstelle tests/test_main.py und nutze die gleichen Prüfungen nach jeder Änderung.
import pytest
from fastapi.testclient import TestClient
from task_api import main
from task_api.main import app
@pytest.fixture(autouse=True)
def clean_tasks() -> None:
main._tasks.clear()
main._next_id = 1
def test_create_and_list_tasks() -> None:
client = TestClient(app)
response = client.post("/tasks", json={"title": "Write pytest"})
assert response.status_code == 201
assert response.json()["title"] == "Write pytest"
list_response = client.get("/tasks")
assert list_response.status_code == 200
assert len(list_response.json()) == 1
def test_mark_done_returns_404_for_missing_task() -> None:
client = TestClient(app)
response = client.patch("/tasks/999/done")
assert response.status_code == 404
assert response.json()["detail"] == "Task not found"
uv run pytest
uv run ruff check .
uv run ruff format .
Praktische Anwendungsfälle
Erstens eignet sich der Ablauf für eine Lern-API: Routing, Pydantic, OpenAPI, Tests und Formatierung bleiben sichtbar. Zweitens passt er zu kleinen Business-CLIs, etwa CSV-Bereinigung, Dateiumbenennung oder Wochenreports. Drittens hilft er bei Legacy-Python, indem Claude Code zuerst bestehendes Verhalten mit Tests fixiert. Viertens ist er eine gute Basis für Team-Training.
Für wiederkehrende Briefs und Review-Muster passen Claude Code Produkte. Für Teams mit echten Repositories, Onboarding und Review-Regeln ist Training und Beratung der bessere nächste Schritt.
Typische Fehler
Der Paketmanager darf nicht offen bleiben, sonst mischen sich pip, poetry, uv und requirements.txt. Baue Datenbank und JWT nicht vor dem lauffähigen In-Memory-Beispiel ein. Prüfe Ruff-Diffs vor der Übernahme. Achte bei src-Layout auf pythonpath = ["src"] oder korrekte Paketinstallation. Und füge nie echte Secrets, Kundendaten oder Produktions-URLs in den Prompt ein.
Verifiziertes Ergebnis
Für diese Überarbeitung habe ich die Reihenfolge genutzt, die Masa für Python-Einsteigerunterlagen verwendet: Umgebung fixieren, pyproject.toml zentralisieren, FastAPI klein halten, Tests vor neuen Funktionen schreiben und Ruff täglich ausführen. Das macht Fehler lokalisierbar und Claude Code nützlich für Lernen, Review und Beratung.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.