Un script suelto es un script; un paquete es código que otros (y tu futuro yo) pueden instalar, importar y versionar. Aquí está la estructura profesional moderna.
La estructura estándar
mi_proyecto/
├── pyproject.toml ← metadatos y dependencias
├── README.md
├── src/
│ └── utilidades/
│ ├── __init__.py ← marca el paquete (y exporta su API)
│ ├── textos.py
│ └── fechas.py
└── tests/
└── test_textos.py
El src-layout tiene una virtud poco apreciada: obliga a instalar tu paquete para importarlo. Tus tests prueban el paquete instalado real, no la carpeta local — evitas tests que pasan de mentira.
pyproject.toml: el manifiesto
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "utilidades"
version = "0.1.0"
description = "Funciones de utilidad para texto y fechas"
requires-python = ">=3.10"
dependencies = [
"requests>=2.31",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"mypy>=1.8",
]
[project]: nombre, versión, Python mínimo, dependencias de runtime[project.optional-dependencies]: extras comodev—pip install -e ".[dev]"las trae todas- Es el estándar (PEP 517/518): los instaladores modernos lo leen todos
Instalar tu propio paquete
pip install -e ".[dev]" # editable + dependencias de desarrollo
-e (editable) enlaza el paquete con tu código fuente: cambias un archivo y el cambio se ve al instante, sin reinstalar.
Versionado semántico
1.4.2
│ │ └── parche: arreglo de bugs, sin romper nada
│ └── menor: nueva funcionalidad compatible
└── mayor: cambios que ROMPEN compatibilidad
Sube el número correcto en cada release. Tus usuarios (incluido tú) lo agradecerán.
Compartir: PyPI
pip install build twine
python -m build # genera el .whl y el .tar.gz en dist/
twine upload dist/* # publica en pypi.org (requiere cuenta)
Después de publicar, cualquiera instala con pip install utilidades. Para código interno de la empresa, servidores privados o repositorios Git directamente (pip install git+https://...).
requirements.txt: todavía útil
# congelar el entorno exacto para reproducibilidad
pip freeze > requirements.txt
pip install -r requirements.txt
Para librerías tu fuente de verdad es pyproject.toml; para aplicaciones desplegadas (donde quieres versiones exactas), el congelado es la práctica de despliegue.
Herramientas que complementan
- uv / poetry: gestores de entornos + dependencias + build en una herramienta
- ruff: linter ultrarrápido (estilo + errores)
- mypy: verificación estática de tus type hints
Resumen
- src-layout +
pyproject.tomles el estándar actual pip install -e ".[dev]"para desarrollar con instante de feedback- Versionado semántico: mayor.menor.parche
python -m build+twine uploadpara publicar en PyPI- Los tests deben probar el paquete instalado, no la carpeta