O pip tem dado passos importantes em relação à sua evolução, sendo um dos mais notórios deles a adoção por padrão de backtracking. Ainda assim, por suas atribuições serem exclusivamente de um gerenciador de dependências, ele pode deixar um gostinho de "quero mais" no seu flow de desenvolvimento. E é nessas necessidades não atendidas que algumas opções se apresentam como alternativas/complementos ao simpático utilitário de linha de comando.
O Pipfile é uma delas, e já falamos sobre no "Tchau, requirements. Olá, Pipfile!". Demorou um pouco, mas hoje vamos falar do seu concorrente direto, o Poetry.
I built Poetry because I wanted a single tool to manage my Python projects from start to finish. I wanted something reliable and intuitive that the community could use and enjoy.
Essas são as palavras do criador do Poetry, Sébastien Eustace. O mesmo argumento usado no artigo sobre Pipfile, acerca de build determinístico, se sustenta aqui. E assim como o Pipenv, há uma camada extra de funcionalidades que "adoçam" o build e o controle de virtualenvs.
A sua instalação pode ocorrer de maneiras diferentes, dependendo do SO que você estiver utilizando. Portanto,
uma visita à sua documentação é essencial. Ainda
assim, nada que o pip
(que ironia) não resolva:
$ pip install --user poetry
Para compreender como a ferramenta funciona de fato, vamos seguir os mesmos passos do getting started da documentação oficial:
$ poetry new poetry-demo
$ cd poetry-demo/
$ ls
README.rst poetry_demo pyproject.toml tests
Aqui nos deparamos com a primeira peculiaridade: o arquivo pyproject.toml
.
O pip utiliza o requirements.txt
, o Pipenv utiliza o Pipfile
e Pipfile.lock
, e o Poetry o pyproject.toml
e poetry.lock
.
Todos os arquivos citados são utilizados pelas respectivas ferramentas de controle de pacotes para
gerenciar atualizações e instalar novas dependências.
O TOML (Tom's Obvious, Minimal Language) é um formato utilizado para a escrita de arquivos de configuração. Segundo o site oficial:
TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table. TOML should be easy to parse into data structures in a wide variety of languages.
Se você já conhece o Pipfile, a sintaxe utilizada no arquivo é a mesma. Mas qual é
a motivação por trás do arquivo pyproject
?
Antes do ano de 1998 havia o vazio, quando o assunto era empacotamento em Python.
A partir dos anos 2000, instalar, buildar, ou distribuir pacotes começou a ganhar
um novo sentido através da inserção da biblioteca distutils
ao standard lib, e
da convenção de uso do entrypoint setup.py
.
Quatro anos depois, somos apresentados ao setuptools
, que introduz o pacote no formato
egg
e a possibilidade de declarar e instalar dependências. Já em 2008, o pip
é lançado
como uma alternativa aprimorada ao seu primo mais velho,
o easy_install
, que possibilitava a
instalação de pacotes consultando um índice centralizado na internet, chamado Python Package Index (pypi).
E após indas e vindas (e um novo formato, chamado "wheel"), em 2014
o pip
e o setuptools
viram finalmente o padrão para empacotamento em Python.
Confira a timeline completa no Packaging History.
A PEP 518 é
quem apresenta o arquivo pyproject.toml
. Segundo Brett Cannon,
criador da proposta:
(...) the purpose of PEP 518 was to come up with a way for projects to specify what build tools they required. That's it, real simple and straightforward.
Antes dela, não havia uma forma (prática) de dizer quais ferramentas de build que um projeto requer para gerar um pacote wheel
. Embora
o setuptools
possua um argumento setup_requires
para este fim, você não consegue ler esse parâmetro sem antes ter o próprio setuptools
instalado,
e não havia um lugar onde você pudesse especificar que precisa do setuptools
para ler a configuração dentro do setuptools
(notou o problema do ovo-galinha?).
E como vivemos até então sem nos preocupar com esse problema? Simples! Ferramentas como o próprio pip injetam o setuptools
e o wheel
quando executando um arquivo setup.py
.
E se então tivéssemos um lugar para dizer ao pip sobre a necessidade dessas ferramentas?
# pyproject.toml
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"
Booomm!!! Se amanhã alternativas mais interessantes ao setuptools ou pip aparecerem, estaremos preparados.
O Poetry declara qual será o build backend através da utilização das PEPs 518 (citada acima) e 517:
# pyproject.toml
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["Klaus Laube <mail@mail.com>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
O cliente, também instalado através do pip install
anterior, sabe se comunicar
com o poetry.core
, explicitamente declarado na seção [build-system]
.
E com isso o Poetry não apenas cuidará das dependências do seu projeto, como também se responsabilizará por buildar o seu app ou lib, e distribuí-lo no Python Package Index.
Para adicionar uma dependência ao projeto, passamos a utilizar o comando poetry add
:
$ poetry add django
Com isso, o Django passa a ser adicionado ao "requirements":
# pyproject.toml
...
[tool.poetry.dependencies]
python = "^3.7"
Django = "^3.1.4"
...
Por consequência um arquivo poetry.lock
foi criado, e é ele quem garantirá o determinismo durante
a instalação de dependências do projeto:
$ poetry install
Installing dependencies from lock file
Outra consequência do comando add
foi a criação automática de um virtualenv. Agora, através do comando
poetry run
, podemos executar dependências Python diretamente do ambiente virtual:
$ poetry run django-admin.py -h
Ou ainda através do comando shell
:
$ poetry shell
$ which django-admin.py
/Users/klauslaube/Library/Caches/pypoetry/virtualenvs/poetry-demo-IqTsQBT7-py3.9/bin/django-admin
Note que em um ambiente diferente de development, talvez você precise do parâmetro --no-root
:
$ poetry install --no-root
Há cerca de 3 meses eu retornei do Java ao Python, e tinha esquecido (ou nunca de fato notado) o quão não intuitivo é a dança entre pyenv, virtualenv e pip.
Nisso, tanto Pipenv quanto Poetry são fenomenais. O Pipenv leva certa vantagem, uma vez que é capaz de gerenciar até mesmo a versão do Python (com Poetry, ainda necessitamos do pyenv).
Aparentemente há planos do pip suportar um argumento --pipfile
, o que faria do Pipfile (e por consequência Pipenv) uma opção ainda mais
atraente que o concorrente.
Mas tenho certeza que o Poetry será uma mão na roda caso você esteja escrevendo libs.
Até a próxima.