Construa Pacotes Python: Guia do Desenvolvimento ao PyPI

Mestre no empacotamento do Python do código até a implantação no PyPI

Conteúdo da página

Empacotamento Python evoluiu significativamente, com ferramentas e padrões modernos tornando mais fácil do que nunca distribuir seu código.

Este guia orienta você na criação de pacotes Python profissionais e na publicação deles no PyPI. Se você é novo em Python ou precisa de um guia rápido, consulte nossa Folha de Dicas Python para se familiarizar com os fundamentos do Python.

Pacotes Python

Por que empacotar seu código Python?

Empacotar seu projeto Python oferece vários benefícios:

  • Reutilização: Compartilhe código entre múltiplos projetos sem copiar e colar
  • Distribuição: Permita que outros instalem seu código com um simples pip install
  • Gerenciamento de dependências: Especifique e gerencie dependências de forma clara
  • Versionamento: Rastreie lançamentos e mantenha compatibilidade para trás
  • Padrões profissionais: Siga as melhores práticas da comunidade Python
  • Documentação: Estrutura que incentiva documentação e testes adequados

Estrutura Moderna de Pacote Python

Um pacote bem organizado segue esta estrutura:

my-package/
├── src/
│   └── mypackage/
│       ├── __init__.py
│       ├── core.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   └── test_core.py
├── docs/
│   └── index.md
├── .github/
│   └── workflows/
│       └── publish.yml
├── pyproject.toml
├── README.md
├── LICENSE
└── .gitignore

O src-layout agora é preferido sobre o layout plano porque:

  • Impede importações acidentais de código não instalado durante o desenvolvimento
  • Torna os testes mais confiáveis forçando a instalação
  • Separa claramente o código fonte de outros arquivos do projeto

Ao organizar a estrutura interna do seu pacote, considere aplicar princípios de arquitetura limpa para tornar seu código mais mantinível e testável. Nosso guia sobre Padrões de Projeto Python para Arquitetura Limpa aborda princípios SOLID, injeção de dependência e padrões de arquitetura em camadas que funcionam excelente com pacotes Python.

O arquivo pyproject.toml: Configuração Moderna

pyproject.toml (PEP 518, 621) é o padrão moderno para configuração de projetos Python, substituindo o legado setup.py:

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "mypackage"
version = "0.1.0"
description = "Um fantástico pacote Python"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
    {name = "Seu Nome", email = "você@example.com"}
]
keywords = ["exemplo", "tutorial", "pacote"]
classifiers = [
    "Estado de Desenvolvimento :: 4 - Beta",
    "Público-Alvo :: Desenvolvedores",
    "Licença :: Aprovada pela OSI :: Licença MIT",
    "Linguagem de Programação :: Python :: 3",
    "Linguagem de Programação :: Python :: 3.8",
    "Linguagem de Programação :: Python :: 3.9",
    "Linguagem de Programação :: Python :: 3.10",
    "Linguagem de Programação :: Python :: 3.11",
    "Linguagem de Programação :: Python :: 3.12",
]
dependencies = [
    "requests>=2.28.0",
    "click>=8.1.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.4.0",
    "black>=23.0.0",
    "flake8>=6.0.0",
    "mypy>=1.5.0",
]
docs = [
    "sphinx>=7.0.0",
    "sphinx-rtd-theme>=1.3.0",
]

[project.urls]
Homepage = "https://github.com/seuusername/mypackage"
Documentação = "https://mypackage.readthedocs.io"
Repositório = "https://github.com/seuusername/mypackage"
Issues = "https://github.com/seuusername/mypackage/issues"

[project.scripts]
mypackage-cli = "mypackage.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

Seções Principais de Configuração

  1. build-system: Especifica o backend de construção (setuptools, hatchling, poetry-core, flit-core)
  2. project: Metadados principais e dependências
  3. project.optional-dependencies: Dependências de recursos extras (dev, docs, testes)
  4. project.scripts: Pontos de entrada para linha de comando
  5. tool.*: Configuração específica de ferramentas (black, pytest, mypy, etc.)

Escolhendo um Backend de Construção

Setuptools (Escolha Padrão)

A opção mais amplamente usada e compatível:

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

Vantagens: Compatibilidade universal, recursos extensos, ecossistema grande Desvantagens: Configuração mais verbosa, mais lento do que alternativas mais novas

Hatchling (Moderno e Rápido)

Backend moderno leve e performante:

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Vantagens: Construção rápida, configuração simples, bons padrões Desvantagens: Menos plugins do que setuptools

Poetry (Completo)

Gerenciamento completo de dependências e ambientes:

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "mypackage"
version = "0.1.0"
description = "Um fantástico pacote Python"
authors = ["Seu Nome <você@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.28.0"

Vantagens: Resolução de dependências, arquivos de bloqueio, fluxo de trabalho integrado Desvantagens: Fluxo de trabalho diferente, superfície maior de ferramentas

Flit (Minimalista)

Ferramenta simples para pacotes simples:

[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

Vantagens: Extremamente simples, configuração mínima Desvantagens: Recursos limitados para pacotes complexos

Construindo seu Pacote

Instale as Ferramentas de Construção

# Instale a ferramenta moderna de construção
pip install build

# Ou para Poetry
pip install poetry

# Ou para Hatchling
pip install hatch

Construa os Arquivos de Distribuição

Usando o pacote build (funciona com qualquer backend):

# Limpe builds anteriores
rm -rf dist/ build/ *.egg-info

# Construa a distribuição de fonte e a roda
python -m build

# Isso cria:
# dist/mypackage-0.1.0.tar.gz    (distribuição de fonte)
# dist/mypackage-0.1.0-py3-none-any.whl  (roda)

Usando Poetry:

poetry build

Usando Hatch:

hatch build

Entenda os Formatos de Distribuição

Distribuição de Fonte (sdist) - .tar.gz

  • Contém o código fonte e as instruções de construção
  • O pip dos usuários o constrói durante a instalação
  • Inclui testes, documentação e outros arquivos de desenvolvimento

Roda - .whl

  • Distribuição binária pré-construída
  • Instalação rápida (sem etapa de construção)
  • Plataforma específica ou puramente em Python
  • Formato recomendado para distribuição

Publicando no PyPI

Método 1: Upload Manual com Twine (Tradicional)

# Instale twine
pip install twine

# Verifique o pacote antes de enviar
twine check dist/*

# Faça upload para o TestPyPI primeiro (recomendado)
twine upload --repository testpypi dist/*

# Teste a instalação do TestPyPI
pip install --index-url https://test.pypi.org/simple/ mypackage

# Faça upload para o PyPI de produção
twine upload dist/*

Configure credenciais em ~/.pypirc:

[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmc...

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-AgENdGVzdC5weXBpLm9yZw...

Método 2: Publicação Confiável (Recomendado para CI/CD)

A Publicação Confiável usa OpenID Connect (OIDC) para autenticar a partir de plataformas de CI/CD sem armazenar tokens.

Configuração no PyPI:

  1. Vá para as configurações do seu projeto no PyPI
  2. Navegue até a seção “Publicação”
  3. Adicione um novo “publicador pendente”
  4. Configure:
    • Proprietário: Seu nome de usuário/organização no GitHub
    • Repositório: Nome do repositório
    • Workflow: publish.yml
    • Ambiente: release (opcional, mas recomendado)

Workflow do GitHub Actions (.github/workflows/publish.yml):

name: Publicar no PyPI

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Configurar Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Instalar dependências de construção
        run: |
          python -m pip install --upgrade pip
          pip install build          
      
      - name: Construir o pacote
        run: python -m build
      
      - name: Armazenar pacotes de distribuição
        uses: actions/upload-artifact@v3
        with:
          name: python-package-distributions
          path: dist/

  publish:
    needs: build
    runs-on: ubuntu-latest
    environment: release
    permissions:
      id-token: write
    
    steps:
      - name: Baixar distribuições
        uses: actions/download-artifact@v3
        with:
          name: python-package-distributions
          path: dist/
      
      - name: Publicar no PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

Vantagens:

  • Nenhuma necessidade de gerenciar ou proteger tokens de API
  • Autenticação automática via OIDC
  • Segurança reforçada por meio de regras de proteção de ambiente
  • Rastreamento de auditoria de todas as publicações

Boas Práticas

1. Gerenciamento de Versões

Use o versionamento semântico (SemVer): MAIOR.MENOR.PATCH

# Instale a ferramenta de aumento de versão
pip install bump2version

# Aumente a versão
bump2version patch  # 0.1.0 -> 0.1.1
bump2version minor  # 0.1.1 -> 0.2.0
bump2version major  # 0.2.0 -> 1.0.0

Configure em .bumpversion.cfg:

[bumpversion]
current_version = 0.1.0
commit = True
tag = True

[bumpversion:file:pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

[bumpversion:file:src/mypackage/__init__.py]
search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"

2. Inclua Arquivos Essenciais

README.md: Descrição clara do projeto, instalação, exemplos de uso LICENSE: Escolha a licença apropriada (MIT, Apache 2.0, GPL, etc.) CHANGELOG.md: Documente as mudanças entre versões .gitignore: Exclua artefatos de construção, caches, ambientes virtuais

3. Testes abrangentes

# Instale dependências de teste
pip install pytest pytest-cov

# Execute testes com cobertura
pytest --cov=mypackage tests/

# Gere relatório de cobertura
pytest --cov=mypackage --cov-report=html tests/

Configure em pyproject.toml:

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = "--strict-markers --cov=mypackage"

4. Ferramentas de Qualidade do Código

# Formatação
black src/ tests/

# Linting
flake8 src/ tests/

# Verificação de tipo
mypy src/

# Ordenação de importações
isort src/ tests/

Integre em hooks de pre-commit (.pre-commit-config.yaml):

repos:
  - repo: https://github.com/psf/black
    rev: 23.9.1
    hooks:
      - id: black
  
  - repo: https://github.com/pycqa/flake8
    rev: 6.1.0
    hooks:
      - id: flake8
  
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.5.1
    hooks:
      - id: mypy

5. Documentação

Use Sphinx para documentação:

# Instale Sphinx
pip install sphinx sphinx-rtd-theme

# Inicialize docs
cd docs
sphinx-quickstart

# Construa a documentação
make html

Ou use MkDocs para documentação baseada em Markdown mais simples:

pip install mkdocs mkdocs-material
mkdocs new .
mkdocs serve

6. Integração Contínua

Testar seus pacotes Python em diferentes plataformas e ambientes é crucial para confiabilidade. Para insights sobre o desempenho do Python em diferentes cenários de implantação, veja nossa comparação de Desempenho de AWS Lambda: JavaScript vs Python vs Golang, que explora como o Python se comporta em ambientes sem servidor.

Workflow completo de CI/CD (.github/workflows/ci.yml):

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Configurar Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - name: Instalar dependências
        run: |
          python -m pip install --upgrade pip
          pip install -e ".[dev]"          
      
      - name: Executar testes
        run: pytest --cov=mypackage --cov-report=xml
      
      - name: Enviar cobertura
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
  
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Configurar Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Instalar dependências
        run: |
          pip install black flake8 mypy          
      
      - name: Verificação de formatação com Black
        run: black --check src/ tests/
      
      - name: Flake8
        run: flake8 src/ tests/
      
      - name: MyPy
        run: mypy src/

Problemas Comuns e Soluções

Problema 1: Erros de Importação Após a Instalação

Problema: O pacote foi instalado, mas as importações falham

Solução: Garanta a estrutura adequada do pacote com arquivos __init__.py e configuração correta do pyproject.toml:

[tool.setuptools.packages.find]
where = ["src"]
include = ["mypackage*"]

Problema 2: Dependências Faltando

Problema: O pacote é instalado, mas falha no tempo de execução devido a dependências faltando

Solução: Declare todas as dependências de tempo de execução no pyproject.toml:

[project]
dependencies = [
    "requests>=2.28.0",
    "click>=8.1.0",
]

Problema 3: Conflitos de Versão

Problema: O pacote funciona no desenvolvimento, mas falha em produção

Solução: Use ambientes virtuais e especifique versões mínimas:

# Crie um ambiente isolado
python -m venv .venv
source .venv/bin/activate  # No Windows: .venv\Scripts\activate

# Instale no modo editável para desenvolvimento
pip install -e ".[dev]"

Problema 4: Tamanho do Pacote Grande

Problema: O pacote demora muito para baixar/instalar

Solução: Exclua arquivos desnecessários usando MANIFEST.in:

include README.md
include LICENSE
include pyproject.toml
recursive-include src *.py
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude tests *
recursive-exclude docs *

Problema 5: Problemas Específicos da Plataforma

Problema: O pacote funciona em um OS, mas falha em outro

Solução: Teste em múltiplas plataformas usando matrizes de construção CI/CD (veja o exemplo de CI acima)

Checklist de Publicação

Antes de publicar seu pacote no PyPI, verifique:

  • Todos os testes passam em diferentes versões do Python
  • O código está formatado e lintado
  • O README.md está completo com exemplos
  • O arquivo LICENSE está incluído
  • O número da versão foi atualizado
  • O CHANGELOG.md foi atualizado
  • As dependências estão especificadas corretamente
  • O pacote constrói sem erros (python -m build)
  • O pacote foi testado no TestPyPI
  • A documentação está atualizada
  • O repositório Git está marcado com a versão
  • Um lançamento no GitHub foi criado (para publicação confiável)

Tópicos Avançados

Pontos de Entrada e Ferramentas CLI

Crie interfaces de linha de comando:

[project.scripts]
mypackage = "mypackage.cli:main"

Implementação em src/mypackage/cli.py:

import click

@click.command()
@click.option('--name', default='Mundo', help='Nome para cumprimentar')
def main(name):
    """Exemplo de ferramenta CLI simples"""
    click.echo(f'Olá, {name}!')

if __name__ == '__main__':
    main()

Para um exemplo real de como criar pacotes Python que interagem com APIs externas, consulte nosso guia sobre Integrando Ollama com Python, que demonstra a criação de clientes Python com integrações tanto da API REST quanto da biblioteca oficial.

Sistemas de Plugin

Habilite a descoberta de plugins:

[project.entry-points."mypackage.plugins"]
plugin_a = "mypackage_plugin_a:PluginA"

Extensões C

Para código crítico de desempenho:

[tool.setuptools.ext-modules]
name = "mypackage._speedups"
sources = ["src/mypackage/_speedups.c"]

Pacotes de Namespace

Para pacotes distribuídos sob um namespace comum:

[tool.setuptools.packages.find]
where = ["src"]
include = ["empresa.*"]

[tool.setuptools.package-data]
"empresa.mypackage" = ["py.typed"]

Ferramentas e Recursos Úteis

Ferramentas de Desenvolvimento de Pacotes

  • cookiecutter: Modelos de projeto para pacotes Python
  • tox: Automação de testes em várias versões do Python
  • nox: Automação de testes flexível (alternativa ao tox)
  • pre-commit: Framework de hooks do Git para qualidade do código
  • commitizen: Padronize mensagens de commit e versionamento

Plataformas de Documentação

  • Read the Docs: Hospedagem gratuita de documentação
  • GitHub Pages: Hospede MkDocs ou documentação Sphinx
  • pdoc: Gerador simples de documentação de API

Registries de Pacotes

  • PyPI: O índice oficial de pacotes Python (pypi.org)
  • TestPyPI: Ambiente de teste (test.pypi.org)
  • Anaconda.org: Distribuição de pacotes Conda
  • GitHub Packages: Hospedagem de pacotes privados

Monitoramento e Análise

  • PyPI Stats: Estatísticas de downloads de pacotes
  • Libraries.io: Monitoramento de dependências e alertas
  • Snyk: Varredura de vulnerabilidades de segurança
  • Dependabot: Atualizações automatizadas de dependências

Conclusão

O empacotamento moderno de Python evoluiu para ser amigável ao desenvolvedor com padrões como pyproject.toml, backends poderosos de construção e publicação segura via Publicação Confiável. Seguindo este guia, você pode criar pacotes Python profissionais e mantiveis que atendam efetivamente aos seus usuários.

Principais lições aprendidas:

  1. Use pyproject.toml para todos os novos projetos
  2. Escolha o backend de construção certo para suas necessidades
  3. Implemente testes automatizados e CI/CD
  4. Use Publicação Confiável para implantação segura sem tokens
  5. Siga versionamento semântico e mantenha logs de mudanças
  6. Forneça documentação abrangente e exemplos

O ecossistema de empacotamento Python continua a melhorar com melhor ferramentas, padrões e recursos de segurança. Mantenha-se atualizado com Propostas de Melhoria do Python (PEPs) e melhores práticas da comunidade para manter seus pacotes modernos e mantiveis.

Outros Artigos Úteis Neste Site