PEX: Empacotando projetos python e suas dependências em um único arquivo
Antes de começar a falar do PEX é importante conhecer um comportamento pouco explorado do interpretador do Python. Para isso vamos criar um arquivo de exemplo com o seguinte conteúdo e chamá-lo de teste.py
:
O código pode ser executado com o comando python teste.py
. Mas para o nosso exemplo tentaremos executá-lo assim:
Mas receberemos um erro que diz que não existe um módulo “main” no diretório atual, o que é verdade já que nosso único o arquivo se chama teste.py
.
Nesse momento você já deve ter percebido qual é o tal comportamento pouco explorado. Se mudarmos o nome do nosso arquivo de teste.py
para __main__.py
ao executarmos o comando python .
o arquivo __main__.py
será executado, exemplo:
Indo um pouco além podemos “zipar” esse arquivo __main__.py
e o comportamento do interpretador não muda:
Podemos também criar um diretório contendo nosso arquivo __main__.py
e executá-lo da mesma forma:
Esses comportamentos são padrões do interpretador do python, foram melhorados com a PEP 441 e o PEX usa para criar ambientes python independentes, que é o nosso objetivo.
O que é o PEX
O PEX é o responsável por gerar arquivos independentes que contém um ambiente python completo, como um virtualenv. Ao gerar um arquivo PEX ele cuida dos detalhes necessários para criar um arquivo “zip” que atenda aos padrões do interpretador do python, adicionando um arquivo __main__.py
e o header #!/usr/bin/env python
.
A documentação do projeto é bem completa e dá mais detalhes sobre como tudo funciona, você pode conferir aqui: https://pex.readthedocs.io/.
Instalando o PEX
A instalação é feita usando o pip, como qualquer outro pacote python:
Eu encontrei um pequeno probleminha nessa abordagem de instalação porque ela requer que você tenha um virtualenv ativo ou permissão para instalar como um pacote global. Para conseguir fugir desses dois pontos eu fiz um pequeno script que baixa, instala no /tmp/
e cria um executável PEX usando o próprio PEX:
Caso você tenha usado a primeira abordagem você terá disponível o comando pex
, se você optou por usar o meu script você precisará executar com ./pex
. Nas dicas a seguir eu usarei o arquivo gerado pelo meu script.
Ambientes virtuais temporários
Com o PEX instalado podemos criar ambientes virtuais tanto temporários quanto permanentes. Para exemplificar vamos criar um ambiente virtual com a biblioteca requests:
Com esse comando o PEX executa o interpretador do python com o pacote especificado no PYTHONPATH, o que pode ser bem útil no momento do desenvolvimento. Caso o pacote que você queria instalar possua um executável você pode usar a flag -c
para dizer para o PEX executá-lo. Vamos usar o thumbor nesse exemplo:
O --
é usado para dizer para o PEX que os próximo parâmetros serão passados para o programa que você está executando(no caso, o thumbor) e não para o próprio PEX.
Salvando ambientes PEX
Apesar de ser útil durante o desenvolvimento, os ambientes temporários não são tão interessantes quando você costumar usar sempre os mesmos softwares, nesse caso é interessante persistir o seu ambiente. Para esse exemplo vamos usar o httpie:
Conclusão
O PEX é uma ótima alternativa para quem quer testar um novo pacote sem “sujar” o ambiente de desenvolvimento do seu projeto e também para quem usa projetos python que contém scripts no dia a dia, como o thumbor, httpie e outros. Nesse segundo caso a grande vantagem é não precisar ter um virtualenv apenas para esses projetos e ter que ficar alternando entre o virtualenv do projeto e o virtualenv que contém esses scripts, nem mesmo “sujar” sua instalação global do Python.
Uma última dica é criar um diretório para abrigar todos esses executáveis e colocar no seu PATH
, com isso você não precisará chamar o executável com o PATH
completo e poderá fazer isso de dentro do seu projeto mesmo. Para isso eu criei um diretório ~/.pybin
e coloquei lá o arquivo pex
gerado pelo meu script e sempre que crio um executável novo também mando pra lá. E adicionei esse diretório ao meu .bash_profile
:
É isso! :)