Gerenciamento de Versões, Ambientes Virtuais e Dependências com Pyenv e Poetry
Quem é desenvolvedor de software sempre tem vários projetos no computador usando diferentes linguagens, versões dessas linguagens, bibliotecas e ferramentas. Para que um projeto não interfira no outro, é importante que sejam isolados de alguma forma. No caso de projetos Python, vamos precisar de ferramentas que gerenciem versões do Python, ambientes virtuais e dependências de projeto. Existem várias opções, mas vamos nos concentrar em duas:
- pyenv gerencia diferentes versões do Python na mesma máquina
- poetry gerencia ambientes virtuais e as dependências do projeto dentro desses ambientes virtuais.
Como Funcionam Ambientes Virtuais do Python
A não ser que você especifique o caminho completo, um comando precisa ser pesquisado pelo sistema operacional para ser executado. A pesquisa é feita em uma lista de diretórios registrada na variável de ambiente chamada PATH
. Quando a primeira ocorrência é encontrada, a busca é interrompida e o programa é executado.
Por exemplo, se PATH
contém $HOME/.local/bin:/usr/local/bin:/usr/bin
e você executa o comando python --version
, então o shell buscará por um executável de nome python
primeiro em $HOME/.local/bin
, depois em /usr/local/bin
e por último em /usr/bin
. O primeiro arquivo executável de nome python
que for encontrado interrompe a busca e é executado com o parâmetro --version
. Se nenhum arquivo for encontrado, então uma mensagem de erro é exibida.
O próximo conceito é que um ambiente virtual no Python é um apenas um diretório que contém a versão desejada do Python e das bibliotecas necessárias para o projeto. A ativação ou desativação de um ambiente virtual é feita, basicamente, manipulando a lista de caminhos contida em PATH
. A ativação põe o diretório do ambiente virtual no começo lista de caminhos, e a desativação o remove da lista da sessão atual.
Instalando e Gerenciando Versões do Python com pyenv
Com vários projetos antigos e novos no mesmo computador, é bem provável que cada um use uma versão diferente do Python. A ferramenta que vai nos permitir instalar e escolher onde e qual versão do Python usar é o pyenv.
Instalação do pyenv
No Ubuntu/Debian/Mint, a instalação do pyenv
é feita por um instalador próprio:
No MacOs, use o brew
para instalar o pyenv
:
Para que o pyenv
funcione corretamente, é necessário adicionar as linhas a seguir no seu arquivo de configuração do shell. Para Bash
, este arquivo é ~/.bashrc
:
Em seguida é necessário iniciar uma nova sessão do terminal ou executar exec $SHELL
para reiniciar a sessão corrente.
Instalação de Versões do Python
Para ver todas as versões do Python disponíveis para instalação, use o comando pyenv install --list
. Como são muitas opções, melhor filtrar usando grep
:
Para instalar as versões 3.7.10
e 3.9.4
, os comandos são:
As versões instaladas disponíveis são listadas pelo comando pyenv versions
:
Como Funciona o pyenv
O pyenv
insere um caminho $HOME/.pyenv/shims
no começo de PATH
para interceptar chamadas a comandos python
e a outros comandos relacionados. Esta interceptação leva a executáveis intermediários, que redirecionam as chamadas para uma versão específica do Python de acordo com a primeira configuração encontrada, nesta ordem:
-
Shell. Versão registrada na variável de ambiente
PYENV_VERSION
. Você pode usar o comandopyenv shell <versão>
para configurar essa variável na sua sessão atual do shell, ou usar outro comando equivalente, tal comoexport PYENV_VERSION=<versão>
. -
Local. Versão registrada no arquivo
.python-version
, que é procurado recursivamente a partir do diretório atual até chegar no diretório-raiz. Você pode usar o comandopyenv local <versão>
para gerar este arquivo. -
Global. Versão registrada no arquivo
$(pyenv root)/version
, que pode ser gerado pelo comandopyenv global <versão>
. - Sistema. Se nenhuma configuração anterior for encontrada, é usada a versão do Python instalada no sistema operacional.
Ambientes Virtuais e Gerenciamento de Dependências com poetry
Instalação do poetry
O poetry
pode ser instalado de várias maneiras. A mais recomendada é através do instalador próprio, que evita que as dependências do poetry
se misturem com as de outras bibliotecas:
No Linux, a instalação é feita no diretório $HOME/.local/bin
. Se este diretório não está no seu PATH
, então é necessário adicioná-lo manualmente no seu arquivo de configuração do shell (~/.bashrc
ou ~/.profile
) com as seguintes linhas:
if [ -d "$HOME/.local/bin" ] ; then PATH="$HOME/.local/bin:$PATH" fi # a configuração do pyenv entra aqui
Para testar a instalação, execute:
Se o comando não retornar nenhuma mensagem de erro, então a instalação foi concluída com sucesso!
Configuração Inicial do poetry
A configuração do poetry
é mantida no arquivo $HOME/.config/pypoetry/config.toml
. Mas ao invés de acessar este arquivo diretamente, você deve usar o comando poetry config
e seus subcomandos.
Para listar as configurações, execute:
Uma das configurações que você deve modificar logo após a instalação é a que define o local de instalação dos ambientes virtuais. Ao invés de manter a configuração padrão que cria ambientes virtuais dentro do diretório $HOME/.cache/pypoetry
, é melhor que cada ambiente virtual seja criado dentro da raiz do projeto com o nome de .venv
porque editores tais como VSCode consigam achá-lo automaticamente e configurar o intellisense.
Para mudar o local de instalação do ambiente virtual para dentro do projeto, execute:
Comandos do poetry
Para exibir os comandos disponíveis, execute:
Vamos nos concentrar em alguns relacionados com as tarefas mais comuns:
- Criar um novo projeto
- Gerenciar as dependências
- Gerenciar o ambiente virtual
Criando Um Novo Projeto
O comando poetry new
cria um novo projeto já com uma estrutura básica de diretórios e arquivos. Por exemplo:
resulta na seguinte estrutura:
projeto-x ├── app │ └── __init__.py ├── pyproject.toml ├── README.rst └── tests ├── __init__.py └── test_app.py
--name
é opcional e permite definir um nome diferente para o diretório onde ficarão os arquivos do pacote do projeto. O padrão do poetry
é usar o mesmo nome do projeto.
O arquivo pyproject.toml
é o arquivo de configuração do projeto. Contém informações como o nome, versão, dependências, etc.
Gerenciando as Dependências
Os principais comandos relacionados com o gerenciamento de dependências são:
-
poetry add
. Adiciona uma dependência ao projeto. -
poetry remove
. Remove uma dependência do projeto. -
poetry show
. Exibe as dependências do projeto. -
poetry update
. Atualiza as dependências do projeto.
As dependências do projeto podem ser divididas em dois grupos: de pacotes essenciais para o funcionamento do projeto e de pacotes usados apenas para o desenvolvimento do projeto, em atividades tais como teste e linting. Na implantação do projeto em um ambiente de estágio ou de produção, é necessário instalar os pacotes do primeiro grupo, mas os do segundo devem ser evitados para diminuir o tamanho da instalação.
A adição dos pacotes principais é feita pelo comando poetry add
. Por exemplo:
$ poetry add fastapi jinja2 aioredis[hiredis] databases loguru passlib[argon2] Creating virtualenv projeto-x in /tmp/projeto-x/.venv Using version ^0.70.0 for fastapi Using version ^3.0.3 for Jinja2 Using version ^2.0.0 for aioredis Using version ^0.5.3 for databases Using version ^0.5.3 for loguru Using version ^1.7.4 for passlib Updating dependencies Resolving dependencies... (8.8s) Writing lock file Package operations: 28 installs, 0 updates, 0 removals • Installing idna (3.3) • Installing pycparser (2.21) • Installing sniffio (1.2.0) • Installing anyio (3.4.0) • Installing cffi (1.15.0) • Installing greenlet (1.1.2) ...
Uma vez que as versões não foram especificadas explicitamente, as versões mais recentes disponíveis dos pacotes e suas dependências são usadas.
Para adicionar os pacotes de desenvolvimento, acrescente a opção --dev
ao comando poetry add
:
$ poetry add --dev pytest alt-pytest-asyncio pytest-cov asgi-lifespan isort blue mypy httpx The following packages are already present in the pyproject.toml and will be skipped: • pytest If you want to update it to the latest compatible version, you can use `poetry update package`. If you prefer to upgrade it to the latest available version, you can use `poetry add package@latest`. Using version ^0.6.0 for alt-pytest-asyncio Using version ^3.0.0 for pytest-cov Using version ^1.0.1 for asgi-lifespan Using version ^5.10.1 for isort Using version ^0.7.0 for blue Using version ^0.910 for mypy Using version ^0.21.1 for httpx Updating dependencies Resolving dependencies... (10.3s) Writing lock file Package operations: 25 installs, 0 updates, 0 removals • Installing appdirs (1.4.4) • Installing certifi (2021.10.8) • Installing click (8.0.3) • Installing h11 (0.12.0) ...
À medida que os pacotes são adicionados, o arquivo pyproject.toml
é atualizado com as informações sobre as dependências. Note que os pacotes de desenvolvimento ficam em uma seção separada:
[tool.poetry.dependencies] python = "^3.10" fastapi = "^0.70.0" Jinja2 = "^3.0.3" aioredis = {extras = ["hiredis"], version = "^2.0.0"} databases = "^0.5.3" loguru = "^0.5.3" passlib = {extras = ["argon2"], version = "^1.7.4"} [tool.poetry.dev-dependencies] pytest = "^5.2" alt-pytest-asyncio = "^0.6.0" pytest-cov = "^3.0.0" asgi-lifespan = "^1.0.1" isort = "^5.10.1" blue = "^0.7.0" mypy = "^0.910" httpx = "^0.21.1"
O poetry
aceita versões baseadas no padrão SemVer (Major.Minor.Patch
) e usa algumas convenções para a especificação da atualização de versões. A notação ^
indica que uma atualização de versão é permitida se o novo número da versão não modificar o dígito diferente de zero mais à esquerda no agrupamento Major.Minor.Patch
. Por exemplo, poetry update fastapi
aceitaria qualquer versão >=0.70.0
e <0.71.0
.
Durante a instalação das dependências de desenvolvimento, você deve ter notado que o pacote pytest
não foi instalado porque já tinha sido incluído pelo comando poetry new
durante a criação do projeto. No entanto, a versão 5.2
não é a versão mais recente disponível. O primeiro impulso é tentar atualizar a versão usando o comando poetry update pytest
, mas a especificação ^5.2
não permite que uma versão 6
seja usada. A solução é adicionar explicitamente a versão mais recente de pytest
como dependência de desenvolvimento:
$ poetry add --dev pytest@latest Using version ^6.2.5 for pytest Updating dependencies Resolving dependencies... (0.7s) Writing lock file Package operations: 1 install, 1 update, 2 removals • Removing more-itertools (8.12.0) • Removing wcwidth (0.2.5) • Installing iniconfig (1.1.1) • Updating pytest (5.4.3 -> 6.2.5)
Isto instala o pacote e também atualizada a seção [tool.poetry.dev-dependencies]
em pyproject.toml
com a nova versão.
Note que, além dos pacotes especificados, várias outras dependências indiretas são instaladas. A relação exata com todos os pacotes instalados, suas versões e outras informações adicionais são armazenadas no arquivo poetry.lock
. Este arquivo garante que todos no projeto usam exatamente as mesmas versões de pacotes.
Ao invés de examinar o arquivo poetry.lock
diretamente, a melhor forma de ver a relação completa de dependências do projeto é através do comando poetry show --tree
:
$ poetry show --tree aioredis 2.0.0 asyncio (PEP 3156) Redis support ├── async-timeout * │ └── typing-extensions >=3.6.5 ├── hiredis >=1.0 └── typing-extensions * alt-pytest-asyncio 0.6.0 Alternative pytest plugin to pytest-asyncio └── pytest >=3.0.6 ├── atomicwrites >=1.0 ├── attrs >=19.2.0 ├── colorama * ├── iniconfig * ├── packaging * │ └── pyparsing >=2.0.2,<3.0.5 || >3.0.5 ├── pluggy >=0.12,<2.0 ├── py >=1.8.2 └── toml * asgi-lifespan 1.0.1 Programmatic startup/shutdown of ASGI apps. └── sniffio * blue 0.7.0 Blue -- Some folks like black but I prefer blue. ├── black 21.7b0 │ ├── appdirs * │ ├── click >=7.1.2 │ │ └── colorama * │ ├── mypy-extensions >=0.4.3 │ ├── pathspec >=0.8.1,<1 │ ├── regex >=2020.1.8 │ └── tomli >=0.2.6,<2.0.0 └── flake8 3.8.4 ├── mccabe >=0.6.0,<0.7.0 ├── pycodestyle >=2.6.0a1,<2.7.0 └── pyflakes >=2.2.0,<2.3.0 ...
Habilitando o Ambiente Virtual
Se você acabou de clonar o projeto, deve usar poetry install
para criar o diretório do ambiente virtual e instalar as dependências.
Uma vez instalado em .venv
, há duas opções de habilitar o ambiente virtual pelo terminal. A primeira é ativar o ambiente virtual com o comando poetry shell
:
O prompt da linha de comando é alterado para mostrar a ativação. Para desativar, você pode executar exit
, apertar CTRL+D
, ou apenas abrir um novo terminal.
A segunda opção é rodar um comando dentro do ambiente virtual mas sem ativá-lo permanentemente. Isso é feito pelo comando poetry run <comando>
, que ativa o ambiente virtual, executa o comando internamente e depois desativa. É particularmente útil para ser rodados em scripts.
Seja, por exemplo, um projeto contendo um Makefile
com a seguinte tarefa:
Você pode ativar o ambiente virtual e depois executar make test
para executar os testes, ou pode executar poetry run make test
em um passo só.
Considerações Finais
Este artigo abordou os principais pontos que você precisa saber para usar a combinação pyenv
+ poetry
no gerenciamento de ecossistemas independentes de projetos Python. Algumas considerações finais:
- Não compartilhe ambientes virtuais entre projetos diferentes.
- O diretório do ambiente virtual não deve ser mantido no controle de versão porque pode ser reconstruído sempre que necessário através dos arquivos
pyproject.toml
epoetry.lock
. Estes, sim, devem fazer rastreados. - Não manipule o diretório do ambiente virtual manualmente. Sempre use os comandos do
poetry
para isso. - Para outros detalhes e comandos do
poetry
, visite a seção sobre comandos na documentação do projeto.
Próximo artigo: Como Começar um Projeto Python Perfeito
Referências Complementares
1 | pyenv: How It Works |
---|
2 | Managing Multiple Python Versions With pyenv |
---|
3 | Modern Python Environments - dependency and workspace management |
---|
4 | Pyenv + Poetry |
---|
5 | Overview of python dependency management tools |
---|
6 | Pipenv and Poetry: Benchmarks & Ergonomics |
---|
7 | Pipenv and Poetry: Benchmarks & Ergonomics II |
---|
Comentários
Comments powered by Disqus