[!NOTE] Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.
pyproject.toml Guia: Empacotamento em Python, Dependências e Configuração de Ferramentas
Projetos Python mais antigos costumam distribuir a configuração por todo o setup.py, setup.cfg, ficheiros de requisitos, MANIFEST.ine arquivos separados para as ferramentas de desenvolvimento. pyproject.toml fornece um local comum para abordar essas preocupações, embora não substitua cada ficheiro de projeto nem torne cada secção parte de um padrão único.
Este guia explora o ficheiro, desde a configuração de compilação até aos metadados do projeto e às definições das ferramentas. A forma mais simples de o manter compreensível é separar as responsabilidades em quatro áreas distintas: o que compila o projeto, o que o projeto publica, o que os colaboradores necessitam localmente e o que as ferramentas individuais configuram.
TL;DR. Utilize
[build-system]para o backend que constrói uma distribuição,[project]para metadados publicados e os requisitos de runtime,[dependency-groups]para ambientes de desenvolvimento não publicados, e[tool.*]Apenas nos locais indicados na documentação daquela ferramenta. Uma declaração de dependência não é um ficheiro de bloqueio.
Um ficheiro, quatro proprietários
Três padrões de embalagem definiram a estrutura fundamental:
- PEP 518 define os requisitos do sistema de compilação. PEP 621 define a metadados do projeto. PEP 735 define grupos de dependências não publicados.
Os autores de ferramentas também podem reivindicar um espaço de nomes abaixo [tool]. Essa área é convencional, e não universal: cada ferramenta define as suas próprias chaves e comportamentos.
Esta é uma pequena biblioteca embalada:
[build-system]
requires = ["hatchling>=1.26"]
build-backend = "hatchling.build"
[project]
name = "weather-client"
version = "0.1.0"
description = "A small weather API client"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"httpx>=0.27",
]
[project.optional-dependencies]
cli = ["rich>=13"]
[project.scripts]
weather = "weather_client.cli:main"
[dependency-groups]
test = ["pytest>=8", "pytest-cov>=5"]
lint = ["ruff>=0.12"]
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.ruff]
line-length = 100
target-version = "py311"
Cada lista de dependências responde a uma pergunta diferente. Essa distinção é o elemento central do ficheiro.
[build-system]: como uma fonte se torna uma distribuição
Uma compilação frontend como python -m buildO pip ou o uv acionam um processo de compilação backend. O backend determina como a árvore de fontes é transformada num sdist ou num wheel, bem como quais ficheiros são incluídos nesses artefatos.
[build-system]
requires = ["hatchling>=1.26"]
build-backend = "hatchling.build"
requires Contém as dependências necessárias para executar o backend no seu ambiente de compilação isolado. Não faz parte da lista de dependências runtime do seu pacote.
Declare um sistema de compilação quando o projeto gera uma distribuição ou necessita que o seu próprio código seja instalado como um pacote. Um projeto que não é um pacote ainda pode utilizar pyproject.toml; O PEP 735 permite mesmo que um ficheiro contenha apenas grupos de dependências. Os gestores de ambiente diferem na forma como tratam um projeto sem sistema de compilação, pelo que deve tomar essa decisão de forma deliberada.
Escolha o backend entre os requisitos de compilação:
- requisitos de layout em Python puro e de seleção de ficheiros
- extensões compiladas ou sistemas de compilação externos
- necessidades de versão dinâmica ou de ficheiros gerados
- comportamento de instalação editável
- nível de backend de maturidade na versão pipeline
Copie a tabela atualmente recomendada pelo backend a partir da sua documentação. Não adicione nada. wheel Para definir os requisitos de forma habitual, o backend especifica quais são as necessidades.
[project]: os consumidores de metadados recebem
O [project] A tabela descreve a distribuição: o seu nome, versão, compatibilidade com Python, as dependências runtime, pontos de entrada e outros metadados do índice.
[project]
name = "weather-client"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["httpx>=0.27"]
Os especificadores de dependência são restrições para um resolvedor, e não uma representação de um ambiente específico. Eles passam a fazer parte dos metadados dos ficheiros wheel e sdist, permitindo que os instaladores subsequentes os combinem com as exigências de outros pacotes.
Os extras constituem uma interface de instalação pública
[project.optional-dependencies] define os recursos adicionais que os consumidores podem solicitar:
[project.optional-dependencies]
cli = ["rich>=13"]
postgres = ["psycopg[binary]>=3.2"]
Um utilizador final pode instalar weather-client[cli]. Como são publicados nomes e requisitos adicionais, trate-os como funcionalidades do produto. Não utilize um nome adicional dev Apenas para armazenar as ferramentas de cada colaborador.
Os pontos de entrada ligam os comandos instalados ao Python
[project.scripts]
weather = "weather_client.cli:main"
Após a instalação da distribuição, o ambiente torna acessíveis weather, que importa e chama weather_client.cli:main. Teste o comando a partir de um ficheiro wheel compilado, e não apenas a partir da raiz do repositório; é o wheel que os utilizadores recebem.
[dependency-groups]: ambientes locais e não publicados
Os grupos de dependências PEP 735 descrevem ambientes de desenvolvimento ou que não são pacotes, sem que estes sejam publicados como metadados de pacote.
[dependency-groups]
test = ["pytest>=8", "pytest-cov>=5"]
lint = ["ruff>=0.12"]
dev = [
{ include-group = "test" },
{ include-group = "lint" },
]
Este é o limite correto para testes, ferramentas de linting, geradores de documentação e outras ferramentas semelhantes destinadas a colaboradores. É também útil para aplicações ou notebooks que não criam uma distribuição.
Os grupos de dependências são dados padronizados, mas as interfaces dos instaladores continuam a variar. Verifique como o gestor de ambiente selecionado os instala, bloqueia e resolve. O PEP 735 não define uma interface de linha de comandos universal.
[tool.*]: configuração pertencente a uma ferramenta específica
As tabelas de ferramentas não partilham um esquema:
[tool.pytest.ini_options]
addopts = "-ra"
testpaths = ["tests"]
[tool.ruff]
line-length = 100
Utilizar um [tool.*] Uma tabela apenas se a ferramenta a documentar. Algumas definições continuam a estar nos seus próprios ficheiros porque outro ecossistema as consome, o ficheiro requer um formato diferente ou a configuração fica mais clara quando está isolada. pyproject.toml Trata‑se de um ponto de coordenação, e não de uma diretiva para centralizar tudo.
Declarações, bloqueios e ficheiros de requisitos resolvem problemas distintos
A fonte mais comum de confusão é tratar cada artefato de dependência como uma fonte de verdade concorrente.
| Artefato | Propósito principal | Conteúdos típicos |
|---|---|---|
[project.dependencies] | Contrato runtime publicado | Requisitos diretos e intervalos compatíveis |
[project.optional-dependencies] | Funcionalidades publicadas com consentimento prévio | Recursos adicionais direcionados ao consumidor |
[dependency-groups] | Ambientes locais não publicados | Testes, verificação de formato, documentação ou grupos de aplicações |
| Ficheiro de bloqueio | Reproduzir um ambiente resolvido | Versões exatas, fontes e metadados de resolução |
requirements.txt | entrada de instalação compatível com pip | Requisitos, opções específicas do pip, restrições, URLs ou hashes |
Uma biblioteca costuma publicar restrições e testes compatíveis para um determinado intervalo. Uma aplicação, por sua vez, geralmente guarda o ficheiro de bloqueio do gestor de ambiente. Os valores exatos devem constar no artefato de deploy finalizado, e não de forma aleatória nos metadados públicos da biblioteca.
Mantenha um ficheiro de requisitos sempre que uma integração exigir o formato ou funcionalidades do pip. Se um projeto gerido por uv precisar de um, exporte-o a partir do lock em vez de manter dois conjuntos de dependências independentes:
uv export --format requirements.txt --output-file requirements.txt
A exportação resulta de uma saída de compatibilidade. O “lock” continua a ser a versão original resolvida para esse fluxo de trabalho.
Uma migração que preserva o comportamento
Não comece por eliminar. setup.py ou requirements.txt. Primeiro, classifique a função de cada ficheiro existente.
- Lógica de construção do inventário, metadados, requisitos runtime, elementos adicionais, ambientes de desenvolvimento, configurações de ferramentas, dados de pacotes e pontos de entrada.
- Selecionar um backend capaz de reproduzir a inclusão atual de ficheiros, os artefatos compilados e as instalações editáveis.
- Mover os metadados estáticos publicados para
[project]; mantenha os campos verdadeiramente dinâmicos explícitos. - Mova os requisitos exclusivos para colaboradores para
[dependency-groups], sem recursos adicionais públicos. - Mova as definições da ferramenta apenas para locais onde ela suporta semânticas equivalentes.
- Crie tanto um sdist como um wheel, verifique o seu conteúdo e instale o wheel num ambiente limpo.
- Execute os pontos de entrada, os testes, as verificações de importação e o processo real de deploy.
- Elimine as configurações antigas somente após os artefatos e o comportamento corresponderem.
MANIFEST.in pode ainda ser necessário em alguns layouts do setuptools, e um pequeno setup.py pode permanecer válido para o comportamento de compilação programática. A modernização consiste numa mudança de propriedade, e não num processo de eliminação de ficheiros.
Um fluxo de trabalho atual para UV
uv diferencia as aplicações das bibliotecas ao criar um projeto:
# Non-library application template
uv init weather-app
# Packaged library with a src layout and build system
uv init --lib weather-client
uv init cria ficheiros de projeto. A primeira operação do projeto, como uv run, uv sync, ou uv lock cria o ficheiro de bloqueio e a persistência .venv conforme necessário.
cd weather-client
uv add httpx
uv add --group test pytest pytest-cov
uv run pytest
uv build
Atualmente, o uv organiza os requisitos de desenvolvimento local em grupos de dependências padronizados. O seu formato nativo uv_build backend é uma opção para projetos em Python puro; extensões compiladas exigem uma alternativa adequada, como o maturin ou o scikit-build-core.
Conclusão
pyproject.toml Fica claro quando cada tabela tem um público-alvo definido. É necessário implementar isolamento para esses públicos. [build-system]. O comportamento publicado pertence a [project]. Os ambientes dos colaboradores pertencem a [dependency-groups]. As alternâncias de ferramenta pertencem à ferramenta que as define.
Assim que esses limites se tornam estáveis, o ficheiro fica mais fácil de analisar — e as migrações deixam de confundir os metadados dos pacotes com o ambiente resolvido de uma determinada máquina.