Python com Claude Code: guia com uv, pytest, Ruff e FastAPI
Crie um projeto Python verificável com Claude Code, uv, pyproject.toml, pytest, Ruff, FastAPI e iteração segura.
O primeiro desafio ao usar Claude Code com Python não é gerar um arquivo. O desafio é saber se o projeto está realmente pronto para evoluir: ambiente reproduzível, imports funcionando, testes executando, formatação consistente e comandos claros para provar cada mudança.
Este guia cria uma base pequena para iniciantes. Vamos usar uv ou venv, concentrar regras em pyproject.toml, implementar uma API mínima com FastAPI, adicionar uma CLI opcional, escrever testes com pytest e revisar com ruff. O objetivo é usar Claude Code para iterações seguras, não para aceitar um backend grande sem entender.
Use documentação oficial como referência: Claude Code, Python Packaging para escrever pyproject.toml, instalação do uv, pytest, Ruff e os primeiros passos do FastAPI.
Defina um alvo pequeno
Não peça autenticação, banco de dados, Docker e CI no primeiro prompt. Para aprender, o primeiro alvo precisa ser verificável.
uv run pytestpassauv run ruff check .euv run ruff format .executam- FastAPI cria e lista uma tarefa
- A CLI adiciona uma tarefa pelo terminal
- Claude Code informa os comandos executados
flowchart LR
A["Brief da tarefa"] --> B["uv ou venv"]
B --> C["pyproject.toml"]
C --> D["Implementação em src"]
D --> E["pytest"]
E --> F["ruff"]
F --> G["Pequena iteração com Claude Code"]
O brief é a ordem de trabalho do agente. Ele deve conter objetivo, arquivos permitidos, versão do Python e comandos de verificação. Para regras permanentes, use também boas práticas de CLAUDE.md. Para crescer a API, veja desenvolvimento de API com Claude Code e estratégias de testes.
Prompt inicial
Este prompt dá limites claros.
Adicione a este repositório uma pequena API de tarefas para Python 3.12.
Condições:
- Use uv para dependências e concentre a configuração em pyproject.toml.
- Coloque o código em src/task_api/ e os testes em tests/.
- Implemente POST /tasks e GET /tasks com FastAPI.
- Escreva testes pytest para o fluxo feliz e um caso 404.
- ruff check e ruff format devem passar.
- Antes de editar, mostre o plano. Depois, informe os comandos executados.
Arquivos permitidos:
- pyproject.toml
- src/task_api/**
- tests/**
Assim Claude Code trabalha com um contrato. Se ele mexer em arquivos fora do escopo ou não rodar testes, o problema fica fácil de detectar.
Ambiente com uv ou venv
Para projetos novos, uv é uma boa escolha por ser rápido e simples. Em máquinas corporativas sem permissão para instalar ferramentas, venv resolve. O importante é escolher uma rota e documentar.
macOS ou 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
Alternativa com 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
Centralize o pyproject.toml
Um iniciante se perde quando dependências, testes e lint ficam espalhados. Este arquivo reúne o essencial.
[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 e CLI mínimos
Salve em src/task_api/main.py. O armazenamento é em memória, então não é produção. Ele serve para aprender rotas, validação e erros antes do banco.
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
Para CLI, crie 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"
Proteja com pytest e Ruff
Crie tests/test_main.py e mantenha os mesmos comandos em toda mudança.
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 .
Casos de uso reais
O primeiro caso é uma API de aprendizado com rotas, Pydantic, OpenAPI, testes e formatação. O segundo é uma CLI para automação de negócio, como limpar CSV, renomear arquivos ou montar relatórios. O terceiro é adicionar testes a scripts legados antes de refatorar. O quarto é criar uma base de treinamento para que todos no time comecem do mesmo ponto.
Para continuar, use produtos Claude Code quando os prompts se repetirem, ou treinamento e consultoria quando houver risco de equipe, revisão ou produção.
Erros comuns
Não deixe o gerenciador de pacotes implícito. Misturar pip, poetry, uv e requirements.txt cria confusão. Não adicione banco e JWT antes da versão em memória funcionar. Revise diffs do Ruff. Garanta pythonpath = ["src"] ou instalação correta do pacote. Nunca cole segredos, dados de clientes ou URLs de produção no prompt.
Resultado verificado
Nesta atualização, segui a ordem que Masa usa em materiais para iniciantes: ambiente, pyproject.toml, FastAPI pequeno, testes e Ruff. O resultado é que cada falha fica localizável. Claude Code se torna mais útil quando o projeto tem comandos claros do que quando gera uma aplicação grande sem prova.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Workflow Obsidian para CLAUDE.md com Claude Code
Transforme notas de trabalho do Obsidian em notas operacionais CLAUDE.md para preservar contexto.
Claude Code Revenue CTA Routing: artigos para PDF, Gumroad e consultoria
Um fluxo com Claude Code para levar leitores ao PDF grátis, Gumroad ou consultoria conforme intenção.
Regras de handoff para equipes com Claude Code: evidências, permissões, rollback e receita
Formato prático para entregar trabalho do Claude Code com prova, permissões, rollback, PDF grátis, Gumroad e consultoria.