El Modelo de Empaquetado de Python: Del Árbol de Fuentes a un Paquete Instalado
Cada página de esta sección —backends de compilación, versionificación, puntos de entrada, extensiones nativas, publicación— en realidad describe un único pipeline desde diferentes ángulos. Un árbol de fuentes se convierte en un artefacto distribuible a través de un paso de compilación estandarizado, ese artefacto transporta metadatos que describen lo que necesita y proporciona, y un instalador lo coloca en un entorno para que import miaplicacion funcione. Comprender ese pipeline como un único sistema, en lugar de una colección de herramientas memorizadas por separado, es lo que hace que el resto de los detalles de esta sección sean comprensibles.
Esta página describe ese pipeline: qué hace realmente un backend de compilación, por qué Python distribuye dos formatos de distribución en lugar de uno, qué significan las etiquetas en el nombre de archivo de una wheel y por qué existen, y dónde encajan la versionificación, los puntos de entrada y el código nativo en la misma imagen que Conceptos Básicos de Empaquetado y Backends de Compilación ya introducen de forma práctica.
Resumen
- El empaquetado es un pipeline —árbol de fuentes, backend de compilación, artefacto de distribución (sdist o wheel), instalador— y cada herramienta específica en esta sección es una pieza de ese único pipeline.
- Por Qué Importa: Tratar el empaquetado como varias herramientas no relacionadas (una herramienta de compilación, una herramienta de publicación, una convención de versionificación) oculta por qué tienen que estar de acuerdo entre sí, y por qué un pipeline roto falla de maneras confusas y no locales.
- Conceptos Clave: backend de compilación, sdist, wheel, etiqueta de plataforma/ABI, PEP 517, punto de entrada.
- Cuándo Usar: Al decidir qué backend configurar, al comprender por qué una wheel compilada en Linux no se instalará en Windows, o al diagnosticar por qué a un paquete instalado le faltan archivos.
- Limitaciones / Compensaciones: La estandarización que proporciona este pipeline (PEP 517/518) no elimina la complejidad subyacente del código nativo; simplemente le da a esa complejidad una interfaz consistente.
- Temas Relacionados: resolución de dependencias, entornos virtuales, compilación de extensiones nativas, integración continua para artefactos de lanzamiento.
Fundamentos
Un paquete de Python, en el sentido de distribución, comienza como un árbol de fuentes ordinario con un archivo pyproject.toml en su raíz.
La tabla [build-system] de ese archivo nombra un backend de compilación — hatchling, setuptools, poetry-core, maturin y otros — que es la pieza de software realmente responsable de convertir ese árbol de fuentes en un artefacto distribuible.
Esta división es importante porque pip y uv no saben cómo compilar tu proyecto específico; saben cómo llamar al backend que hayas declarado, siguiendo una interfaz estándar, y dejar que haga el trabajo real.
Esa interfaz estándar es PEP 517: cualquier backend que implemente un pequeño conjunto de funciones requeridas (compilar una wheel, compilar un sdist) puede ser intercambiado sin que el instalador necesite lógica específica del backend, que es por lo que pasar de setuptools a hatchling es un cambio de configuración, no una reescritura de cómo instalas cosas.
Hay dos artefactos de distribución que un backend puede producir, y resuelven problemas diferentes.
Un sdist (distribución de fuentes) es una instantánea de tu árbol de fuentes, más metadatos suficientes para compilarlo más tarde; es portable entre plataformas porque aún no ha sido compilado.
Una wheel es lo opuesto: un artefacto precompilado y listo para instalar, organizado exactamente como debería aparecer en site-packages, que es por lo que instalar desde una wheel es rápido; no hay ningún paso de compilación en el momento de la instalación.
Mecánicas e Interacciones
El backend de compilación se invoca, conceptualmente, en dos momentos diferentes, y confundirlos es una fuente común de errores de empaquetado.
Tiempo de compilación es cuando uv build o python -m build llama al backend para producir un sdist y/o wheel a partir de tu árbol de fuentes; aquí es donde la configuración de estilo [tool.hatch.build] (qué archivos incluir, cuáles excluir, dónde residen los paquetes) realmente entra en vigor.
Tiempo de instalación es cuando pip o uv toma una wheel ya compilada y copia su contenido en el site-packages de un entorno, actualizando los metadatos de ese entorno para que el paquete sea importable; para una instalación de wheel pura, el backend no participa en absoluto en esta etapa.
Una instalación editable (pip install -e . o uv pip install -e .) difumina deliberadamente esta distinción: registra tu árbol de fuentes como importable en su lugar, sin producir una wheel real, específicamente para que el desarrollo local no requiera una recompilación después de cada cambio.
Los nombres de archivo de las wheels codifican un contrato que explica un punto común de confusión: por qué una wheel compilada en una máquina a veces se niega a instalarse en otra.
myapp-1.2.0-cp313-cp313-manylinux_2_28_x86_64.whl
│ │ │ │
│ │ │ └─ etiqueta de plataforma: SO + arquitectura de destino de esta wheel
│ │ └─ etiqueta ABI: interfaz binaria con la que fue compilada
│ └─ etiqueta de Python: intérprete/versión de destino (cp313 = CPython 3.13)
└─ versión del paqueteUna wheel puramente Python típicamente lleva py3-none-any en esas ranuras, lo que significa que no le importa la versión del intérprete, la ABI o la plataforma; es solo código fuente de Python, por lo que se instala en cualquier lugar.
Una wheel que contiene código nativo compilado, por el contrario, solo es válida para la combinación exacta de intérprete ABI y SO/arquitectura integrada en esas etiquetas; eso no es tanto una limitación del empaquetado como una descripción honesta de lo que realmente es un binario compilado.
Consideraciones y Aplicaciones Avanzadas
Todo lo que esta sección cubre más allá del bucle central de compilación/instalación son metadatos o procesos superpuestos al mismo pipeline, no un sistema separado.
La versionificación (Versionificación y Changelogs) son metadatos que el backend de compilación incrusta en el artefacto para que los instaladores y los resolvedores de dependencias puedan comparar lanzamientos; SemVer es una convención sobre lo que deben significar los números de versión, no un mecanismo que el pipeline imponga por sí solo.
Los puntos de entrada (Puntos de Entrada y Scripts de Consola) también son metadatos: un mapeo de un nombre de comando a una función de Python — que el backend de compilación escribe en la wheel, y que el instalador lee para generar un script ejecutable real en el momento de la instalación; la CLI que escribes en una terminal se genera, no se escribe a mano.
Las extensiones nativas (Extensiones Nativas y Wheels) añaden un paso de compilación antes de la misma salida en forma de wheel — el backend (a menudo emparejado con una cadena de herramientas de compilación, o un backend centrado en Rust como maturin) produce archivos .so/.pyd que aterrizan dentro de la wheel al igual que lo harían los archivos puramente Python, etiquetados con la plataforma/ABI a la que apuntó esa compilación. Compilar para múltiples plataformas significa ejecutar ese paso de compilación una vez por destino, que es lo que herramientas como cibuildwheel automatizan en lugar de reemplazar.
La publicación (Publicación en PyPI) es el paso final de mover un artefacto ya compilado a un registro que los instaladores puedan encontrar por nombre; nada sobre la publicación cambia cómo se compiló el artefacto, que es por lo que probar una compilación localmente antes de publicarla (instalando tu propia wheel e importándola) detecta la mayoría de los errores de empaquetado antes de que lleguen a un registro.
La distribución de aplicaciones (Distribución de Aplicaciones) — PyInstaller, pipx, contenedores — existe en gran medida porque el pipeline de wheels asume que un intérprete y entorno de Python ya existen en la máquina de destino; cuando esa suposición no se cumple (un usuario final sin Python instalado), el pipeline se envuelve en algo que también empaqueta un intérprete.
| Forma de distribución | Qué asume | Qué resuelve | Costo |
|---|---|---|---|
| Sdist | Un backend de compilación y cadena de herramientas disponibles en tiempo de instalación | Portabilidad entre plataformas y versiones de Python | Instalación más lenta; requiere un entorno de compilación funcional |
| Wheel pura | Solo una versión compatible de Python | Instalación rápida y sin compilación | No cubre dependencias compiladas |
| Wheel específica de plataforma | Una coincidencia exacta de ABI de intérprete + SO + arquitectura | Instalación rápida con código nativo incluido | Debe compilarse por separado para cada plataforma de destino |
| Aplicación empaquetada (PyInstaller, contenedor) | Nada - no se requiere Python en el destino | Distribución a usuarios sin un entorno de Python | Artefacto mucho más grande; propia historia de actualización/parcheo |
Razonar sobre qué fila se aplica a una decisión de lanzamiento dada — "¿esta dependencia tiene que compilarse por plataforma?" o "¿mi usuario final siquiera tiene Python?" — es la decisión real hacia la que se dirige toda esta sección; las páginas de herramientas específicas asumen que puedes ubicar un problema en esta tabla antes de recurrir a sus comandos.
Conceptos Erróneos Comunes
- "pip compila mi paquete." pip orquesta el proceso pero delega la compilación real al backend que declare
[build-system]; pip no sabe cómo compilar una extensión Cython o organizar una wheel por sí solo. - "Un sdist y una wheel son solo diferentes formatos de compresión de lo mismo." Difieren en qué etapa del pipeline representan — un sdist es fuente pre-compilación, una wheel es un artefacto terminado y listo para colocar — y una wheel puede contener archivos (binarios compilados) que nunca existieron en la forma fuente del sdist.
- "Una wheel que funciona en mi máquina funcionará en cualquier caja Linux." Las etiquetas de plataforma de las wheels codifican suposiciones reales de ABI y SO; una wheel compilada contra una versión de glibc o una arquitectura de CPU diferente puede fallar al importarse en una máquina con una diferente, que es exactamente lo que las etiquetas de estilo
manylinuxycibuildwheelexisten para gestionar sistemáticamente. - "La versionificación es solo elegir un número." La cadena de versión son metadatos que otras herramientas — resolvedores de dependencias, changelogs, puertas de lanzamiento de CI — leen y sobre las que actúan; una versión inconsistente o no monótona puede romper la resolución para todos los consumidores del paquete, no solo cosméticos.
- "Las extensiones nativas son un sistema de empaquetado completamente separado." Añaden un paso de compilación antes de que el backend produzca la misma salida en forma de wheel que todo lo demás usa; la salida todavía tiene que satisfacer el mismo contrato de etiquetado de plataforma/ABI que una wheel puramente Python.
Preguntas Frecuentes
¿Qué hace realmente un backend de compilación que pip no hace?
Contiene la lógica específica del proyecto para convertir un árbol de fuentes en una wheel o sdist —decidir qué archivos pertenecen, compilar cualquier código nativo y escribir metadatos del paquete; pip solo conoce la interfaz estándar (PEP 517) para llamar a esa lógica, no cómo realizarla por sí mismo.
¿Por qué Python tiene dos formatos de distribución en lugar de uno?
Un sdist es una instantánea portable pre-compilación útil cuando una wheel aún no existe para una plataforma; una wheel es un artefacto precompilado listo para instalar que omite por completo el paso de compilación — intercambian portabilidad por velocidad de instalación en direcciones opuestas.
¿Qué significan los segmentos en el nombre de archivo de una wheel?
Codifican la versión del paquete, la etiqueta del intérprete de Python, la ABI contra la que fue compilada y la plataforma/arquitectura de destino — una wheel puramente Python usa valores genéricos py3-none-any, mientras que una wheel compilada está fijada a la combinación exacta para la que fue compilada.
¿Por qué no puedo simplemente instalar cualquier wheel que encuentre en cualquier máquina?
Porque una wheel con código nativo compilado solo es válida para la ABI del intérprete, el SO y la arquitectura integrados en las etiquetas de su nombre de archivo; instalarla en un destino no coincidente falla directamente o, peor aún, se importa con éxito pero falla en tiempo de ejecución.
¿Cuál es la diferencia entre el tiempo de compilación y el tiempo de instalación?
El tiempo de compilación es cuando el backend convierte las fuentes en un artefacto y cualquier configuración de compilación específica del proyecto entra en vigor; el tiempo de instalación es cuando los archivos de una wheel ya compilada se copian en un entorno — para una wheel pura, el backend no participa en el tiempo de instalación en absoluto.
¿Por qué una instalación editable no produce una wheel real?
Porque su propósito es omitir el paso de compilación — registra tu árbol de fuentes como importable en su lugar para que los cambios locales sean visibles inmediatamente sin recompilar, lo cual es una conveniencia de desarrollo en lugar de un artefacto de distribución.
¿Son los puntos de entrada y los scripts de consola una característica separada del empaquetado?
No — un punto de entrada es un metadato que el backend escribe en la wheel, y el instalador lee ese metadato para generar un script ejecutable real en el momento de la instalación, por lo que el comando CLI que ejecutas se genera a partir de metadatos de empaquetado, no se escribe a mano.
¿Cambia añadir una extensión nativa el pipeline de empaquetado general?
No la forma del pipeline — añade un paso de compilación antes de que el backend produzca la misma salida en forma de wheel, etiquetada con la plataforma/ABI a la que apunta el código compilado, que es por lo que los paquetes nativos multiplataforma necesitan compilarse una vez por destino.
¿Por qué necesitaría PyInstaller o un contenedor en lugar de solo una wheel?
Una wheel asume que la máquina de destino ya tiene un intérprete y entorno de Python compatibles; cuando un usuario final no tiene ningún intérprete de Python instalado, esa suposición falla, y todo el pipeline de wheels se envuelve dentro de algo que también empaqueta un intérprete.
¿La versionificación es impuesta por el propio pipeline de empaquetado?
El pipeline incrusta la cadena de versión que proporciones como metadatos y los resolvedores comparan esas cadenas, pero el significado del número — convenciones SemVer, orden de pre-lanzamiento — es una convención que los equipos siguen, no algo que el backend de compilación valide por corrección.
¿Qué se rompe realmente cuando un backend de compilación y un sdist discrepan sobre los archivos incluidos?
Un sdist al que le faltan archivos que el backend espera en tiempo de compilación fallará al reconstruirse en otra máquina, y una wheel a la que le faltan archivos que el backend esperaba incluir produce un paquete que se importa pero le faltan módulos o datos en tiempo de ejecución — ambos son fallos de la configuración de "qué pertenece a este artefacto", no del instalador.
¿Por qué probar una wheel compilada localmente antes de publicarla?
Porque la publicación solo mueve un artefacto ya compilado a un registro — no valida el contenido del artefacto — por lo que instalar tu propia wheel en un entorno nuevo e importarla detecta archivos faltantes o metadatos rotos antes de que lleguen a todos los futuros consumidores del paquete.
Relacionados
- Conceptos Básicos de Empaquetado - el ciclo de vida práctico de compilación/publicación
- Backends de Compilación - elección y configuración de hatchling, setuptools y alternativas
- Extensiones Nativas y Wheels - el paso de compilación antes de la wheel
- Versionificación y Changelogs - los metadatos que viajan sobre el artefacto
- Puntos de Entrada y Scripts de Consola - comandos CLI generados a partir de metadatos de empaquetado
- Publicación en PyPI - mover un artefacto compilado a un registro
Versiones de la Pila: Esta página fue escrita para Python 3.14.0 (estable) / Python 3.13 (mantenimiento), con uv 0.6+ como la herramienta principal de compilación/publicación referenciada.