Construindo Pacotes Python: Guia do Desenvolvimento ao PyPI

Domine o empacotamento em Python, do código ao deployment no PyPI.

Conteúdo da página

A 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 construção de pacotes Python profissionais e na publicação deles no PyPI. Se você é novo em Python ou precisa de uma referência rápida, consulte nossa Lista de Referência de Python para se atualizar com os fundamentos do Python.

Pacotes Python

Por que Empacotar seu Código Python?

Empacotar seu projeto Python oferece múltiplos benefícios:

  • Reutilização: Compartilhe código entre vários 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 claramente
  • Versionamento: Rastreie lançamentos e mantenha compatibilidade retroativa
  • Padrões Profissionais: Siga as melhores práticas da comunidade Python
  • Documentação: A estrutura incentiva documentação e testes adequados

Estrutura Moderna de Pacotes 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 layout src é agora preferível ao layout plano porque:

  • Previne importações acidentais de código não instalado durante o desenvolvimento
  • Torna os testes mais confiáveis ao forçar 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 mantível e testável. Nosso guia sobre Padrões de Design Python para Arquitetura Limpa cobre 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 pacote Python fantástico"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
    {name = "Seu Nome", email = "voce@exemplo.com"}
]
keywords = ["exemplo", "tutorial", "pacote"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "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",
]
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/seuusuario/mypackage"
Documentation = "https://mypackage.readthedocs.io"
Repository = "https://github.com/seuusuario/mypackage"
Issues = "https://github.com/seuusuario/mypackage/issues"

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

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

Seções de Configuração Principais

  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, testing)
  4. project.scripts: Pontos de entrada de linha de comando
  5. tool.*: Configuração específica de ferramentas (black, pytest, mypy, etc.)

Escolhendo um Backend de Construção

Setuptools (Opção Padrão)

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

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

Prós: Compatibilidade universal, recursos extensos, ecossistema grande Contras: Configuração mais verbosa, mais lento que alternativas mais novas

Hatchling (Moderno e Rápido)

Backend moderno leve e performático:

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

Prós: Construções rápidas, configuração simples, bons padrões Contras: Menos plugins que setuptools

Poetry (Tudo-em-Um)

Gerenciamento completo de dependências e ambiente:

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

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

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

Prós: Resolução de dependências, arquivos de bloqueio, fluxo de trabalho integrado Contras: Fluxo de trabalho diferente, área de superfície de ferramenta maior

Flit (Minimalista)

Ferramenta simples para pacotes simples:

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

Prós: Extremamente simples, configuração mínima Contras: Recursos limitados para pacotes complexos

Construindo Seu Pacote

Instale as Ferramentas de Construção

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

# Ou para Poetry
pip install poetry

# Ou para Hatchling
pip install hatch

Construa Arquivos de Distribuição

Usando o pacote build (funciona com qualquer backend):

# Limpe construções anteriores
rm -rf dist/ build/ *.egg-info

# Construa distribuição de fonte e wheel
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  (wheel)

Usando Poetry:

poetry build

Usando Hatch:

hatch build

Entendendo Formatos de Distribuição

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

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

Wheel - .whl

  • Distribuição binária pré-construída
  • Instalação rápida (sem etapa de construção)
  • Específico de plataforma ou Python puro
  • 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/*

# Envie para TestPyPI primeiro (recomendado)
twine upload --repository testpypi dist/*

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

# Envie para 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 de plataformas CI/CD sem armazenar tokens.

Configuração no PyPI:

  1. Vá para as configurações do seu projeto PyPI
  2. Navegue até a seção “Publishing”
  3. Adicione um novo “pending publisher”
  4. Configure:
    • Owner: Seu nome de usuário/organização do GitHub
    • Repository: Nome do repositório
    • Workflow: publish.yml
    • Environment: release (opcional mas recomendado)

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

name: Publish to PyPI

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install build dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build          
      
      - name: Build package
        run: python -m build
      
      - name: Store distribution packages
        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: Download distributions
        uses: actions/download-artifact@v3
        with:
          name: python-package-distributions
          path: dist/
      
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

Vantagens:

  • Nenhum token de API para gerenciar ou proteger
  • Autenticação automática via OIDC
  • Segurança aprimorada através de regras de proteção de ambiente
  • Rastro de auditoria de todas as publicações

Melhores Práticas

1. Gerenciamento de Versão

Use versionamento semântico (SemVer): MAJOR.MINOR.PATCH

# Instale ferramenta de incremento de versão
pip install bump2version

# Incremente 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 licença apropriada (MIT, Apache 2.0, GPL, etc.) CHANGELOG.md: Documente alterações 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 de Código

# Formatação
black src/ tests/

# Linting
flake8 src/ tests/

# Verificação de tipo
mypy src/

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

Integre em ganchos 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 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 a confiabilidade. Para insights sobre o desempenho do Python em diferentes cenários de implantação, veja nossa comparação de desempenho AWS Lambda: JavaScript vs Python vs Golang, que explora como o Python performa em ambientes serverless.

Fluxo de trabalho completo 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: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e ".[dev]"          
      
      - name: Run tests
        run: pytest --cov=mypackage --cov-report=xml
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
  
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          pip install black flake8 mypy          
      
      - name: Black formatting check
        run: black --check src/ tests/
      
      - name: Flake8
        run: flake8 src/ tests/
      
      - name: MyPy
        run: mypy src/

Armadilhas Comuns e Soluções

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

Problema: Pacote instalado mas importações falham

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

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

Problema 2: Dependências Ausentes

Problema: Pacote instala mas falha em tempo de execução devido a dependências ausentes

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

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

Problema 3: Conflitos de Versão

Problema: Pacote funciona no desenvolvimento mas falha em produção

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

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

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

Problema 4: Tamanho do Pacote Grande

Problema: 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 de Plataforma

Problema: Pacote funciona em um OS mas falha em outro

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

Checklist de Publicação

Antes de publicar seu pacote no PyPI, verifique:

  • Todos os testes passam em versões Python
  • Código está formatado e lintado
  • README.md está completo com exemplos
  • Arquivo LICENSE está incluído
  • Número de versão está atualizado
  • CHANGELOG.md está atualizado
  • Dependências estão especificadas corretamente
  • Pacote constrói sem erros (python -m build)
  • Pacote testado no TestPyPI
  • Documentação está atualizada
  • Repositório Git está taggeado com versão
  • Lançamento do GitHub é 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='World', help='Name to greet')
def main(name):
    """Exemplo simples de ferramenta CLI"""
    click.echo(f'Olá, {name}!')

if __name__ == '__main__':
    main()

Para um exemplo real de criação de pacotes Python que interagem com APIs externas, consulte nosso guia sobre Integração do Ollama com Python, que demonstra a construção de clientes Python com integrações de API REST e biblioteca oficial.

Sistemas de Plugin

Habilite 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 versões Python
  • nox: Automação de testes flexível (alternativa ao tox)
  • pre-commit: Framework de ganchos Git para qualidade de código
  • commitizen: Padronize mensagens de commit e versionamento

Plataformas de Documentação

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

Registros 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 privada de pacotes

Monitoramento e Análise

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

Conclusão

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

Pontos principais:

  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 o versionamento semântico e mantenha changelogs
  6. Forneça documentação abrangente e exemplos

O ecossistema de empacotamento Python continua a melhorar com melhores 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 mantíveis.

Outros Artigos Úteis neste Site