Ambientes Virtuais e Empacotamento em Python
Lição 6 de 15 · Conteúdo aberto
Ambientes Virtuais e Empacotamento em Python
Este guia cobre criação de ambientes isolados, instalação de dependências, organização de projetos e empacotamento com setuptools e poetry.
Sumário
- Objetivo
- Por Que Usar Ambiente Virtual
- Venv
- Virtualenv
- Pip e Requirements
- Pyproject.toml
- Setuptools
- Poetry
- Estrutura Profissional de Projeto
- Scripts e Entry Points
- Publicação e Versionamento
- Boas Práticas
- Nível Avançado: Projetos Reprodutíveis e Pacotes Profissionais
- Armadilhas de Especialista
- Checklist de Proficiência
- Exercícios
Objetivo
Ao final, você deve saber:
- criar ambientes isolados;
- instalar e congelar dependências;
- entender
requirements.txtepyproject.toml; - estruturar projeto empacotável;
- configurar
setuptools; - usar
poetry; - criar comandos executáveis;
- versionar pacotes.
Por Que Usar Ambiente Virtual
Ambiente virtual isola dependências por projeto.
Sem isolamento:
- projetos diferentes podem exigir versões incompatíveis;
- atualizações quebram projetos antigos;
- fica difícil reproduzir ambiente.
Com isolamento:
- cada projeto tem suas próprias dependências;
- instalação fica controlada;
- o ambiente é mais previsível.
Venv
Criar ambiente:
python -m venv .venv
Ativar no macOS/Linux:
source .venv/bin/activate
Ativar no Windows PowerShell:
.\.venv\Scripts\Activate.ps1
Verificar Python:
which python
python --version
Desativar:
deactivate
Virtualenv
virtualenv é uma alternativa mais antiga e ainda usada em alguns fluxos.
Instalação:
python -m pip install virtualenv
Criação:
virtualenv .venv
Na maioria dos projetos modernos, venv já é suficiente.
Pip e Requirements
Instalar pacote:
python -m pip install requests
Listar pacotes:
python -m pip list
Gerar requirements.txt:
python -m pip freeze > requirements.txt
Instalar a partir de requirements.txt:
python -m pip install -r requirements.txt
Exemplo:
requests==2.32.3
pydantic==2.8.2
pytest==8.3.2
Para aplicações, fixar versões aumenta reprodutibilidade.
Para bibliotecas, evite travar dependências de forma rígida demais.
Pyproject.toml
pyproject.toml centraliza metadados, build system e configuração de ferramentas.
Exemplo mínimo:
[project]
name = "meu-pacote"
version = "0.1.0"
description = "Pacote Python de exemplo"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"requests>=2.32",
]
[project.optional-dependencies]
dev = [
"pytest>=8",
"ruff>=0.6",
"mypy>=1.11",
]
Setuptools
Estrutura:
meu-pacote/
pyproject.toml
README.md
src/
meu_pacote/
__init__.py
calculos.py
tests/
test_calculos.py
pyproject.toml:
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "meu-pacote"
version = "0.1.0"
description = "Exemplo com setuptools"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[tool.setuptools.packages.find]
where = ["src"]
Instalação em modo editável:
python -m pip install -e .
Com dependências de desenvolvimento:
python -m pip install -e ".[dev]"
Build:
python -m pip install build
python -m build
Poetry
Poetry gerencia dependências, ambiente e build.
Criar projeto:
poetry new meu-pacote
Iniciar em projeto existente:
poetry init
Adicionar dependência:
poetry add requests
Adicionar dependência de desenvolvimento:
poetry add --group dev pytest ruff mypy
Instalar:
poetry install
Executar comando:
poetry run pytest
Abrir shell:
poetry shell
Build:
poetry build
Estrutura Profissional de Projeto
projeto/
.venv/
src/
app/
__init__.py
main.py
config.py
services.py
tests/
test_services.py
pyproject.toml
README.md
.gitignore
Por que usar src/:
- evita imports acidentais do diretório raiz;
- aproxima ambiente local do pacote instalado;
- melhora confiabilidade de testes.
Scripts e Entry Points
Com pyproject.toml:
[project.scripts]
meu-comando = "app.main:main"
Código:
def main() -> None:
print("Executando aplicação")
Depois de instalar:
meu-comando
Publicação e Versionamento
Versionamento semântico:
MAJOR.MINOR.PATCH
PATCH: correção compatível;MINOR: funcionalidade compatível;MAJOR: mudança incompatível.
Antes de publicar:
- rode testes;
- rode lint;
- confira metadados;
- confira README;
- gere build limpo;
- publique primeiro em ambiente de teste quando possível.
Boas Práticas
- Use
.venvlocal no projeto. - Não versione
.venv. - Versione
pyproject.toml. - Para aplicações, use lock file quando possível.
- Para bibliotecas, declare faixas compatíveis de dependência.
- Use
python -m pipem vez depipsolto. - Prefira estrutura
src/para pacotes. - Automatize comandos com
Makefile,taskipy,noxoutoxquando o projeto crescer. - Documente como instalar e rodar o projeto no
README.md.
Nível Avançado: Projetos Reprodutíveis e Pacotes Profissionais
Especialistas não apenas criam ambientes. Eles garantem que o projeto possa ser instalado, testado, empacotado e mantido por outras pessoas.
Aplicação vs biblioteca
Aplicação:
- deploya um sistema final;
- deve ter versões travadas;
- usa lock file;
- prioriza reprodutibilidade.
Biblioteca:
- será usada por outros projetos;
- deve declarar faixas de compatibilidade;
- evita pins rígidos;
- prioriza interoperabilidade.
Dependências opcionais
[project.optional-dependencies]
dev = [
"pytest>=8",
"ruff>=0.6",
"mypy>=1.11",
]
postgres = [
"psycopg[binary]>=3.2",
]
excel = [
"openpyxl>=3.1",
]
Instalação:
python -m pip install -e ".[dev,postgres]"
Configuração de ferramentas no pyproject.toml
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.mypy]
python_version = "3.12"
disallow_untyped_defs = true
warn_return_any = true
Centralizar configurações reduz arquivos soltos e melhora manutenção.
Builds isolados
python -m pip install build
python -m build
Gera:
sdist: distribuição fonte;wheel: distribuição construída.
Testando instalação real
Um pacote pode passar nos testes localmente e falhar instalado. Teste em ambiente limpo:
python -m venv /tmp/teste-pacote
source /tmp/teste-pacote/bin/activate
python -m pip install dist/meu_pacote-0.1.0-py3-none-any.whl
python -c "import meu_pacote; print(meu_pacote.__version__)"
Versionamento em pacote
Exponha versão:
__version__ = "0.1.0"
Ou use metadados:
from importlib.metadata import version
__version__ = version("meu-pacote")
CLI profissional
import argparse
def main(argv=None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("nome")
args = parser.parse_args(argv)
print(f"Olá, {args.nome}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Esse padrão facilita teste:
def test_main(capsys):
codigo = main(["Ana"])
saida = capsys.readouterr()
assert codigo == 0
assert "Ana" in saida.out
Automação com Nox
import nox
@nox.session
def tests(session):
session.install("-e", ".[dev]")
session.run("pytest")
@nox.session
def lint(session):
session.install("ruff")
session.run("ruff", "check", ".")
nox ajuda a padronizar tarefas em ambientes isolados.
Supply chain e segurança
Boas práticas:
- revise dependências diretas;
- remova dependências não usadas;
- use lock file em aplicações;
- atualize pacotes com rotina;
- rode auditoria quando possível;
- evite instalar pacotes desconhecidos sem verificar origem;
- prefira tokens com escopo limitado para publicação.
Armadilhas de Especialista
Misturar dependências de app e biblioteca
Aplicações podem travar versões. Bibliotecas devem permitir faixas compatíveis.
Empacotar sem src/
Projetos sem src/ podem mascarar problemas de import durante testes.
Publicar pacote sem testar wheel
Sempre teste o pacote instalado, não apenas o código no diretório.
CLI que chama sys.exit dentro da lógica
Mantenha sys.exit na borda. Retorne código de saída da função main.
Checklist de Proficiência
- Sei criar ambientes reprodutíveis.
- Sei diferenciar dependências de produção, desenvolvimento e opcionais.
- Sei configurar
pyproject.toml. - Sei empacotar com
setuptoolsou Poetry. - Sei criar entry points.
- Sei testar instalação real de wheel.
- Sei estruturar projeto com
src/. - Sei automatizar testes, lint e type check.
- Sei aplicar versionamento semântico.
- Sei avaliar riscos de dependências.
Ampliação de Proficiência
Ambiente reproduzível
Um projeto profissional deve responder:
- qual versão de Python usa;
- como criar o ambiente;
- como instalar dependências;
- como rodar a aplicação;
- como rodar testes;
- como empacotar, se necessário.
Essas respostas normalmente ficam no README.md e no pyproject.toml.
Requirements versus pyproject
requirements.txt é simples e útil para aplicações pequenas.
pyproject.toml é melhor quando o projeto precisa centralizar metadados, dependências, build e ferramentas.
Projetos podem usar ambos, mas evite duplicar fonte de verdade sem necessidade.
Dependência direta e transitiva
Dependência direta é a que você escolheu instalar.
Dependência transitiva é instalada porque uma dependência direta precisa dela.
Exemplo:
seu-projeto -> requests -> urllib3
Você deve declarar dependências diretas. Ferramentas de lock ajudam a congelar todo o grafo.
Versionamento semântico
Formato comum:
MAJOR.MINOR.PATCH
PATCH: correção compatível;MINOR: funcionalidade compatível;MAJOR: mudança incompatível.
Mini-checklist de domínio
- Sei criar e ativar
.venv. - Sei instalar dependências sem afetar o Python global.
- Sei explicar
requirements.txtepyproject.toml. - Sei instalar pacote em modo editável.
- Sei criar estrutura
src/. - Sei documentar comandos básicos do projeto.
- Sei diferenciar aplicação, biblioteca e pacote distribuível.
Exercícios
- Crie um ambiente virtual com
venv. - Instale
requestse gererequirements.txt. - Recrie o ambiente a partir de
requirements.txt. - Crie um projeto com estrutura
src/. - Configure
pyproject.tomlcomsetuptools. - Instale o projeto em modo editável.
- Crie um script de linha de comando com
[project.scripts]. - Crie um projeto com Poetry.
- Adicione dependências de produção e desenvolvimento.
- Gere um build do pacote.
Aprofundamento Complementar
Aplicação versus biblioteca
Aplicação é executada para entregar um comportamento final: CLI, API, automação, dashboard.
Biblioteca é importada por outro código para oferecer funcionalidades reutilizáveis.
Essa diferença muda decisões de dependência, versionamento e empacotamento.
Estrutura src
projeto/
├── pyproject.toml
├── src/
│ └── meu_pacote/
│ └── __init__.py
└── tests/
A estrutura src evita que testes importem acidentalmente arquivos locais sem instalação correta.
Dependências opcionais
[project.optional-dependencies]
dev = ["pytest", "ruff", "mypy"]
excel = ["openpyxl", "xlsxwriter"]
Isso permite instalar apenas o necessário:
python -m pip install -e ".[dev]"
Arquivos que não devem ir para o repositório
Normalmente não versionar: .venv/, __pycache__/, .pytest_cache/, arquivos .pyc, segredos, builds locais e dados sensíveis.
Exercícios extras
- Crie um projeto com estrutura
src. - Configure dependências opcionais
dev. - Instale o pacote em modo editável.
- Crie um
.gitignoreadequado. - Escreva no README os comandos de setup, teste e execução.