Poetry: construindo pacotes Python de uma forma fácil
Como construir e disponibilizar no PyPI um pacote Python com o auxílio da ferramenta Poetry
A criação de pacotes Python sempre foi algo que me chamou a atenção. Em meu trabalho atual, acabei me tornando um core developer da biblioteca de aprendizado de máquina de uso interno da empresa, além de contribuidor de alguns projetos open-source.
Sendo core developer, comecei a entender melhor como a construção de pacotes é feita e a conhecer diferentes ferramentas que podem auxiliar o desenvolvedor nessa tarefa
Uma das ferramentas que mais me chamou a atenção foi o Poetry, que torna a construção de pacotes em Python cada vez mais simples. Essa ferramenta gera um ambiente virtual (isolado) para podermos trabalhar com nosso projeto, além de nos ajudar com o controle de versão, gerenciamento de dependências, build e compartilhamento no repositório de pacotes Python PyPI (que você provavelmente conhece).
A ideia deste artigo é criar um pacote Python (para fins educativos, somente) e compartilhá-lo no repositório PyPI, tudo isso com o auxílio da ferramenta Poetry. Todo o código fonte desenvolvido aqui poderá ser acessado no repositório GitHub do projeto:
Definição do projeto
A ideia aqui é construirmos um pacote que gere tabelas de dados transacionais fictícios. Queremos gerar tabelas contendo o ID único do usuário (consumer_id), data da compra (transaction_created_at) e valor da compra (transaction_payment_value).
O nome do nosso pacote será RandomDataGen (eu não sou muito criativo hehe).
Basicamente, a ideia final é poder importar esse pacote e utilizá-lo da seguinte forma:
Como saída, devemos ter algo assim (lembrando que toda a geração de dados será aleatória):
Mas, antes de mais nada, precisamos entender como o Poetry funciona e como ele pode nos ajudar nessa tarefa.
Instalando o Poetry
A instalação do Poetry é muito simples, basta seguirmos os passos apresentados aqui.
Iniciando o uso
Após a instalação, o Poetry estará pronto para ser utilizado. O primeiro passo é criarmos uma pasta chamada random-data-gen e navegarmos até ela com com o terminal. Após isso, devemos rodar o seguinte comando:
Este comando cria uma estrutura de pastas e de arquivos no diretório “.” (que no nosso caso deve ser um diretório chamado random-data-gen) com o nome desse diretório sendo utilizado como nome do projeto.
A estrutura de pastas gerada pelo Poetry tem a seguinte forma:
random-data-gen/
│ README.md
│ pyproject.toml
│
└───random_data_gen/
│ │ __init__.py
│
└───tests/
│ __init__.py
│ test_random_data_gen.py
Nessa estrutura, arquivo README.md deve ser utilizado para descrição do projeto. O arquivo pyproject.toml contém todas as informações do pacote que está sendo desenvolvido e é nele que toda a mágica do Poetry acontece. A pasta /random_data_gen será o diretório utilizado para armazenarmos todo o código do projeto. Por fim, a pasta /tests irá conter todos os testes funcionais presentes no projeto.
Entrando em detalhes, o arquivo pyproject.toml contém as seguintes informações:
Os campos name, version, description e authors são autoexplicativos. Os campos abaixo da seção tool.poetry.dependencies são referentes as dependências utilizadas pelo projeto (que no caso de um projeto vazio será somente a versão do Python desejada).
- python = “^3.8” indica que a versão do Python utilizada pelo pacote deve ser pelo menos a 3.8 (que é o nosso caso).
Os campos abaixo da seção tool.poetry.dev-dependencies indicam dependências que serão utilizadas somente durante desenvolvimento (que, no nosso caso, é somente a biblioteca pytest, para testes funcionais). Aqui, podemos incluir outras dependências, como black para formatação de código, mypy para verificação de tipos etc.
Um ponto interessante é a distinção entre as seções dependencies e dev-dependencies:
- tool.poetry.dependencies: essa seção especifica as dependências que serão necessárias para o funcionamento do pacote (e que serão instaladas quando o usuário instalar o pacote via pip install, por exemplo);
- tool.poetry.dev-dependencies: essa seção especifica as dependências necessárias para construção e manutenção do pacote, e que não serão instaladas quando algum usuário instalar o pacote.
Essa distinção é muito interessante, pois evita que pacotes desnecessários tenham de ser instalados por quem vai utilizar o pacote, além de garantir mais organização na criação do projeto.
Os campos abaixo de build-system são campos padrão e não necessitaremos alterar durante esse projeto. Para quem quiser ler mais sobre os arquivos pyproject.toml, irei deixar uma referência ao final do artigo.
Criando nosso pacote
Agora que sabemos um pouco mais como o Poetry funciona, vamos utilizá-lo para construir nosso pacote. O primeiro passo é inicializar nosso ambiente virtual com o seguinte comando (passo muito semelhante ao uso do comando conda activate):
Antes de mais nada, precisamos especificar as dependências que vamos utilizar, que no nosso caso serão duas:
- pandas: para construção do dataframe que será retornado pelo nosso módulo;
- numpy: para geração de dados numéricos utilizados pelo pacote.
A instalação desses pacotes dentro do nosso ambiente virtual é muito simples, precisamos apenas do seguinte comando:
Após instalarmos esses pacotes, podemos verificar que as dependências no nosso arquivo pyproject.toml foram alteradas:
Basicamente essa seção está nos dizendo que:
- Precisamos da biblioteca pandas com versão igual ou superior a versão 1.4.0;
- Precisamos da biblioteca numpy com versão igual ou superior a versão 1.22.1.
Desenvolvendo o pacote
Agora que criamos um ambiente virtual e instalamos tudo que é necessário, podemos começar a criação do nosso pacote Python. O primeiro passo é criar os seguintes arquivos e pastas na nossa estrutura inicial do projeto (em negrito para facilitar a leitura):
random-data-gen/
│ README.md
│ pyproject.toml
| poetry.lock
│
└───random_data_gen/
│ │ __init__.py
| | data_generator.py
| |
| └───features/
| | transactional_features.py
|
└───tests/
│ __init__.py
│ test_random_data_gen.py
A pasta /features irá conter o código para geração de cada uma das três colunas presentes na tabela final (código que está dentro do arquivo transactional_features.py). O arquivo data_generator.py irá conter a lógica principal da aplicação, que será responsável por criar o conjunto de dados transacionais.
O intuito não é entrar em detalhes nesses códigos, caso queira saber mais você pode visitar o repositório do projeto. A título de exemplificação, uma parte do código presente no arquivo transactional_features.py é apresentado na figura abaixo:
Adicionando dependências de desenvolvimento
Com o intuito de padronizar nosso código e verificar erros de tipagem, iremos instalar três pacotes como dependência de desenvolvimento. Essas dependências não serão utilizadas pela versão final do pacote RandomDataGen, sendo instaladas somente quando alguém necessitar contribuir com seu desenvolvimento.
Nesse projeto iremos instalar três dependências:
- black: responsável pela formatação de código;
- mypy: responsável pela checagem de tipos (por isso a função apresentada anteriormente tinha os tipos de cada uma das variáveis de entrada e saída definidos);
- flake8: responsável por garantir a padronização do código segundo o estilo de código definido na PEP8 (irei deixar uma referência sobre isso no final do artigo).
A explicação em detalhes do funcionamento desses três pacotes pode ser vista em suas documentações oficiais, que estarão como referências no final desse artigo.
A instalação de dependências de desenvolvimento com o Poetry é extremamente simples:
Depois da instalação, nosso arquivo pyproject.toml ficará da seguinte forma:
Para configurar a ferramenta black, devemos adicionar a seguinte seção no nosso arquivo pyprojet.toml (nessa configuração estamos definindo basicamente a quantidade de caracteres máxima por linha):
A título de exemplo, as figuras abaixo apresentam o código antes e depois da aplicação da ferramenta black:
Podemos ver que a ferramenta inseriu quebras de linha nas linhas que excediam o máximo de caracteres esperado (que no nosso caso foi definido como 100 caracteres por linha).
Publicando o pacote
Após finalizarmos o desenvolvimento do pacote devemos pública-lo no repositório de pacotes Python PyPI. Esse repositório pode ser acessado aqui (para publicar um pacote você precisa se cadastrar na plataforma).
Devemos incluir nosso README.md no cabeçalho de nosso arquivo pyproject.toml para que ele seja utilizado como descrição na página oficial do projeto:
Antes de publicarmos o pacote precisamos rodar o seguinte comando:
Esse comando cria os arquivos .whl e .tar.gz dentro de uma pasta /dist, na raiz do nosso projeto.
Após isso, podemos rodar o comando:
Esse comando irá guiá-lo pelo login no PyPI e após isso enviará o pacote para lá.
Caso você deseje publicar esse mesmo pacote, uma alteração no nome deverá ser realizada, pois o PyPI não permite pacotes com o mesmo nome (o que faz sentido, não é?!).
Agora que publicamos nosso pacote, podemos acessá-lo pelo link:
Conclusão e próximos passos
Nesse artigo vimos como a ferramenta Poetry pode nos ajudar a desenvolver pacotes Python de uma forma rápida e elegante. Passamos desde a instalação da ferramenta até a publicação do pacote no PyPI.
O Poetry abstraiu diversas etapas do desenvolvimento, tornando a tarefa do desenvolvedor mais focada em resolver a lógica do problema/criação do pacote do que nas tarefas secundárias que são necessárias para conclusão dessa tarefa.
Os nossos próximos passos serão:
- Criar testes funcionais para esse pacote, tornando ele mais robusto a alterações;
- Entrar em detalhes sobre as bibliotecas black, mypy e flake8;
- Adicionar um arquivo Makefile para facilitar a contribuição (esse arquivo já existe no repositório do projeto);
- Criar a documentação do projeto com a ferramenta sphinx;
- Adicionar etapas de continuous integration (CI) e continuous delivery (CD) para que possamos automatizar todo o processo de checagem de código e disponibilização de novas versões do pacote.
Espero que tenham gostado!
Quer saber mais sobre o assunto ou descobrir como a Datarisk pode te ajudar nessas questões? Acesse o nosso site e não deixe de conferir nossos outros posts. Até mais.