Skip to content

Latest commit

 

History

History
320 lines (247 loc) · 8.98 KB

File metadata and controls

320 lines (247 loc) · 8.98 KB

Referência da API

import genpyexeks

build()

Atalho para o pipeline completo.

resultado = genpyexeks.build(
    "C:/projetos/MeuApp",
    app_name="Meu App",
    version="1.0.0",
    publisher="Seu Nome",
    icon="assets/logo.png",
    installer=True,
)

Parâmetros

Parâmetro Tipo Padrão Descrição
project_dir str | Path Pasta do projeto
app_name str | None nome da pasta Nome do aplicativo
version str "1.0.0" Versão X.Y.Z
publisher str "" Autor ou empresa
description str nome do app Descrição curta
copyright str derivado de publisher Aviso de copyright
url str "" Site do projeto
icon str | Path | None None Imagem do ícone
auto_icon bool False Gera ícone com as iniciais
entrypoint str | Path | None detectado Arquivo .py inicial
onefile bool True Um .exe ou uma pasta
windowed bool True Sem console
isolated bool True Constrói em venv limpa
base_python str | Path | None atual Interpretador base
installer bool | InstallerOptions False Gera o instalador
output_dir str | Path | None <projeto>/dist Pasta de saída
hidden_imports list[str] | None None Imports dinâmicos
extra_data list[tuple[str, str]] | None None (origem, destino)
collect_all list[str] | None None Pacotes a coletar
excludes list[str] | None None Módulos a excluir
apply_recipes bool True Aplica as receitas automáticas por biblioteca
uac_admin bool False Exige elevação
clean bool False Reconstrói do zero
on_progress callable | None None (etapa, mensagem, percentual)
on_output callable | None None (linha)

Retorna BuildResult. Levanta GenPyExeError em qualquer falha prevista.


analyze()

Analisa sem construir nada.

info = genpyexeks.analyze("./MeuApp")

print(info.entrypoint_rel)       # "main.py"
print(info.requirements)         # ["PySide6", "pandas"]
print(info.requirements_source)  # "requirements.txt"
print(info.data_dirs)            # [Path("assets")]
print(info.suggests_windowed)    # True
print(info.icon_candidates)      # [Path("assets/logo.png")]
print(info.warnings)             # []

O seu código não é importado nem executado: a detecção usa apenas a AST.


run_build()

Executa o pipeline a partir de uma BuildConfig já montada. É o que a CLI e a GUI usam internamente, e o caminho para configurações que build() não expõe.

from genpyexeks import BuildConfig, AppMetadata, BuildMode, ConsoleMode, run_build

config = BuildConfig(
    project_dir="./MeuApp",
    app=AppMetadata(name="Meu App", version="1.0.0", publisher="Seu Nome"),
    mode=BuildMode.ONEDIR,
    console=ConsoleMode.CONSOLE,
    extra_pyinstaller_args=["--log-level", "DEBUG"],
)

resultado = run_build(config)

Modelos

AppMetadata

from genpyexeks import AppMetadata

app = AppMetadata(
    name="Meu App",
    version="1.0.0",
    publisher="Davi Kasmirski dos Santos",
    description="Faz coisas úteis",
    copyright="",   # gerado a partir do publisher
    url="https://github.com/DaviKdS/GenPyEXE",
)

app.safe_name      # "Meu App"       - utilizável como nome de arquivo
app.slug           # "meu-app"       - minúsculas com hifens
app.version_tuple  # (1, 0, 0, 0)    - formato do VERSIONINFO
app.app_id         # "{GUID}"        - determinístico, para o instalador

Nome vazio levanta ValueError. Sufixos como -beta são descartados na versão numérica, que o Windows exige inteira.

InstallerOptions

from genpyexeks import InstallerOptions

opcoes = InstallerOptions(
    enabled=True,
    desktop_shortcut=True,
    start_menu=True,
    launch_after_install=True,
    per_user_install=True,        # sem UAC
    add_to_path=False,
    file_associations=[".meuext"],  # normalizadas: "txt" vira ".txt"
    run_at_startup=False,
    keep_data_on_uninstall=False,
    license_file=None,
    output_base_name="",          # padrão: <slug>-<versão>-setup-x64
    compression="auto",           # auto | max | fast | none
)

compression="auto" usa fast em onefile e max em onedir. O motivo é que o executável --onefile do PyInstaller já chega comprimido: num teste com 54 MB, max levou 10,1 s para gerar 56,08 MB, contra 5,3 s e 56,15 MB do fast — o dobro do tempo por 0,1% de tamanho. Em onedir a pasta traz DLLs e .pyd crus, e aí a compressão sólida no máximo compensa. Um valor fora da lista levanta ValueError.

BuildConfig

Configuração completa. Campos além dos expostos por build():

Campo Descrição
requirements Caminho alternativo do requirements.txt
extra_pyinstaller_args Argumentos crus repassados ao PyInstaller
sign_tool_args Argumentos do signtool (assinatura opcional)
work_dir Pasta de trabalho (padrão <projeto>/.genpyexe)
dist_dir Pasta de saída efetiva

BuildResult

resultado.success            # bool
resultado.exe_path           # Path | None
resultado.dist_dir           # Path | None
resultado.installer_path     # Path | None
resultado.iss_path           # Path | None  - script do instalador
resultado.spec_path          # Path | None
resultado.icon_path          # Path | None
resultado.notices_path       # Path | None  - THIRD_PARTY_NOTICES.txt
resultado.venv_path          # Path | None
resultado.exe_size_bytes     # int
resultado.exe_size_mb        # float
resultado.duration_seconds   # float
resultado.warnings           # list[str]
resultado.messages           # list[str]

ProjectInfo

Resultado de analyze(): project_dir, entrypoint, entrypoint_rel, requirements, requirements_source, data_dirs, data_files, imported_modules, detected_packages, suggests_windowed, icon_candidates, warnings.


Utilitários

Ícones

from genpyexeks import convert_to_ico, generate_default_icon

convert_to_ico("logo.png", "app.ico")          # 7 resoluções, proporção preservada
generate_default_icon("Meu App", "auto.ico")   # ladrilho com as iniciais

Diagnóstico

from genpyexeks import diagnose

for tool in diagnose():
    print(tool.name, tool.found, tool.version, tool.detail)

Cache de ambientes

from genpyexeks import list_cached_envs, clean_cache

for caminho, tamanho in list_cached_envs():
    print(caminho.name, f"{tamanho / 1024**2:.0f} MB")

clean_cache()

Perfil

from genpyexeks import config

config.save(build_config)              # grava genpyexe.toml
cfg = config.load("./MeuApp")          # lê o perfil
config.exists("./MeuApp")              # bool

Erros

Todos herdam de GenPyExeError, que carrega message e hint.

GenPyExeError
├── ProjectError
│   └── EntrypointNotFoundError
├── IconError
├── ToolchainError
├── EnvironmentError_
├── BuildError          (tem também log_tail)
├── InstallerError
└── ConfigError
from genpyexeks import GenPyExeError, BuildError

try:
    genpyexeks.build("./MeuApp", installer=True)
except BuildError as exc:
    print(exc.message)
    print(exc.hint)
    print(exc.log_tail)     # últimas linhas do PyInstaller
except GenPyExeError as exc:
    print(exc)              # mensagem + dica formatadas

Acompanhar o progresso

def progresso(etapa, mensagem, percentual):
    print(f"[{percentual:3d}%] {mensagem}")

def saida(linha):
    print(f"  | {linha}")

genpyexeks.build("./MeuApp", on_progress=progresso, on_output=saida)

Etapas emitidas: analise, icone, metadados, ambiente, build, licencas, instalador, fim.


Exemplo completo: build em lote

from pathlib import Path

import genpyexeks
from genpyexeks import GenPyExeError, InstallerOptions

PROJETOS = Path("C:/projetos")
AUTOR = "Davi Kasmirski dos Santos"

opcoes = InstallerOptions(
    enabled=True,
    desktop_shortcut=True,
    start_menu=True,
    per_user_install=True,
)

for projeto in sorted(p for p in PROJETOS.iterdir() if (p / "main.py").is_file()):
    print(f"\n=== {projeto.name} ===")
    try:
        resultado = genpyexeks.build(
            projeto,
            app_name=projeto.name.replace("_", " ").title(),
            publisher=AUTOR,
            auto_icon=True,
            installer=opcoes,
            output_dir=Path("C:/releases") / projeto.name,
        )
    except GenPyExeError as exc:
        print(f"  falhou: {exc.message}")
        continue

    print(f"  {resultado.exe_path.name}  ({resultado.exe_size_mb} MB)")
    if resultado.installer_path:
        print(f"  {resultado.installer_path.name}")
    for aviso in resultado.warnings:
        print(f"  ! {aviso}")