Convertir un conjunto de módulos en un paquete instalable facilita reutilizar código, mantener versiones y compartir una herramienta entre proyectos. Un paquete moderno de Python puede instalarse con pip, declarar sus dependencias en pyproject.toml y generar archivos de distribución compatibles con entornos locales, servidores y PyPI. No necesitas una infraestructura compleja: una estructura clara, metadatos correctos y algunas herramientas oficiales son suficientes.
Antes de empezar, revisa cómo funcionan los módulos y paquetes en Python y crea un entorno virtual con venv. Trabajar en un entorno aislado evita que las dependencias globales oculten errores del paquete.
Qué significa que un paquete sea instalable
Un directorio con archivos .py puede importarse en determinadas circunstancias, pero un paquete instalable incluye metadatos y un sistema de construcción. Esto permite ejecutar comandos como:
python -m pip install .Después de la instalación, el paquete queda disponible para el intérprete del entorno, independientemente del directorio actual.
Crear la estructura del proyecto
Una estructura moderna utiliza un directorio src para impedir que las pruebas importen accidentalmente el código sin instalar:
mi_paquete/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── calculadora_util/
│ ├── __init__.py
│ └── operaciones.py
└── tests/
└── test_operaciones.pyEl nombre del proyecto publicado puede contener guiones, mientras que el nombre importable suele utilizar guiones bajos.
Escribir el código del paquete
En src/calculadora_util/operaciones.py puedes añadir funciones sencillas:
def sumar(a: float, b: float) -> float:
"""Devuelve la suma de dos números."""
return a + b
def dividir(a: float, b: float) -> float:
"""Divide a entre b y valida el divisor."""
if b == 0:
raise ValueError("El divisor no puede ser cero")
return a / bEl archivo __init__.py puede exponer la API pública:
from .operaciones import dividir, sumar
__all__ = ["dividir", "sumar"]Mantener una API pequeña ayuda a cambiar la implementación interna sin romper a los usuarios.
Configurar pyproject.toml
pyproject.toml centraliza el sistema de construcción y los metadatos:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "calculadora-util-ejemplo"
version = "0.1.0"
description = "Funciones matemáticas sencillas"
readme = "README.md"
requires-python = ">=3.10"
authors = [
{ name = "Tu nombre" }
]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License"
]
[project.urls]
Homepage = "https://example.com"
Repository = "https://github.com/usuario/proyecto"El nombre debe ser único si planeas publicarlo. No copies un nombre popular ni uses datos falsos en los enlaces. El requisito de Python debe representar las versiones que realmente pruebas.
Declarar dependencias
Si tu biblioteca necesita paquetes externos, decláralos:
[project]
dependencies = [
"requests>=2.32,<3"
]Evita fijar versiones excesivamente estrictas en una biblioteca, porque puedes crear conflictos con las aplicaciones que la utilizan. Las aplicaciones finales pueden usar archivos de bloqueo o herramientas como Poetry para gestionar dependencias.
Instalar el proyecto en modo editable
Durante el desarrollo, instala el paquete con:
python -m pip install -e .El modo editable permite modificar los archivos de src sin reinstalar después de cada cambio. Aun así, los cambios en metadatos o dependencias pueden requerir una nueva instalación.
Probar la importación
python -c "from calculadora_util import sumar; print(sumar(2, 3))"Ejecuta también las pruebas desde un entorno limpio. Así compruebas que el paquete funciona porque está correctamente instalado y no porque el directorio actual aparece en sys.path.
Crear una prueba con pytest
from calculadora_util import dividir, sumar
def test_sumar():
assert sumar(2, 3) == 5
def test_dividir():
assert dividir(10, 2) == 5Instala pytest como dependencia de desarrollo, no como dependencia obligatoria del usuario final. Después ejecuta:
python -m pytestGenerar archivos de distribución
Instala la herramienta oficial de construcción:
python -m pip install --upgrade build
python -m buildEl comando crea normalmente dos archivos en dist/: una distribución fuente .tar.gz y una wheel .whl. La wheel permite una instalación rápida sin ejecutar el proceso de construcción en el equipo del usuario.
Probar la wheel localmente
No publiques inmediatamente. Crea otro entorno virtual e instala la wheel:
python -m venv .venv-prueba
# Windows
.venv-prueba\Scripts\activate
# macOS o Linux
source .venv-prueba/bin/activate
python -m pip install dist/calculadora_util_ejemplo-0.1.0-py3-none-any.whlComprueba imports, funciones, recursos incluidos y comandos de terminal. Esta prueba detecta archivos olvidados y configuraciones que funcionaban solo en el repositorio.
Añadir un comando de consola
Un paquete puede exponer una CLI. Crea una función:
# src/calculadora_util/cli.py
from .operaciones import sumar
def main():
print(sumar(2, 3))Declara el punto de entrada:
[project.scripts]
calculadora-demo = "calculadora_util.cli:main"Después de instalar el paquete, el comando calculadora-demo estará disponible en el entorno.
Versionado y cambios
Una versión como 0.1.0 comunica el estado del proyecto. Incrementa la versión antes de crear una nueva distribución. No reutilices una versión ya publicada en PyPI, porque los repositorios no permiten reemplazarla. Mantén un registro de cambios y documenta las modificaciones incompatibles.
Publicar cuando el paquete esté listo
La guía para publicar un paquete en PyPI explica el uso de TestPyPI, tokens y Twine. La publicación debe ser el último paso, después de revisar la wheel en un entorno limpio.
El tutorial oficial de empaquetado de proyectos de Python mantiene un ejemplo actualizado de estructura, construcción y publicación. La documentación de pip sobre instalación de proyectos locales explica las diferencias entre instalaciones normales y editables.
Errores frecuentes
Los problemas comunes incluyen olvidar __init__.py, ejecutar pruebas contra el código local sin instalarlo, usar un nombre ya registrado, no incluir README o licencia, declarar dependencias innecesariamente rígidas y publicar sin probar la wheel. También es frecuente mezclar archivos generados dentro del repositorio; agrega dist/, build/ y metadatos temporales a .gitignore.
Conclusión
Crear un paquete instalable consiste en organizar el código, definir metadatos en pyproject.toml, instalarlo de forma editable durante el desarrollo, ejecutar pruebas y construir distribuciones. La estructura src, los entornos limpios y las wheels verificadas reducen errores que solo aparecerían en el equipo de otra persona. Cuando el paquete funciona localmente de manera reproducible, puedes publicarlo o utilizarlo internamente con mucha más confianza.






