Voltar ao Glossario
Glossario Python

Pacote Python: O que É e Como Funciona | Python Brasil

Guia completo sobre pacotes Python: __init__.py, pyproject.toml, build, publicação no PyPI, versionamento semântico e registros privados.

O que é um Pacote Python?

Um pacote (package) em Python é uma forma de organizar módulos relacionados em uma estrutura de diretórios hierárquica. Na definição clássica, um pacote é um diretório que contém um arquivo __init__.py e um ou mais módulos (arquivos .py). O __init__.py sinaliza ao Python que aquele diretório deve ser tratado como um pacote e pode conter código de inicialização.

Pacotes permitem criar namespaces hierárquicos: você pode ter meu_app.models.usuario e meu_app.models.produto sem conflito de nomes.

A evolução do init.py

O __init__.py passou por mudanças importantes ao longo das versões do Python:

# Antes do Python 3.3: __init__.py era OBRIGATÓRIO
# meu_pacote/__init__.py precisava existir (mesmo vazio)

# Python 3.3+ introduziu "namespace packages" (PEP 420)
# Diretórios SEM __init__.py também podem ser importados
# Isso permite pacotes espalhados por múltiplos diretórios

# Quando usar __init__.py moderno:
# meu_pacote/__init__.py

# Expor a API pública do pacote
from .core import funcao_principal
from .utils import formatar, validar
from .models import Usuario, Produto

# Versão do pacote (acessível como meu_pacote.__version__)
__version__ = "2.1.0"

# Controlar o que é exportado com import *
__all__ = ["funcao_principal", "formatar", "Usuario", "Produto"]

Para pacotes de distribuição (que serão instalados via pip), sempre inclua o __init__.py. Para namespaces internos grandes em aplicações, pacotes implícitos podem simplificar a estrutura.

Estrutura de um pacote completo

meu_pacote/
├── src/
│   └── meu_pacote/
│       ├── __init__.py
│       ├── core.py
│       ├── utils.py
│       └── models/
│           ├── __init__.py
│           ├── usuario.py
│           └── produto.py
├── tests/
│   ├── __init__.py
│   ├── test_core.py
│   └── test_models.py
├── docs/
├── pyproject.toml
├── README.md
└── LICENSE

O layout src/ (conhecido como “src layout”) é a convenção recomendada atualmente, pois evita que o Python importe acidentalmente o código do diretório de trabalho em vez do pacote instalado.

pyproject.toml: o arquivo de configuração moderno

O pyproject.toml é o padrão atual (PEP 517, PEP 518, PEP 621) para configurar projetos e pacotes Python. Ele substituiu o setup.py e o setup.cfg:

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

[project]
name = "meu-pacote"
version = "1.0.0"
description = "Uma biblioteca Python para processamento de dados"
readme = "README.md"
license = { file = "LICENSE" }
authors = [
    { name = "Seu Nome", email = "voce@exemplo.com" }
]
keywords = ["dados", "processamento", "python"]
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]
requires-python = ">=3.9"
dependencies = [
    "requests>=2.28.0",
    "pydantic>=2.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "black>=23.0",
    "mypy>=1.0",
]

[project.urls]
Homepage = "https://github.com/usuario/meu-pacote"
Documentation = "https://meu-pacote.readthedocs.io"
Repository = "https://github.com/usuario/meu-pacote.git"

[project.scripts]
meu-comando = "meu_pacote.cli:main"

setup.py vs setup.cfg vs pyproject.toml

A evolução das ferramentas de empacotamento Python:

# setup.py — legado, mas ainda encontrado em projetos antigos
from setuptools import setup, find_packages

setup(
    name="meu-pacote",
    version="1.0.0",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    install_requires=["requests>=2.28.0"],
)

# setup.cfg — configuração declarativa (intermediário)
# [metadata]
# name = meu-pacote
# version = 1.0.0
#
# [options]
# install_requires =
#     requests>=2.28.0

# pyproject.toml — padrão atual recomendado
# (veja exemplo completo acima)

Para projetos novos, use exclusivamente pyproject.toml. Projetos legados com setup.py funcionam, mas a migração é recomendada.

Criando e usando o pacote localmente

# meu_pacote/core.py
def processar(dados: list) -> dict:
    """Processa uma lista de dados e retorna estatísticas."""
    if not dados:
        return {"total": 0, "media": 0}
    return {
        "total": len(dados),
        "soma": sum(dados),
        "media": sum(dados) / len(dados),
        "minimo": min(dados),
        "maximo": max(dados),
    }

# meu_pacote/models/usuario.py
from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class Usuario:
    nome: str
    email: str
    criado_em: datetime = field(default_factory=datetime.now)

    def __post_init__(self):
        if "@" not in self.email:
            raise ValueError(f"Email inválido: {self.email}")

# Instalar o pacote local em modo editável
# pip install -e .

# Usar o pacote
from meu_pacote import processar
from meu_pacote.models.usuario import Usuario

resultado = processar([10, 20, 30, 40, 50])
print(resultado)  # {'total': 5, 'soma': 150, 'media': 30.0, ...}

user = Usuario("Ana", "ana@exemplo.com")
print(user)  # Usuario(nome='Ana', email='ana@exemplo.com', ...)

Construindo o pacote para distribuição

Para gerar os arquivos de distribuição (wheel e sdist), use a ferramenta build:

# Instalar a ferramenta de build
pip install build

# Construir o pacote
python -m build

# Gera dois arquivos em dist/:
# dist/meu_pacote-1.0.0-py3-none-any.whl  (wheel — formato moderno)
# dist/meu_pacote-1.0.0.tar.gz              (sdist — código fonte)

Ferramentas alternativas de build com funcionalidades extras:

# Flit — simples, focado em pacotes Python puro
pip install flit
flit build

# Hatch — moderno, com gerenciamento de versões e ambientes
pip install hatch
hatch build

# Poetry — all-in-one: dependências + build + publish
poetry build

Publicando no PyPI passo a passo

# 1. Criar conta em pypi.org e test.pypi.org

# 2. Instalar twine (ferramenta de upload)
pip install twine

# 3. Testar primeiro no TestPyPI
twine upload --repository testpypi dist/*
# Instalar do TestPyPI para validar:
pip install --index-url https://test.pypi.org/simple/ meu-pacote

# 4. Publicar no PyPI oficial
twine upload dist/*
# Informe seu token de API do PyPI (recomendado sobre senha)

# 5. Qualquer pessoa pode instalar
pip install meu-pacote

Configure o token de API no ~/.pypirc para não digitar toda vez:

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

Registros privados de pacotes

Em ambientes corporativos, você pode hospedar pacotes internos em registros privados:

# Instalar do registro privado
pip install meu-pacote-interno \
    --extra-index-url https://usuario:senha@registry.empresa.com/simple/

# Publicar no registro privado com twine
twine upload \
    --repository-url https://registry.empresa.com/ \
    dist/*

# pip.conf para configurar o registro permanentemente
# [global]
# extra-index-url = https://token@registry.empresa.com/simple/

Soluções populares para registros privados: Artifactory (JFrog), Nexus (Sonatype), AWS CodeArtifact, Google Artifact Registry e o devpi (open source).

Versionamento semântico

Todo pacote publicado deve seguir o SemVer (Versionamento Semântico):

MAJOR.MINOR.PATCH
  2  .  1  .  3

MAJOR — mudanças incompatíveis com versões anteriores (breaking changes)
MINOR — novas funcionalidades compatíveis com versões anteriores
PATCH — correções de bugs compatíveis com versões anteriores

Exemplos:
1.0.0 → 1.0.1  (correção de bug)
1.0.1 → 1.1.0  (nova feature)
1.1.0 → 2.0.0  (breaking change)

Versões de pré-lançamento:
2.0.0-alpha.1
2.0.0-beta.1
2.0.0rc1       (release candidate — convenção do PyPI)

Pacotes vs Módulos

A diferença é objetiva: um módulo é um único arquivo .py, enquanto um pacote é um diretório com múltiplos módulos. Pacotes permitem organizar projetos grandes de forma hierárquica. Na prática, quando você instala algo via pip install, está instalando um pacote de distribuição (distribution package) — que pode conter múltiplos pacotes e módulos Python.

Termos Relacionados

  • Módulo - Unidade básica de organização de código
  • pip - Ferramenta para instalar pacotes
  • Python - A linguagem de programação