zipapp en Python: crea archivos .pyz

Publicado el: 27/08/2026
Tempo de leitura: 6 minutos
Side view of contemplating female assistant in casual style standing near shelves and choosing file with documents

El módulo zipapp empaqueta una aplicación Python en un único archivo ZIP ejecutable, normalmente con extensión .pyz. Python añade el archivo a sys.path y ejecuta su __main__.py. Es útil para herramientas internas, scripts de automatización, utilidades CLI, prototipos y distribución en sistemas que ya tienen un runtime compatible.

Un zipapp no es un ejecutable nativo independiente. No incluye automáticamente Python, no resuelve todas las dependencias ni hace importables extensiones compiladas desde dentro del ZIP. Para distribución pública, desktop o equipos sin Python, una herramienta de packaging completa puede ser más apropiada.

Estructura mínima

El archive necesita un __main__.py en la raíz.

mi_app/
├── __main__.py
└── paquete/
    ├── __init__.py
    └── cli.py

El entry file inicia la aplicación.

from paquete.cli import main

if __name__ == "__main__":
    raise SystemExit(main())

Así main() puede probarse de forma independiente y devolver un exit code.

Crea desde línea de comandos

python -m zipapp mi_app -o mi_app.pyz

Ejecútalo con:

python mi_app.pyz --help

Python trata el archive como directorio importable y ejecuta el entry point.

Crea con la API

zipapp.create_archive() automatiza el build.

from zipapp import create_archive

create_archive(
    "mi_app",
    target="dist/mi_app.pyz",
)

Crea primero el directorio de destino y usa pathlib para organizar el pipeline.

Genera un entry point

Si no existe __main__.py, indica una función como paquete.modulo:funcion.

python -m zipapp mi_app \
  -m "paquete.cli:main" \
  -o mi_app.pyz

La herramienta genera un archivo que importa y llama la función.

Diseño de main

La función debe ser importable y callable sin argumentos posicionales, salvo que lea sys.argv.

def main():
    argumentos = parser.parse_args()
    ejecutar(argumentos)
    return 0

No ejecutes todo el programa durante el import. Los imports deberían definir componentes.

Shebang e interpreter

La opción --python o el parámetro interpreter añade una línea de intérprete.

python -m zipapp mi_app \
  --python "/usr/bin/env python3" \
  -o mi_app.pyz
chmod +x mi_app.pyz
./mi_app.pyz

Funciona en sistemas con shebang. En Windows normalmente se usa python mi_app.pyz.

Versión del runtime

Un shebang genérico puede resolver a versiones diferentes. Valida la mínima al iniciar.

import sys

if sys.version_info < (3, 12):
    raise SystemExit("Se requiere Python 3.12 o superior")

Documenta las versiones probadas.

Compresión

--compress o compressed=True comprime las entradas.

create_archive(
    "mi_app",
    target="dist/mi_app.pyz",
    compressed=True,
)

Reduce tamaño, pero añade CPU. En aplicaciones pequeñas la diferencia puede ser mínima.

Build desde fuente limpia

La API puede procesar archives existentes en ciertos flujos, pero no debería tratarse como editor ZIP genérico.

Reconstruye desde una fuente limpia para trazabilidad y reproducibilidad.

Dependencias Python puras

Los paquetes escritos solo en Python pueden instalarse en un staging directory.

python -m pip install \
  --target build/app \
  --requirement requirements.txt
cp -r src/mi_paquete build/app/
python -m zipapp build/app -o dist/app.pyz

Usa entorno aislado y versiones fijadas.

Extensiones nativas

Módulos .so y .pyd normalmente no pueden importarse directamente desde el ZIP porque el loader necesita un archivo real.

Mantén dependencias nativas fuera, extráelas de forma controlada o elige otra herramienta.

Detecta dependencias nativas

No confíes solo en el nombre. Inspecciona wheels y prueba en un entorno limpio.

Una dependencia transitiva puede introducir código nativo.

Recursos del paquete

El código dentro del ZIP no debe asumir que __file__ es un path normal.

Usa importlib.resources.

from importlib.resources import files

texto = (
    files("mi_paquete")
    .joinpath("datos/default.json")
    .read_text(encoding="utf-8")
)

Recursos que necesitan path

importlib.resources.as_file() puede materializar temporalmente un recurso.

Úsalo con context manager y no guardes el path después.

Archivos escribibles

Trata el contenido del archive como read-only. No guardes configuración, cache o base junto a los módulos internos.

Usa directorios de usuario, cache o temporales.

Directorio actual

No supongas que el proceso empieza en el directorio del archive. Path.cwd() depende del lugar de ejecución.

Usa paths absolutos configurados o recursos internos.

Imports

Organiza la aplicación como paquete y prefiere imports absolutos. Los nombres que coinciden con la biblioteca estándar causan conflictos.

Prueba el artefacto final.

Namespace packages

Pueden funcionar, pero mezclar partes internas y externas requiere pruebas.

Un paquete normal suele ser más predecible.

Comportamiento de sys.path

El archive aparece en el import path y puede interactuar con paquetes instalados.

Usa nombres únicos y no dependas de shadowing accidental.

Conflictos externos

Si una dependencia no está incluida, la aplicación puede importar una versión cualquiera del entorno.

Valida versiones o distribuye instrucciones para un venv dedicado.

Uso con venv

Una estrategia interna es crear un venv con Python y dependencias nativas y ejecutar el .pyz con ese intérprete.

El archive contiene código y el venv aporta runtime y bibliotecas.

zipapp frente a pipx

pipx instala CLIs en entornos aislados. Un paquete convencional con entry point puede ser más fácil de actualizar.

Elige zipapp cuando el archivo único simplifique realmente la operación.

Metadatos de versión

Expón --version e incluye opcionalmente un manifest con commit, fecha y lock de dependencias.

__version__ = "1.4.0"

Build reproducible

Los ZIP guardan timestamps y orden, produciendo hashes distintos. Controla timestamps, ordena entradas y fija dependencias.

Puede ser necesaria una etapa adicional para determinismo estricto.

Filtro de archivos

La API acepta un filtro.

def incluir(ruta):
    partes = set(ruta.parts)
    return not partes.intersection({"__pycache__", ".git", "tests"})

create_archive("build/app", "dist/app.pyz", filter=incluir)

No excluyas recursos necesarios. Ejecuta el resultado en un directorio limpio.

No incluyas secretos

Un zipapp es un ZIP común y puede abrirse fácilmente. Nunca guardes passwords, tokens, private keys o credenciales.

Carga secretos desde un manager o configuración externa protegida.

Checksums y firmas

Distribuye hash o firma. Python no valida automáticamente una firma antes de ejecutar.

El proceso de deployment debe verificar el archivo.

Archives no confiables

Ejecutar un .pyz ejecuta código con los permisos del usuario. No descargues y ejecutes archives desconocidos.

Usa HTTPS, firmas, origen confiable y mínimo privilegio.

Actualizaciones atómicas

Descarga con un nombre temporal, valida y usa os.replace().

No sobrescribas la versión activa antes de verificar.

Rollback

Conserva la versión anterior hasta que un smoke test pase. Un launcher o symlink puede seleccionar la activa.

No combines migraciones irreversibles con actualización sin rollback.

Containers

Un zipapp puede reducir archivos en una imagen, pero sigue necesitando Python y dependencias.

Evalúa si agrega valor sobre las layers del container.

Argumentos y exit codes

Usa argparse y códigos consistentes. raise SystemExit(main()) propaga el resultado.

Salida normal en stdout y errores en stderr.

Logging

No escribas logs dentro del archive. Usa stderr, archivo externo o logging estructurado.

Registra la versión al iniciar.

Pruebas

Construye en CI y ejecuta comandos reales en un entorno limpio. Prueba help, version, dependencias ausentes, recursos, códigos, paths con espacios, Windows y POSIX.

Compara fuente y .pyz.

Errores comunes

Los fallos frecuentes son olvidar __main__.py, incluir extensiones nativas, tratar __file__ como path normal, escribir dentro del archive, depender de versiones externas desconocidas, incluir secretos, no probar el artefacto y confundir zipapp con ejecutable autónomo.

Conclusión

zipapp empaqueta aplicaciones Python puras en un único archive ejecutado por Python. Usa un entry point limpio, importlib.resources, dependencias fijadas, contenido read-only y tests del artefacto.

Consulta la documentación oficial de zipapp y sysconfig en Python para comprender el runtime de destino.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Rack de servidores que representa el balanceo de conexiones con SO_REUSEPORT_LB en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: reparte conexiones entre workers

    Aprende SO_REUSEPORT_LB en Python para distribuir conexiones entre workers con pruebas, portabilidad y cierre ordenado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Código Python para representar fracciones exactas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: convierte números en fracciones

    Aprende fractions.from_number en Python para convertir números en fracciones exactas, controlar precisión, validar entradas y evitar redondeos inesperados.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026
    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026