Ir al contenido

Cómo funciona la compilación

pyzed build convierte un proyecto Pyzed en una app que funciona en equipos sin Python: una carpeta (o un único archivo) con el intérprete de Python, pyzed-ui, tus dependencias, el código de tu backend y tus formularios. Usa PyInstaller o Nuitka por debajo, dentro del entorno del propio proyecto, así que no hay que instalar nada de forma global.

  1. Abre una terminal en la carpeta del proyecto (la que tiene pyproject.toml). Si todavía no tienes un proyecto, créalo con pyzed new (mira Crear un proyecto).

  2. Compila:

    Windows, macOS y Linux
    uv run pyzed build
  3. Abre el resultado en dist/:

    Plataforma Resultado Cómo se ejecuta
    Windows dist\Shop\Shop.exe (o dist\Shop.exe con --onefile) Doble clic.
    macOS dist/Shop.app Ábrela desde Finder.
    Linux dist/Shop/Shop (o dist/Shop con --onefile) ./dist/Shop/Shop
flowchart LR
    P["pyproject.toml<br/>[tool.pyzed.build]"] --> B["pyzed build"]
    U["ui/ formularios + manejadores"] --> B
    S["src/ backend"] --> B
    B --> L["script lanzador<br/>build/pyzed/"]
    B --> I["PyInstaller o Nuitka<br/>(uv run --with ...)"]
    L --> I
    I --> D["dist/<br/>carpeta de la app, .exe o .app"]
  1. pyzed build lee [tool.pyzed] y [tool.pyzed.build] de pyproject.toml.
  2. Escribe un pequeño lanzador (build/pyzed/<nombre>_launcher.py) que abre el formulario principal ([tool.pyzed] main) desde dentro del paquete, con el icono de la ventana y la pantalla de inicio.
  3. Crea los archivos de icono (.ico, .icns, .png) a partir de tu imagen, y el archivo de versión de Windows.
  4. Analiza los .py de la carpeta de la interfaz con el módulo ast de Python para saber qué importan.
  5. Ejecuta el empaquetador en el entorno del proyecto con las opciones adecuadas, y la app queda en dist/. Por último completa el Info.plist de macOS y comprime el archivo, si lo pediste.

Los formularios cargan sus manejadores desde archivos .py al abrirse, así que PyInstaller no puede seguir sus imports por sí solo. pyzed build completa lo que falta:

  • La carpeta de la interfaz se incluye como datos, con su estructura (ui/main.pzform, ui/main.py, módulos auxiliares…).
  • Cada módulo que importa la interfaz se pasa como import oculto, así que el backend en src/, los módulos junto a pyproject.toml y los paquetes de terceros se incluyen con todas sus dependencias.
  • El paquete propio del proyecto (src/<nombre>) se incluye entero, también los módulos importados dinámicamente.
  • Pyzed con sus archivos de datos (temas, iconos, plantillas).
  • ui/, src/ y la raíz del proyecto se añaden a la ruta de búsqueda de PyInstaller.

El código de fuera del proyecto, como una biblioteca compartida en una carpeta vecina, se incluye como cualquier otra dependencia una vez instalado en el entorno:

Ventana de terminal
pyzed add --editable ../facturacion # luego `from facturacion import factura` en un manejador

Las opciones de la línea de comandos ganan a [tool.pyzed.build] de pyproject.toml:

Opción Efecto
--backend nuitka Compila con Nuitka en lugar de PyInstaller (mira Elegir un empaquetador).
--onefile Un único ejecutable en lugar de una carpeta.
--console Mantiene la ventana de consola (útil para ver los tracebacks).
--name Shop Nombre del ejecutable o del paquete.
--archive zip Además comprime la app en un zip (o tar.gz) con el nombre que busca el actualizador.
--target linux-x64 Comprueba que este equipo compila ese destino (lo usa la CI); no hace compilación cruzada.
--dry-run Muestra el comando del empaquetador y se detiene.
--workflow Escribe un flujo de GitHub Actions para los targets del proyecto en lugar de compilar (mira CI).

Toda la configuración del proyecto está en pyproject.toml (el diálogo Exportar de Pyzed Design escribe la misma tabla):

pyproject.toml
[tool.pyzed.build]
name = "Shop" # nombre del ejecutable / paquete (por defecto: el del proyecto)
backend = "pyinstaller" # o "nuitka"
onefile = false # un único archivo autoextraíble en lugar de una carpeta
windowed = true # sin ventana de consola en Windows y macOS
icon = "assets/icon.png" # una imagen cuadrada; de ella salen el .ico y el .icns
version = "1.2.0" # por defecto: la versión de [project]
publisher = "Acme" # la empresa en las propiedades del archivo en Windows
identifier = "com.acme.shop" # id del paquete en macOS e id de la app en Linux
copyright = "© 2026 Acme"
optimize = 0 # 1 quita los assert, 2 también los docstrings
slim = true # deja fuera tkinter, test, idlelib... (las apps de Pyzed no los usan)
exclude = ["numpy.tests"] # más módulos que dejar fuera
include = ["assets", "data/precios.csv"] # archivos y carpetas extra, con la misma ruta relativa
hidden-imports = ["shop.plugins.csv"] # módulos importados con importlib o por nombre
collect = ["babel"] # paquetes a incluir enteros: código, datos y binarios
archive = "zip" # además comprime la app: shop-windows-x86_64.zip...
targets = ["windows-x64", "macos-arm64", "linux-x64"] # lo que compila el flujo de CI
args = [] # cualquier otra cosa, pasada al empaquetador tal cual
[tool.pyzed.build.splash]
image = "assets/splash.png"
duration = 1.5 # segundos, como mínimo
text = "Cargando…"
native = true # también la pantalla propia del empaquetador mientras se descomprime
[tool.pyzed.build.nuitka] # opciones solo para un empaquetador ([tool.pyzed.build.pyinstaller] también)
args = ["--lto=yes"]
Ajuste Por defecto Notas
name el nombre del proyecto También el nombre de la carpeta en dist/.
backend "pyinstaller" "nuitka" compila a C: mira más abajo.
onefile false Un único archivo arranca más lento (se descomprime cada vez) y no puede actualizarse solo.
windowed true false (o --console) muestra una terminal junto a la app.
icon ninguno Un PNG se convierte en .ico, .icns y el icono de la ventana; mira Iconos y metadatos.
version, publisher, identifier, description, copyright de [project] Se escriben en las propiedades del archivo en Windows y en el Info.plist de macOS.
splash ninguna Una pantalla de inicio.
optimize 0 El -O (1) o -OO (2) de Python.
slim true Deja fuera tkinter, test, idlelib, lib2to3, ensurepip, pydoc_data, turtle y turtledemo.
strip, upx true, false Quita los símbolos de depuración (Linux y macOS); comprime con UPX si está instalado.
exclude [] Módulos que dejar fuera.
include [] Rutas relativas a la raíz del proyecto.
hidden-imports [] Módulos que el empaquetador no puede ver.
collect [] Paquetes con archivos de datos o plugins.
archive ninguno "zip" o "tar.gz".
targets este equipo Para --workflow: windows-x64, windows-arm64, macos-arm64, macos-x64, linux-x64, linux-arm64.
args [] Cualquier otra opción del empaquetador (PyInstaller, Nuitka).
PyInstaller Nuitka
Cómo Empaqueta tus .py tal cual, junto a Python Compila tu código y sus dependencias a C y luego a código máquina
Tiempo de compilación Segundos Minutos
Velocidad Python normal Compilado: código Python puro más rápido
Tamaño de un archivo único Mayor Alrededor de un 15 % menor (mejor compresión)
Tamaño de una carpeta Menor Mayor (el código compilado ocupa más que los .pyc)
Necesita Nada (uv lo instala) Un compilador de C

Medido con una app de un formulario en Linux x64: PyInstaller creó una carpeta de 57 MB o un archivo único de 25 MB en unos 25 segundos; Nuitka una carpeta de 72 MB o un archivo único de 21 MB en unos 3 minutos. Casi todo el tamaño es el motor de Pyzed (unos 33 MB) y el propio Python, así que slim, exclude y strip importan más que el empaquetador.

Empieza con PyInstaller mientras desarrollas y prueba Nuitka para las versiones publicadas. Nuitka necesita un compilador de C: en Linux gcc (sudo apt install gcc), en macOS las herramientas de línea de comandos de Xcode (xcode-select --install), en Windows las Build Tools de Visual Studio, o Nuitka descarga un compilador la primera vez. pyzed build añade por su cuenta patchelf (Linux) y zstandard (archivos únicos).

Con [tool.pyzed.build.splash], la app abre antes del formulario principal una ventana sin marco con tu imagen, centrada en la pantalla. Se queda al menos duration segundos y hasta que el formulario principal ha cargado, y luego se cierra. text se escribe sobre la parte inferior de la imagen. Con native = true también se muestra la pantalla propia del empaquetador antes de que arranque Python (PyInstaller en Windows y Linux, que necesita tkinter en el Python del proyecto; Nuitka para archivos únicos en Windows), útil en apps de un solo archivo que tardan un momento en descomprimirse.

La misma pantalla funciona en una app escrita en código, con App.splash:

import pyzed as pz
class Shop(pz.App):
splash = pz.Splash("assets/splash.png", duration=1.5, text="Cargando…")

Los archivos de include terminan bajo la raíz del paquete, con la misma ruta relativa. Encuéntralos desde tu código con:

import sys
from pathlib import Path
RAIZ = Path(getattr(sys, "_MEIPASS", Path(__file__).resolve().parents[1]))
precios = RAIZ / "data" / "precios.csv"

sys._MEIPASS es la carpeta del paquete en una app de PyInstaller. En una app de Nuitka y mientras desarrollas se usa la alternativa: desde un manejador de ui/ apunta a la raíz del paquete (o del proyecto); ajusta parents[1] según dónde esté el archivo que ejecuta esto.

Los archivos intermedios van a build/pyzed/ y el resultado a dist/; ambos están en el .gitignore de los proyectos nuevos. Cada compilación empieza limpia, así que no hay que borrar nada a mano.

pyzed build arranca el formulario principal del proyecto. Para una app escrita totalmente en código (una clase pz.App y pz.run(...)), ejecuta tú mismo PyInstaller sobre tu script, incluyendo los datos de Pyzed. pyzed build --dry-run muestra el comando exacto que ejecutaría pyzed build, que puedes adaptar:

Ventana de terminal
uv run --with pyinstaller pyinstaller main.py --name Shop --windowed --collect-data pyzed --collect-submodules pyzed

Con Nuitka:

Ventana de terminal
uv run --with nuitka --with patchelf python -m nuitka --mode=standalone --include-package-data=pyzed main.py