Use Cases (Actualizado: 2/6/2026)

Python con Claude Code: guía práctica con uv, pytest, Ruff y FastAPI

Crea un proyecto Python real con Claude Code: uv, pyproject.toml, pytest, Ruff, FastAPI y una iteración segura.

Python con Claude Code: guía práctica con uv, pytest, Ruff y FastAPI

El primer problema al usar Claude Code con Python no suele ser generar código. El problema real aparece después: ¿el entorno es reproducible?, ¿los imports funcionan?, ¿los tests se ejecutan?, ¿el formateo es consistente?, ¿la siguiente modificación se puede revisar sin miedo?

Esta guía propone un flujo pequeño y verificable para principiantes. Usaremos uv o venv, pondremos la configuración en pyproject.toml, crearemos una API mínima con FastAPI, añadiremos una CLI opcional, escribiremos tests con pytest y revisaremos el código con ruff. Claude Code debe trabajar dentro de ese marco, no inventar toda la arquitectura en una sola respuesta.

Consulta siempre las fuentes oficiales: Claude Code, la guía de Python para escribir pyproject.toml, la instalación de uv, pytest, Ruff y los primeros pasos de FastAPI.

Define primero un resultado pequeño

No pidas autenticación, base de datos, Docker, CI y tareas en segundo plano en el primer prompt. Para aprender, conviene que cada fallo tenga una causa probable. El primer resultado puede ser simple:

  • uv run pytest pasa
  • uv run ruff check . y uv run ruff format . se ejecutan
  • FastAPI crea y lista una tarea
  • La CLI agrega una tarea desde la terminal
  • Claude Code informa qué comandos ejecutó
flowchart LR
  A["Brief de trabajo"] --> B["uv o venv"]
  B --> C["pyproject.toml"]
  C --> D["Implementación en src"]
  D --> E["pytest"]
  E --> F["ruff"]
  F --> G["Iteración pequeña con Claude Code"]

El brief es la orden de trabajo para el agente. Debe incluir objetivo, archivos permitidos, versión de Python y comandos de verificación. Para reglas persistentes del repositorio, combina este flujo con buenas prácticas de CLAUDE.md. Si el proyecto crece hacia una API real, revisa también desarrollo de API con Claude Code y estrategias de testing.

Prompt inicial para Claude Code

Este prompt es deliberadamente concreto. Reduce cambios fuera de alcance y obliga a reportar pruebas.

Añade a este repositorio una pequeña API de tareas para Python 3.12.

Condiciones:
- Usa uv para dependencias y centraliza la configuración en pyproject.toml.
- Coloca el código en src/task_api/ y los tests en tests/.
- Implementa POST /tasks y GET /tasks con FastAPI.
- Añade tests con pytest para el flujo correcto y un caso 404.
- ruff check y ruff format deben pasar.
- Antes de editar, muestra el plan. Después, informa los comandos ejecutados.

Archivos permitidos:
- pyproject.toml
- src/task_api/**
- tests/**

La diferencia entre este prompt y “hazme una app Python” es enorme. Claude Code sabe qué tocar, cómo demostrar que terminó y qué no debe modificar. Eso hace que la revisión humana sea posible incluso para alguien que todavía está aprendiendo Python.

Crea el entorno con uv o venv

Para proyectos nuevos, uv es una buena opción por velocidad y claridad. Si tu equipo no permite instalar herramientas nuevas, venv sigue siendo suficiente. Lo importante es no mezclar caminos.

macOS o 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 con 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

Centraliza pyproject.toml

Un proyecto pequeño no necesita cinco archivos de configuración. Este pyproject.toml contiene dependencias, script de consola, ruta de tests y reglas de Ruff.

[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"]

Con esta base puedes pedir a Claude Code que respete una sola fuente de verdad. Las discusiones sobre dependencias, imports y estilo quedan visibles en un archivo revisable.

Implementa FastAPI y una CLI mínima

Guarda este archivo como src/task_api/main.py. Usa memoria local, así que no es almacenamiento de producción. Justamente por eso sirve para aprender antes de añadir una base de datos.

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 una CLI, crea 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"

Protege la iteración con pytest y Ruff

Guarda los tests en tests/test_main.py. A partir de aquí, cada cambio de Claude Code debe volver a pasar por los mismos comandos.

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 reales

El primer caso es una API de aprendizaje. En un proyecto corto se ven rutas, validación, documentación OpenAPI, tests y formato. El segundo caso es una CLI de automatización: limpiar CSV, renombrar archivos exportados o preparar un informe semanal. El tercer caso es añadir tests a un script heredado antes de refactorizar. El cuarto caso es crear una plantilla de formación para que todo el equipo empiece con la misma estructura.

Estos casos también conectan con monetización sin forzar la venta. Un lector individual puede pasar a plantillas y productos de Claude Code. Un equipo que quiere usarlo en repositorios reales puede revisar formación y consultoría.

Errores frecuentes

No dejes abierto el gestor de paquetes. Si no lo dices, pueden mezclarse pip, poetry, uv y requirements.txt. No añadas base de datos y JWT antes de que la versión en memoria funcione. Revisa los cambios automáticos de Ruff. Configura bien pythonpath = ["src"] para evitar errores de import. Y nunca pegues secretos, datos de clientes ni URLs reales de producción en el prompt.

Resultado verificado

Para esta actualización seguí el orden que Masa usa en materiales para principiantes: entorno primero, pyproject.toml después, FastAPI pequeño, tests antes de nuevas funciones y Ruff como comando cotidiano. El resultado práctico es que cada fallo queda localizado: entorno, import, comportamiento de test o formato. Eso hace que Claude Code sea útil para aprender, revisar y preparar una formación real, no solo para generar código rápido.

#Claude Code #Python #uv #pytest #FastAPI
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.