zipapp en Python: crea ejecutables .pyz

Publicado el: 13/08/2026
Tempo de leitura: 6 minutos
Archivadores organizados que representan aplicaciones empaquetadas en archivos .pyz con zipapp en Python

El módulo zipapp en Python crea archivos ZIP ejecutables que contienen una aplicación Python. Estos archivos suelen utilizar la extensión .pyz y se pueden iniciar con python aplicacion.pyz. En sistemas POSIX también pueden incluir un shebang y permiso de ejecución para funcionar como un comando normal.

El formato es útil para distribuir utilidades internas, herramientas de línea de comandos, scripts administrativos y aplicaciones puramente Python en un único archivo. No convierte el proyecto en un binario nativo ni incluye automáticamente el intérprete. La máquina de destino necesita una versión compatible de Python y las dependencias deben soportar la ejecución desde un ZIP.

Cómo funciona un archivo .pyz

Una Python Zip Application es un ZIP estándar que contiene __main__.py en la raíz. Al ejecutarlo, Python añade el archivo a sys.path y ejecuta ese módulo como punto de entrada.

mi_app/
├── __main__.py
├── comandos.py
└── datos/
    └── config.json

Crea el archivo con:

python -m zipapp mi_app

Después:

python mi_app.pyz

Los imports utilizan el mecanismo normal de Python para archivos ZIP. Para datos empaquetados, usa los patrones explicados en importlib.resources en Python.

Generar un punto de entrada

Si el directorio no contiene __main__.py, la opción -m genera uno que importa y llama una función sin argumentos.

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

La función debe formar parte del archivo:

# mi_app/cli.py
def main():
    print('Aplicación iniciada')

El formato requerido es paquete.modulo:funcion. No uses -m si la fuente ya contiene __main__.py.

Añadir un shebang

La opción -p añade una línea de intérprete. En POSIX, zipapp también activa el permiso ejecutable.

python -m zipapp mi_app \
  -p "/usr/bin/env python3" \
  -o herramienta.pyz

./herramienta.pyz

El intérprete elegido debe ser portable para el público objetivo. /usr/bin/env python3 suele ser más flexible que una ruta absoluta, pero presupone que existe un comando python3 compatible.

Comprimir o almacenar

Por defecto, los archivos se guardan sin compresión. Usa --compress para aplicar deflate:

python -m zipapp mi_app --compress -o herramienta.pyz

La compresión reduce el tamaño, aunque puede aumentar el trabajo de construcción y lectura. El código fuente suele comprimir bien; formatos ya comprimidos, como JPEG o PNG, cambian poco.

Automatizar con create_archive()

La API Python ofrece la misma funcionalidad.

import zipapp

zipapp.create_archive(
    source='mi_app',
    target='dist/herramienta.pyz',
    interpreter='/usr/bin/env python3',
    main='mi_app.cli:main',
    compressed=True,
)

source puede ser un directorio, un archivo existente o un stream binario. target puede ser una ruta o un stream abierto para escritura binaria. El llamador debe cerrar los streams que proporciona.

Filtrar el contenido del build

El parámetro filter recibe un Path relativo y decide si el elemento entra en el archivo.

from pathlib import Path
import zipapp

IGNORADOS = {'__pycache__', '.git', '.pytest_cache'}

def incluir(ruta: Path) -> bool:
    if any(parte in IGNORADOS for parte in ruta.parts):
        return False
    return ruta.suffix not in {'.pyc', '.log', '.env'}

zipapp.create_archive(
    'mi_app',
    'dist/mi_app.pyz',
    filter=incluir,
    compressed=True,
)

Excluye secretos, archivos de entorno, logs, caches y artefactos de desarrollo. Construye desde un directorio limpio e inspecciona el ZIP final.

Incluir dependencias puramente Python

Instala las dependencias en el árbol de build antes de empaquetar:

python -m pip install \
  --requirement requirements.txt \
  --target build/mi_app

python -m zipapp build/mi_app \
  -m "mi_app.cli:main" \
  -o dist/mi_app.pyz

Fija versiones y hashes para builds reproducibles. No instales dependencias directamente en la carpeta de código fuente; usa un directorio descartable.

Las extensiones C no cargan desde el ZIP

Los módulos nativos como archivos .so o .pyd normalmente no pueden cargarse directamente desde el archivo porque el loader del sistema operativo exige objetos reales en el sistema de archivos.

Paquetes como NumPy, bibliotecas criptográficas, drivers y procesadores de imágenes pueden incluir componentes nativos. Exígelos de forma externa, distribuye binarios compatibles junto al .pyz o utiliza otro método de empaquetado. Considera arquitectura y sistema operativo.

Leer recursos empaquetados correctamente

No supongas que __file__ apunta a un directorio normal. Un recurso dentro del ZIP puede no existir como ruta persistente.

from importlib.resources import files

texto = (
    files('mi_app.datos')
    .joinpath('config.json')
    .read_text(encoding='utf-8')
)

Si una API requiere una ruta física, usa as_file() dentro de un context manager. La guía de importlib.resources explica el flujo completo.

Consultar el intérprete incorporado

zipapp.get_interpreter() lee el shebang.

import zipapp

interprete = zipapp.get_interpreter('dist/mi_app.pyz')
print(interprete)

En la CLI, python -m zipapp archivo.pyz --info ofrece el mismo diagnóstico. Úsalo en releases para confirmar el launcher esperado.

Copiar y modificar un archivo existente

create_archive() puede copiar un .pyz existente y reemplazar su línea de intérprete.

zipapp.create_archive(
    'antiguo.pyz',
    'nuevo.pyz',
    interpreter='/usr/bin/env python3',
)

La ruta de entrada y salida no puede ser la misma. Escribe un archivo nuevo, valídalo y sustituye el anterior de manera atómica.

Evitar sobrescrituras inseguras

La documentación muestra una modificación mediante BytesIO, pero advierte que un error durante la sobrescritura puede destruir el original. En producción, usa un archivo temporal vecino y os.replace().

import os
import zipapp

nuevo = 'app.pyz.nuevo'
zipapp.create_archive('app.pyz', nuevo, '/usr/bin/env python3')
validar(nuevo)
os.replace(nuevo, 'app.pyz')

Artefactos reproducibles

Un build repetible requiere controlar versión de Python, dependencias, archivos, permisos, timestamps y orden del ZIP. Registra el checksum final.

import hashlib
from pathlib import Path

datos = Path('dist/app.pyz').read_bytes()
print(hashlib.sha256(datos).hexdigest())

compileall en Python y py_compile ayudan a verificar sintaxis, pero el bytecode no elimina restricciones de versión.

Seguridad de distribución

Un .pyz es código ejecutable. Firma el artefacto o publica hashes por un canal confiable, limita quién puede crear releases y nunca ejecutes archivos desconocidos.

Empaquetar en ZIP no oculta el contenido. No incluyas claves API, contraseñas, certificados privados ni configuración de producción.

Compatibilidad de versiones

El archivo debe ser compatible con el intérprete de destino. Sintaxis nueva, APIs recientes y requisitos de dependencias pueden fallar en versiones antiguas. Declara una versión mínima y prueba una matriz de entornos limpios.

import sys

if sys.version_info < (3, 11):
    raise SystemExit('Se requiere Python 3.11 o superior')

Un shebang no expresa “versión X.Y o posterior”. Solo apunta a un comando.

Cuándo usar zipapp

Usa zipapp cuando la aplicación es principalmente Python puro, los usuarios ya tienen un intérprete compatible y un único archivo simplifica la operación. Las automatizaciones internas y utilidades CLI son buenos candidatos.

Evítalo cuando necesitas incluir Python, dependes de extensiones nativas, requieres rutas físicas persistentes o necesitas un instalador nativo. Wheels, containers o empaquetadores de ejecutables pueden ser mejores.

Probar el artefacto final

No pruebes únicamente el directorio fuente. Ejecuta el archivo generado en un entorno limpio:

python dist/mi_app.pyz --version
python dist/mi_app.pyz diagnostico

Comprueba que no dependa de paquetes globales. Prueba encoding, recursos, argumentos, errores, códigos de salida y versiones soportadas. La documentación generada con pydoc en Python puede ayudar a revisar APIs.

Errores frecuentes

  • No incluir __main__.py ni el parámetro main.
  • Empaquetar secretos y archivos de desarrollo.
  • Suponer que las extensiones nativas funcionan dentro del ZIP.
  • Usar __file__ para todos los recursos.
  • Elegir un shebang no portable.
  • Sobrescribir el original sin reemplazo atómico.
  • Probar solo en la máquina de build.

Buenas prácticas

  • Construye en un directorio limpio.
  • Fija dependencias y registra hashes.
  • Filtra caches, logs y secretos.
  • Usa importlib.resources para datos.
  • Prueba el .pyz real en entornos limpios.
  • Documenta la versión mínima de Python.
  • Distribuye mediante un canal confiable.

Conclusión

zipapp en Python convierte un árbol de código en una aplicación ejecutable de archivo único. Los entry points, shebangs, filtros y dependencias puramente Python lo hacen práctico para muchas herramientas internas.

No incluye el intérprete ni resuelve dependencias nativas. Planifica compatibilidad, recursos, seguridad y pruebas. Consulta la documentación oficial de zipapp y la documentación de zipimport.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Editor de código que representa autocompletado de REPL con rlcompleter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    rlcompleter en Python: autocompletar REPL

    Aprende rlcompleter en Python para añadir autocompletado a REPLs, consolas y editores, controlar namespaces y evitar efectos secundarios.

    Ler mais

    Tempo de leitura: 6 minutos
    13/08/2026
    Ventana de terminal que representa una consola interactiva creada con cmd en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    cmd en Python: crea consolas interactivas

    Aprende cmd en Python para crear consolas interactivas con comandos, ayuda, historial, autocompletado, pruebas y control seguro de acciones.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Terminal interactivo que representa un REPL personalizado creado con el módulo code en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    code en Python: crea un REPL personalizado

    Aprende el módulo code en Python para crear REPLs personalizados, controlar namespaces, prompts, salida, bloques incompletos y cierre local.

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Código de aplicación web que representa WSGI con wsgiref en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref en Python: aplicaciones WSGI

    Aprende wsgiref en Python para crear y validar aplicaciones WSGI, probar environ y headers, enrutar solicitudes y ejecutar un servidor

    Ler mais

    Tempo de leitura: 4 minutos
    12/08/2026
    Protocolo seguro de Internet que representa preparación Unicode con stringprep en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    stringprep en Python: prepara Unicode

    Aprende stringprep en Python para aplicar tablas RFC 3454, mapear Unicode, rechazar caracteres prohibidos y validar reglas bidireccionales.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Red de conexiones que representa I/O no bloqueante con selectors en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    selectors en Python: I/O no bloqueante

    Aprende selectors en Python para monitorizar muchos sockets, eventos de lectura y escritura, timeouts y conexiones no bloqueantes con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    11/08/2026