Empaquetado y Distribución en Python
🗺️ Mapa de la Lección
⏱ 1.5 horas🔵 Avanzado🎯 Qué aprenderás
- Crear estructura de paquetes Python
- Configurar setup.py o pyproject.toml
- Gestionar dependencias y metadatos
- Instalar paquetes en modo desarrollo
- Publicar paquetes en PyPI (opcional)
🌍 Para qué te sirve
- Crear bibliotecas reutilizables
- Compartir código entre proyectos del equipo
- Publicar en PyPI para uso público
- Distribuir herramientas internas de empresa
- Crear paquetes instalables con pip
- Gestionar versiones y actualizaciones
🎯 ¿Por qué aprender empaquetado?
Tienes un módulo útil que quieres compartir. Podrías decirle a la gente "copia este archivo a tu proyecto", pero eso no escala. ¿Qué pasa si actualizas el módulo? ¿Cómo manejan las dependencias?
El empaquetado es esencial porque:
- Compartir código profesionalmente: otros pueden instalar con
pip install - Gestión de versiones: usuarios pueden elegir qué versión usar
- Dependencias automáticas:
pipinstala todo lo necesario - Distribución fácil: un comando para instalar en cualquier máquina
- Estándar de la industria: forma profesional de compartir código Python
🌍 Casos reales donde se usa
El empaquetado está en todos los proyectos que se comparten:
- Crear bibliotecas reutilizables: Código que otros pueden usar
- Compartir código en equipo: Módulos compartidos entre proyectos
- Publicar en PyPI: Hacer tu código disponible públicamente
- Distribuir herramientas internas: Paquetes privados para tu empresa
- Gestionar versiones: Controlar qué versión usa cada proyecto
- Instalación simple:
pip installen lugar de copiar archivos
Ejemplo real: Librerías como requests, pandas, django están empaquetadas. Puedes instalarlas con pip install requests en lugar de descargar y copiar archivos manualmente.
💡 Concepto base
El empaquetado organiza tu código como un paquete que otros pueden instalar con pip install tu-paquete. Es la forma profesional de compartir código Python.
Lo genial de Python: Puedes crear paquetes con setuptools o poetry, y distribuirlos fácilmente a través de PyPI o repositorios privados.
# Estructura básica de un paquete
mi_paquete/
__init__.py
modulo.py
setup.py # o pyproject.toml
# Instalar en modo desarrollo
pip install -e .
# O publicar en PyPI
python setup.py sdist bdist_wheel
twine upload dist/*
# Después de pip install -e .
# Puedes importar tu paquete desde cualquier lugar
import mi_paquete
El empaquetado es como crear un kit de ingredientes pre-empacado para preparar chilaquiles al pastor. En lugar de que cada cocinero tenga que buscar y comprar todos los ingredientes por separado, tú creas un paquete completo con todo lo necesario (tortillas, salsa, queso, pastor, especias) y otros pueden simplemente "instalar" tu paquete y empezar a cocinar. Es como crear una marca de comida que otros pueden usar fácilmente. Un comando (pip install) y todo está listo.
Antes de continuar: Asegúrate de entender Módulos y Entornos Virtuales. El empaquetado es avanzado pero esencial si quieres compartir código profesionalmente.
Estructura Básica de un Paquete
Estructura de Directorios
mi_paquete/
├── LICENSE
├── README.md
├── setup.py
├── requirements.txt
├── mi_paquete/
│ ├── __init__.py
│ ├── modulo1.py
│ └── modulo2.py
└── tests/
├── __init__.py
└── test_modulo1.py
setup.py Básico
from setuptools import setup, find_packages
setup(
name="mi_paquete",
version="0.1.0",
packages=find_packages(),
install_requires=[
"requests>=2.25.1",
"pandas>=1.2.0",
],
author="Tu Nombre",
author_email="tu@email.com",
description="Descripción corta del paquete",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/usuario/mi_paquete",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
)
Creación de Paquetes
Configuración de pyproject.toml
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mi_paquete"
version = "0.1.0"
description = "Descripción del paquete"
readme = "README.md"
authors = [
{name = "Tu Nombre", email = "tu@email.com"}
]
license = {file = "LICENSE"}
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
requires-python = ">=3.6"
dependencies = [
"requests>=2.25.1",
"pandas>=1.2.0",
]
[project.urls]
Homepage = "https://github.com/usuario/mi_paquete"
Documentation = "https://mi_paquete.readthedocs.io/"
requirements.txt
requests>=2.25.1
pandas>=1.2.0
pytest>=6.0.0
black>=21.0.0
flake8>=3.9.0
Distribución
Construir el Paquete
# Instalar herramientas necesarias
pip install build twine
# Construir el paquete
python -m build
# Verificar el paquete
twine check dist/*
Subir a PyPI
# Subir a PyPI
twine upload dist/*
# Subir a TestPyPI (para pruebas)
twine upload --repository testpypi dist/*
Entornos Virtuales
Crear y Activar
# Crear entorno virtual
python -m venv venv
# Activar en Windows
venv\Scripts\activate
# Activar en Unix/MacOS
source venv/bin/activate
requirements.txt
# requirements.txt
# Dependencias de producción
requests==2.25.1
pandas==1.2.0
# Dependencias de desarrollo
pytest==6.0.0
black==21.0.0
flake8==3.9.0
Buenas Prácticas
- Versionado Semántico
# setup.py
setup(
version="1.2.3", # MAJOR.MINOR.PATCH
# ...
)
- Manejo de Dependencias
# setup.py
setup(
install_requires=[
"requests>=2.25.1,<3.0.0", # Rango de versiones
"pandas>=1.2.0",
],
extras_require={
"dev": [
"pytest>=6.0.0",
"black>=21.0.0",
],
},
)
- Documentación
# setup.py
setup(
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
project_urls={
"Documentation": "https://mi_paquete.readthedocs.io/",
"Source": "https://github.com/usuario/mi_paquete",
},
)
Ejemplos Avanzados
Paquete con Código C
# setup.py
from setuptools import setup, Extension
module = Extension(
"mi_modulo",
sources=["mi_modulo.c"],
include_dirs=["include"],
libraries=["m"],
)
setup(
name="mi_paquete",
version="0.1.0",
ext_modules=[module],
# ...
)
Paquete con Datos
# setup.py
setup(
# ...
package_data={
"mi_paquete": [
"datos/*.json",
"config/*.yaml",
],
},
include_package_data=True,
)
Scripts de Consola
# setup.py
setup(
# ...
entry_points={
"console_scripts": [
"mi_comando=mi_paquete.cli:main",
],
},
)
Herramientas de Desarrollo
black
# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py36', 'py37', 'py38']
include = '\.pyi?$'
flake8
# setup.cfg
[flake8]
max-line-length = 88
extend-ignore = E203
exclude = .git,__pycache__,build,dist
pytest
# pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
Consejos
- Usa versionado semántico
- Mantén las dependencias actualizadas
- Incluye documentación clara
- Prueba el paquete antes de distribuir
- Usa entornos virtuales
Recursos Adicionales
Documentación Oficial
- Python Packaging User Guide
- setuptools Documentation
- PyPI
- TestPyPI
- PEP 517 - Build System
- PEP 518 - Specifying Build System
Bibliografía Recomendada
- Python Tricks (Dan Bader) - Capítulo sobre empaquetado
- Effective Python (Brett Slatkin) - Item 84: Write Docstrings for Every Function, Class, and Module
- The Hitchhiker's Guide to Python (Kenneth Reitz) - Sección sobre packaging
- Python Packaging User Guide (https://packaging.python.org/) - Guía oficial completa
Conceptos Relacionados
- Entornos Virtuales - Prepara el entorno antes de empaquetar
- Testing - Prueba tu paquete antes de publicarlo
- Type Hints - Documenta tipos en tu código
Siguiente paso
Ahora que sabes empaquetar código, aprende a escribir tests para asegurar su calidad. Continúa con: Testing