Explicación de pyproject.toml
pyproject.toml es el único archivo de configuración para proyectos modernos de Python. Contiene metadatos del paquete, dependencias, configuraciones de compilación y configuración de herramientas (ruff, pytest, mypy) en un solo archivo TOML.
Receta
Tarjeta de referencia rápida - lista para copiar y pegar.
[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = ["fastapi>=0.115"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 88
target-version = "py314"Cuándo usar esto:
- Al iniciar cualquier nueva biblioteca o aplicación de Python
- Al consolidar archivos
setup.cfg,setup.pyyruff.tomldispersos - Al configurar backends de compilación, linters y ejecutores de pruebas en un solo lugar
Ejemplo de trabajo
[project]
name = "invoice-api"
version = "0.1.0"
description = "Invoice management API"
readme = "README.md"
requires-python = ">=3.14"
license = "MIT"
authors = [{ name = "Ada Lovelace", email = "ada@example.com" }]
dependencies = [
"fastapi>=0.115",
"uvicorn[standard]>=0.34",
"pydantic>=2",
"sqlalchemy>=2.0",
]
[project.optional-dependencies]
dev = ["pytest>=8", "ruff>=0.9", "mypy>=1.14"]
[project.scripts]
invoice-api = "invoice_api.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/invoice_api"]
[tool.ruff]
line-length = 88
target-version = "py314"
[tool.ruff.lint]
select = ["E", "F", "I", "UP"]
[tool.pytest.ini_options]
testpaths = ["tests"]uv sync --group dev
uv run pytest
uv run ruff check .Lo que esto demuestra:
- Bloque
[project]de PEP 621 con metadatos, dependencias y puntos de entrada [build-system]indica a los instaladores qué backend compila las ruedas (wheels)- Las secciones
[tool.*]configuran ruff y pytest sin archivos de configuración separados [project.scripts]crea un comando CLI al instalar
Inmersión profunda
Cómo funciona
- PEP 518 introdujo
[build-system]- cada instalador lee esto primero - PEP 621 estandarizó los metadatos de
[project](reemplaza los argumentos desetup.py) - Las herramientas leen sus propias secciones
[tool.<name>]- no se necesita un registro central - Un archivo significa una única fuente de verdad para humanos y CI
Secciones clave
| Sección | Propósito |
|---|---|
[project] | Nombre, versión, dependencias, scripts, clasificadores |
[build-system] | Backend de compilación (hatchling, setuptools, poetry-core) |
[dependency-groups] | Grupos de desarrollo/documentación/pruebas (PEP 735) |
[tool.ruff] | Configuración del linter y formateador |
[tool.pytest.ini_options] | Descubrimiento de pruebas y marcadores |
[tool.mypy] | Configuración del verificador de tipos |
[tool.uv] | Configuración de índice y espacio de trabajo específica de uv |
Notas de Python
# Versión dinámica desde VCS (hatchling)
[project]
dynamic = ["version"]
[tool.hatch.version]
source = "vcs"# Espacio de trabajo Monorepo (uv)
[tool.uv.workspace]
members = ["packages/*"]Trampas comunes
- Falta
[build-system]:pip install .falla con errores opacos. Solución: incluir siemprerequiresybuild-backend. - Configuración duplicada en
setup.pyypyproject.toml: las herramientas leen archivos diferentes. Solución: migrar completamente apyproject.toml; eliminar los archivos heredados. - Descubrimiento incorrecto de paquetes: rueda vacía sin módulos. Solución: configurar
packagesen[tool.hatch.build.targets.wheel]o usar el diseñosrc/. requires-pythondemasiado restrictivo o demasiado amplio: las instalaciones fallan o se ejecutan en versiones no compatibles. Solución: igualar el límite inferior de tu matriz de CI.- Secretos en
[tool.*]: tokens confirmados en git. Solución: usar variables de entorno; mantener solo los valores predeterminados no secretos en TOML.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
setup.py solamente | Proyecto heredado sin tocar | Proyectos nuevos (patrón obsoleto) |
setup.cfg | Proyectos muy antiguos de setuptools | Necesitas configuración de herramientas más allá de los metadatos |
| Archivos de configuración divididos | La herramienta carece de soporte para pyproject.toml | La herramienta admite [tool.*] (preferir un solo archivo) |
Preguntas frecuentes
¿Todavía necesito setup.py?
No para la mayoría de los proyectos. pyproject.toml con un backend de compilación lo reemplaza por completo.
¿Dónde van las dependencias de desarrollo?
Usa [dependency-groups] (PEP 735) o [project.optional-dependencies] para grupos opcionales.
¿Puedo configurar varias herramientas en un solo archivo?
Sí. Cada sección [tool.*] es independiente. ruff, pytest, mypy y hatch coexisten.
¿Qué backend de compilación debo elegir?
hatchling para la mayoría de los paquetes. Usa setuptools para extensiones heredadas. Usa maturin para extensiones de Rust.
¿Cómo funcionan los puntos de entrada?
[project.scripts] mapea los nombres de CLI a funciones llamables módulo:función. Se instalan en el directorio bin/ del venv al ejecutar pip install.
¿Es pyproject.toml obligatorio para las aplicaciones?
No estrictamente, pero es el estándar para la declaración de dependencias, la configuración de herramientas y la reproducibilidad.
¿Cómo especifico solo Python 3.14?
requires-python = ">=3.14,<3.15" o ==3.14.* dependiendo de la rigurosidad con la que quieras fijar la versión.
¿Pueden entrar en conflicto las herramientas en el mismo archivo?
No. Cada sección [tool.*] es independiente. Solo los metadatos de [project] se comparten.
¿Cómo valido la sintaxis de pyproject.toml?
pip install validate-pyproject o deja que tu gestor de paquetes (uv sync) informe de los errores de análisis.
¿Debo confirmar pyproject.toml?
Siempre. Es el manifiesto del proyecto. Los archivos de bloqueo (uv.lock, poetry.lock) también deben confirmarse.
Relacionado
- uv - La Cadena de Herramientas Rápida - flujo de trabajo diario
- Resolución de Dependencias y Archivos de Bloqueo - fijación de versiones
- Instalaciones Editables y Paquetes Locales - diseño src
- Backends de Compilación - hatchling vs setuptools
Versiones de pila: Esta página se escribió para Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+ y uv 0.6+.