Executando verificação de segurança...
10

Descomplicando o PyPI: Um Guia Prático para Iniciantes na Publicação de Projetos Python

Hoje vamos aprender a publicar um projeto no PyPI, o indexador de pacotes da linguagem Python.

Para este tutorial, não usaremos o Poetry ou qualquer outra ferramenta de gerenciamento de dependências, priorizando a utilização exclusiva de recursos nativos do Python. Utilizaremos o setuptools como base para a configuração do projeto, a biblioteca build para empacotamento e o Twine para efetuar o upload para o repositório.

É claro que ferramentas como o Poetry facilitam e agilizam o processo de empacotamento e publicação, porém, eu julgo como um conhecimento necessário aprender esse processo independente da ferramenta, depois é muito mais fácil se adaptar a elas.

O Projeto

A criação do pacote é irrelevante para este tutorial, por este motivo eu resolvi disponibilizar um modelo no github que você pode clonar e utilizar como base:

git clone https://github.com/AdaiasMagdiel/exemplo-empacotamento-python.git

Este exemplo consiste em uma única pasta denominada "meu-exemplo-seu-nome". Substitua a parte "seu-nome" pelo seu nome, seguindo a convenção de trocar espaços por hífens e sem o uso de acentos. Essa prática é essencial para evitar colisões de nomes de pacotes durante a publicação (embora seja possível que outra pessoa com o mesmo nome publique esse projeto antes de você, então seja criativo nessa parte).

Dentro dessa pasta, há apenas um arquivo __init__.py contendo uma única função denominada "hello_word" que retorna a string "Hello, World!".

Começando

É sempre uma boa prática utilizar um ambiente isolado para a instalação de bibliotecas, de forma a não afetar a instalação global e evitar possíveis conflitos, entre outros motivos.

Após clonar o repositório, dentro dele, você pode criar e ativar um ambiente virtual da seguinte maneira:

No Linux e MacOS:

python3 -m venv .venv
source .venv/bin/activate

No Windows:

python -m venv .venv
.venv\Scripts\activate

Em seguida, instale as ferramentas que serão utilizadas posteriormente:

pip install build twine

Além do código que você pretende disponibilizar, alguns arquivos, embora não sejam obrigatórios, são essenciais para um projeto quando é empacotado. Entre eles, estão o arquivo de licença e o README.md, que é exibido na página do projeto no PyPI e contém informações importantes. No projeto de exemplo que disponibilizei no Github, adicionei esses arquivos com a licença MIT. Lembre-se sempre de incluí-los caso crie seus próprios projetos.

O pyproject.toml

Durante um bom tempo, o desenvolvimento de pacotes costumava envolver a criação de um arquivo denominado setup.py. Esse arquivo era responsável por fornecer informações cruciais sobre o projeto, como o sistema de build, nome, versão, entre outras. Apesar de ainda ser utilizado, atualmente essa configuração é realizada por meio de um arquivo chamado pyproject.toml.

Para implementar essa configuração em seu projeto, crie um arquivo chamado pyproject.toml na raíz do seu projeto e insira as seguintes informações:

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

Aqui, criamos uma seção chamada de build-system que informa qual o backend que será utilizado pelo nosso projeto. No exemplo, utilizamos o Setuptools mas além dele existem outros como o Flit, PDM, Hatchling, o Poetry e mais alguns outros.

A seguir, criamos a seção project, que contém os metadados do projeto:

[project]
name = "meu-exemplo-seu-nome"
version = "0.1.0"
description = "Um projeto de exemplo utilizado para um estudo sobre empacotamento e publicação de projetos Python."
readme = "README.md"
authors = [
    { name = "seu nome", email = "seu email" }
]
license = { file = "LICENSE" }
classifiers = [
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.6",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
]
keywords = ["hello world", "examples"]
requires-python = ">=3.6"

Lembre-se de alterar o campo name adicionando o seu nome e no campo authors também.

Analisando os nosso metadados linha a linha, temos as seguintes informações:

  • name: O nome da distribuição do nosso pacote. Deve consistir apenas em letras, números, ".", "_" e "-". Também não pode ser um nome já utilizado por outro pacote no PyPi.

  • version: A versão do pacote. A especificação Semantic Version é uma boa referência.

  • description: Um breve resumo sobre o pacote.

  • authors: Usado para identificar as pessoas autoras do pacote. É essencialmente uma lista de objetos contendo o nome e e-mail de cada pessoa autora.

  • readme: O caminho para o arquivo que contém a descrição detalhada do nosso pacote.

  • license: O caminho para o arquivo de licença.

  • classifiers: Uma maneira de fornecer informações adicionais para que o PyPi possa categorizar melhor nosso pacote. Devemos, no mínimo, informar as versões do Python suportadas e a licença utilizada. Uma lista completa com os classifiers disponíveis pode ser vista em https://pypi.org/classifiers/.

  • keywords: Palavras-chave que ajudam na indexação do nosso pacote no PyPi, facilitando que outras pessoas o encontrem através de uma busca simples.

  • requires-python: A versão do Python suportada pelo pacote. Isso significa que nosso pacote só pode ser utilizado em instalações do Python iguais ou superiores à versão 3.6 (no nosso caso poderia até ser uma versão menor).

Caso queira se aprofundar e ver uma lista completa de campos e seções disponíveis para o pyproject.toml, consulte a documentação oficial.

No final, seu arquivo pyproject.toml terá este formato:

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "meu-exemplo-seu-nome"
version = "0.1.0"
description = "Um projeto de exemplo utilizado para um estudo sobre empacotamento e publicação de projetos Python."
readme = "README.md"
authors = [
    { name = "seu nome", email = "seu email" }
]
license = { file = "LICENSE" }
classifiers = [
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.6",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
]
keywords = ["hello world", "examples"]
requires-python = ">=3.6"

Publicando

Para finalmente publicarmos o nosso projeto, você deve primeiro executar o comando de build, usando a biblioteca build previamente instalada:

python -m build

Este comando irá empacotar o seu projeto e gerar os arquivos necessários para a publicação. Ao final, você deverá ter uma estrutura semelhante a esta:

.
├── LICENSE
├── pyproject.toml
├── README.md
├── dist
│   ├── meu-exemplo-seu-nome-0.1.0.tar.gz
│   └── meu_exemplo_seu_nome-0.1.0-py3-none-any.whl
├── meu-exemplo-seu-nome
│   └── __init__.py
└── meu_exemplo_seu-_nome.egg-info
    ├── dependency_links.txt
    ├── PKG-INFO
    ├── SOURCES.txt
    └── top_level.txt

Agora é hora de criar uma conta no PyPI. Acesse este link https://pypi.org/account/register/, preencha todos os dados e clique em "Create account". Você irá receber um e-mail e precisará clicar no link enviado para confirmar a sua conta.

Com o twine instalado vamos publicar nosso pacote com o seguinte comando:

python -m twine upload dist/* --skip-existing

Nesse momento, será solicitado seu username e a sua senha. No entanto, se você inserir essas informações, será informado que a autenticação por username e senha não é mais suportada e deve ser migrada para token de API.

Para criar um token, acesse as configurações da sua conta e vá para a seção "Tokens de API".

Repita comando novamente quando for solicitado o username insira __token__ e quando solicitar a senha insira o token que você copiou. Se tudo der certo vai ser retornado uma mensagem com o link para o seu repositório, já publicado.

Caso queira guardar o seu token para não precisar passá-lo manualmente sempre que for publicar, você pode criar um arquivo chamado .pypirc na raíz do seu usuário ("C:\Users\Usuário\.pypirc" no Windows ou "~/.pypirc" no Linux e MacOS) com o seguinte conteúdo:

[pypi]
username = __token__
password = <o valor do token, incluindo o prefixo pypi->

Com isso configurado, sempre que rodar o comando twine upload, ele automaticamente irá publicar seu projeto sem solicitar essas informações novamente.


É isto. Se você ler mais sobre o arquivo pyproject.toml, pode descobrir como disponibilizar uma interface cli para o seu projeto, como ler a versão e as dependências de forma dinâmica, entre outras coisas. Recomendo fortemente que leiam a documentação e expandam ainda mais os seus conhecimentos.

Até a próxima e obrigado pelos peixes!