Criação de Pacotes Python Embarcados para Distribuição Simplificada em Windows

Introdução à Distribuição de Aplicações Python

Desenvolvedores Python frequentemente enfrentam o desafio de distribuir suas aplicações para usuários que não possuem o interpretador Python instalado ou que não estão familiarizados com o gerenciamento de dependências via pip. A instalação manual de um interpretador e bibliotecas de terceiros pode ser um obstáculo significaitvo para a adoção de projetos por usuários não técnicos. Para resolver essa questão, a criação de um pacote embarcado (embeddable) que inclua o interpretador Python e todas as dependências do projeto em um único diretório oferece uma solução prática e fácil de usar.

Este guia demonstrará como empacotar um projeto Python 3.10 como um "pacote de um clique", utilizando um exemplo prático de uma aplicação de transcrição musical.

Configurando o Ambiente Python Embarcado

O primeiro passo é obter o código-fonte do seu projeto. Para este exemplo, utilizaremos um projeto de transcrição musical. Clone o repositório para o seu ambiente de trabalho:

git clone https://github.com/v3ucn/YiJianBaPu.git

Em vez de instalar o Python tradicionalmente, vamos baixar a versão embarcável específica para Windows. Acesse a página oficial de downloads do Python:

https://www.python.org/downloads/windows/

Procure e baixe o "Windows embeddable package (64-bit)" que corresponda à versão do Python utilizada no desenvolvimento do seu projeto (neste caso, Python 3.10). Descompacte este arquivo ZIP diretamente na pasta raiz do seu projeto. Por exemplo, se o seu projeto está em D:\work\YiJianBaPu, crie uma subpasta python310 e descompacte lá, resultando em D:\work\YiJianBaPu\python310.

Em seguida, é necessário obter o script get-pip.py, que permitirá a instalação do pip no interpretador embarcado. Baixe-o de:

https://bootstrap.pypa.io/get-pip.py

Coloque o arquivo get-pip.py dentro do diretório python310 que você acabou de criar. A estrutura de diretórios dentro de python310 deve ser semelhante a esta:

D:\work\YiJianBaPu\python310>tree /f
Folder PATH listing for volume Novo Volume
Volume serial number is XXXX-XXXX
D:.
    get-pip.py
    libcrypto-1_1.dll
    libffi-7.dll
    libssl-1_1.dll
    LICENSE.txt
    pyexpat.pyd
    python.cat
    python.exe
    python3.dll
    python310.dll
    python310.zip
    python310._pth
    pythonw.exe
    select.pyd
    sqlite3.dll
    unicodedata.pyd
    vcruntime140.dll
    vcruntime140_1.dll
    winsound.pyd
    _asyncio.pyd
    _bz2.pyd
    _ctypes.pyd
    _decimal.pyd
    _elementtree.pyd
    _hashlib.pyd
    _lzma.pyd
    _msi.pyd
    _multiprocessing.pyd
    _overlapped.pyd
    _queue.pyd
    _socket.pyd
    _sqlite3.pyd
    _ssl.pyd
    _uuid.pyd
    _zoneinfo.pyd

Agora, execute o script get-pip.py usando o interpretador Python embarcado. A partir da raiz do seu projeto (D:\work\YiJianBaPu), execute o seguinte comando no terminal:

.\python310\python.exe .\python310\get-pip.py

Após a execução, observe que novas pastas Lib e Scripts serão criadas dentro de python310, indicando que o pip foi instalado com sucesso. A estrutura de diretórios expandida confirmará a presença do pip e de suas dependências:

D:\work\YiJianBaPu\python310>tree
Folder PATH listing for volume Novo Volume
Volume serial number is XXXX-XXXX
D:.
├───Lib
│   └───site-packages
│       ├───pip
│       │   └───... (conteúdo de pip)
│       ├───pip-23.3.1.dist-info
│       ├───pkg_resources
│       │   └───... (conteúdo de pkg_resources)
│       ├───setuptools
│       │   └───... (conteúdo de setuptools)
│       ├───setuptools-68.2.2.dist-info
│       └───_distutils_hack
│           └───__pycache__
└───Scripts

Finalmente, é crucial modificar o arquivo python310._pth (ou o nome correspondente à sua versão do Python) dentro do diretório python310. Edite-o para que seu conteúdo seja:

python310.zip
.

# Uncomment to run site.main() automatically
import site

Essa alteração habilita o carregamento de módulos a partir do diretório atual e do site-packages, o que é essencial para que suas dependências sejam encontradas.

Instalando Dependências no Ambiente Embarcado

Com o pip configurado no interpretador embarcado, você pode instalar as dependências do seu projeto. É imperativo usar o interpretador embarcado e direcionar a instalação para a pasta site-packages dentro do seu ambiente embarcado. Por exemplo, para instalar a biblioteca noisereduce:

.\python310\python.exe -m pip install noisereduce -t .\python310\Lib\site-packages

O argumento -t é fundamental aqui, pois ele força a instalação do pacote e suas dependências diretamente no caminho especificado (.\python310\Lib\site-packages), garantindo que elas estejam contidas no seu pacote embarcado. Após a instalação, você deve ver a biblioteca listada no diretório site-packages:

D:\work\YiJianBaPu\python310\Lib\site-packages>tree
Folder PATH listing for volume Novo Volume
Volume serial number is XXXX-XXXX
D:.
├───noisereduce
│   ├───spectralgate
│   │   └───__pycache__
│   ├───torchgate
│   │   └───__pycache__
│   └───__pycache__

Repita este processo para todas as dependências do seu projeto. Assim, o interpretador e todas as bibliotecas necessárias estarão autocontidos, permitindo que o projeto seja executado em qualquer máquina Windows sem instalações adicionais de Python.

Criando um Script de Execução Rápida

Para facilitar a execução do projeto para o usuário final, crie um arquivo .bat na raiz do seu projeto. Este script iniciará a aplicação usando o interpretador Python embarcado. Nomeie-o, por exemplo, como iniciar_projeto.bat:

@echo off
chcp 65001 > nul
echo Iniciando a aplicação...

REM Executa a separação de áudio usando Spleeter
call .\python310\python.exe -m spleeter separate -p spleeter:2stems -o .\output .\test.mp3
if %errorlevel% neq 0 (
    echo Erro na separação de áudio com Spleeter. Pressione qualquer tecla para sair.
    pause > nul
    exit /b %errorlevel%
)

REM Executa o script de inferência do modelo
call .\python310\python.exe .\infer.py --model .\ckpt\model_ckpt_steps_104000_simplified.ckpt --wav .\output\test\vocals.wav
if %errorlevel% neq 0 (
    echo Erro na inferência do modelo. Pressione qualquer tecla para sair.
    pause > nul
    exit /b %errorlevel%
)

echo Processamento concluído.
pause > nul

Neste script:

  • @echo off: Dseativa a exibição dos comandos no console.
  • chcp 65001 > nul: Define a página de código para UTF-8, essencail para evitar problemas com caracteres especiais (como português) em prompts de console, e redireciona a saída do comando para nul para não poluir o console.
  • echo Iniciando a aplicação...: Exibe uma mensagem de início.
  • call .\python310\python.exe ...: Cada comando call executa um script Python usando o interpretador embarcado. O primeiro executa o spleeter para separar áudio, e o segundo executa o script infer.py para processamento.
  • Os blocos if %errorlevel% neq 0 verificam se o comando anterior foi executado com sucesso e exibe uma mensagem de erro se houver falha, pausando a execução.
  • pause > nul: Mantém a janela do console aberta após a conclusão para que o usuário possa ver as mensagens, redirecionando a saída da pausa para nul.

Ao clicar duas vezes em iniciar_projeto.bat, o programa será executado. Um exemplo de saída no console seria:

Iniciando a aplicação...
INFO:spleeter:File ./output\test/vocals.wav written succesfully
INFO:spleeter:File ./output\test/accompaniment.wav written succesfully
accumulate_grad_batches: 1, audio_sample_rate: 44100, binarization_args: {'num_workers': 0, 'shuffle': True}, binarizer_cls: preprocessing.MIDIExtractionBinarizer, binary_data_dir: data/some_ds_fixmel_spk3_aug8/binary,
clip_grad_norm: 1, dataloader_prefetch_factor: 2, ddp_backend: nccl, ds_workers: 4, finetune_ckpt_path: None,
finetune_enabled: False, finetune_ignored_params: [], finetune_strict_shapes: True, fmax: 8000, fmin: 40,
freezing_enabled: False, frozen_params: [], hop_size: 512, log_interval: 100, lr_scheduler_args: {'min_lr': 1e-05, 'scheduler_cls': 'lr_scheduler.scheduler.WarmupLR', 'warmup_steps': 5000},
max_batch_frames: 80000, max_batch_size: 8, max_updates: 10000000, max_val_batch_frames: 10000, max_val_batch_size: 1,
midi_extractor_args: {'attention_drop': 0.1, 'attention_heads': 8, 'attention_heads_dim': 64, 'conv_drop': 0.1, 'dim': 512, 'ffn_latent_drop': 0.1, 'ffn_out_drop': 0.1, 'kernel_size': 31, 'lay': 8, 'use_lay_skip': True}, midi_max: 127, midi_min: 0, midi_num_bins: 128, midi_prob_deviation: 1.0,
midi_shift_proportion: 0.0, midi_shift_range: [-6, 6], model_cls: modules.model.Gmidi_conform.midi_conforms, num_ckpt_keep: 5, num_sanity_val_steps: 1,
num_valid_plots: 300, optimizer_args: {'beta1': 0.9, 'beta2': 0.98, 'lr': 0.0001, 'optimizer_cls': 'torch.optim.AdamW', 'weight_decay': 0}, pe: rmvpe, pe_ckpt: pretrained/rmvpe/model.pt, permanent_ckpt_interval: 40000,
permanent_ckpt_start: 200000, pl_trainer_accelerator: auto, pl_trainer_devices: auto, pl_trainer_num_nodes: 1, pl_trainer_precision: 32-true,
pl_trainer_strategy: auto, raw_data_dir: [], rest_threshold: 0.1, sampler_frame_count_grid: 6, seed: 114514,
sort_by_len: True, task_cls: training.MIDIExtractionTask, test_prefixes: None, train_set_name: train, units_dim: 80,
units_encoder: mel, units_encoder_ckpt: pretrained/contentvec/checkpoint_best_legacy_500.pt, use_buond_loss: True, use_midi_loss: True, val_check_interval: 4000,
valid_set_name: valid, win_size: 2048
| load 'model' from 'ckpt\model_ckpt_steps_104000_simplified.ckpt'.
100%|████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:01<00:00,  1.88it/s]
Processamento concluído.
Pressione qualquer tecla para continuar . . .

A principal vantagem é que o usuário não precisa se preocupar com a configuração de um ambiente Python em sua máquina. Basta descompactar o pacote e executar o script .bat.

Tags: Python Distribuição de Aplicações Pacote Embarcado pip Windows

Publicado em 10-15 16:09