Escrevendo seu pyproject.toml
¶
pyproject.toml
é um arquivo de configuração usado por ferramentas de empacotamento, bem como outras ferramentas como linters, verificadores de tipo, etc. Existem três tabelas TOML possíveis neste arquivo.
A tabela
[build-system]
é altamente recomendada. Ela permite que você declare qual backend de construção você usa e quais outras dependências são necessárias para construir seu projeto.A tabela
[project]
é o formato que a maioria dos backends de construção usa para especificar os metadados básicos do seu projeto, como as dependências, seu nome, etc.A tabela
[tool]
possui subtabelas específicas da ferramenta, por exemplo,[tool.hatch]
,[tool.black]
,[tool.mypy]
. Tocamos aqui apenas nesta tabela porque seu conteúdo é definido por cada ferramenta. Consulte a documentação da ferramenta específica para saber o que ela pode conter.
Nota
The [build-system]
table should always be present,
regardless of which build backend you use ([build-system]
defines the
build tool you use).
On the other hand, the [project]
table is understood by most build
backends, but some build backends use a different format.
A notable exception is Poetry, which before version 2.0 (released January
5, 2025) did not use the [project]
table, it used the [tool.poetry]
table instead. With version 2.0, it supports both.
Also, the setuptools build backend supports both the [project]
table,
and the older format in setup.cfg
or setup.py
.
For new projects, use the [project]
table, and keep setup.py
only if
some programmatic configuration is needed (such as building C extensions),
but the setup.cfg
and setup.py
formats are still valid. See
setup.py foi descontinuado?.
Declarando o backend de construção¶
A tabela [build-system]
contém uma chave build-backend
, que especifica o backend de construção a ser usado. Ele também contém uma chave requires
, que é uma lista de dependências necessárias para construir o projeto – normalmente é apenas o pacote backend de construção, mas também pode conter dependências adicionais. Você também pode restringir as versões, por exemplo, requires = ["setuptools >= 61.0"]
.
Normalmente, você apenas copiará o que a documentação do seu backend de construção sugere (após escolher seu backend de construção). Aqui estão os valores para alguns backends de construção comuns:
[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"
[build-system]
requires = ["setuptools >= 77.0.3"]
build-backend = "setuptools.build_meta"
[build-system]
requires = ["flit_core >= 3.12.0, <4"]
build-backend = "flit_core.buildapi"
[build-system]
requires = ["pdm-backend >= 2.4.0"]
build-backend = "pdm.backend"
Metadados estáticos vs dinâmicos¶
O resto deste guia é dedicado à tabela [project]
.
Na maioria das vezes, você escreverá diretamente o valor de um campo [project]
. Por exemplo: requires-python = ">= 3.8"
, ou version = "1.0"
.
No entanto, em alguns casos, é útil permitir que o backend de construção calcule os metadados para você. Por exemplo: muitos backend sde construção podem ler a versão de um atributo __version__
em seu código, uma tag Git ou similar. Nesses casos, você deve marcar o campo como dinâmico usando, por exemplo,
[project]
dynamic = ["version"]
Quando um campo é dinâmico, é da responsabilidade do backend de construção preenchê-lo. Consulte a documentação do seu backend de construção para saber como ele faz.
Informações básicas¶
name
¶
Coloque o nome do seu projeto em PyPI. Este campo é necessário e é o único campo que não pode ser marcado como dinâmico.
[project]
name = "spam-eggs"
The project name must consist of ASCII letters, digits, underscores “_
”,
hyphens “-
” and periods “.
”. It must not start or end with an
underscore, hyphen or period.
A comparação de nomes de projetos não diferencia maiúsculas de minúsculas e trata sequências arbitrariamente longas de sublinhados, hífenes e/ou pontos como iguais. Por exemplo, se você registrar um projeto chamado cool-stuff
, os usuários poderão baixá-lo ou declarar uma dependência dele usando qualquer uma das seguintes formas de escrever: Cool-Stuff
, cool.stuff
, COOL_STUFF
, CoOl__-.-__sTuFF
.
version
¶
Coloque a versão do seu projeto.
[project]
version = "2020.0.0"
Alguns especificadores de versão mais complicados como 2020.0.0a1
(para uma versão alfa) são possíveis; veja a especificação para detalhes completos.
Este campo é necessário, embora muitas vezes seja marcado como dinâmico usando
[project]
dynamic = ["version"]
This allows use cases such as filling the version from a __version__
attribute or a Git tag. Consult the Mantendo uma única fonte da versão do pacote
discussion for more details.
Dependências e requisitos¶
dependencies
/optional-dependencies
¶
Se o seu projeto tiver dependências, liste-as assim:
[project]
dependencies = [
"httpx",
"gidgethub[httpx]>4.0.0",
"django>2.1; os_name != 'nt'",
"django>2.0; os_name == 'nt'",
]
Veja Especificadores de dependências para a sintaxe completa que você pode usar para restringir versões.
Você pode querer fazer algumas de suas dependências opcionais, se forem necessárias apenas para um recurso específico do seu pacote. Nesse caso, coloque-os em optional-dependencies
.
[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
"rich",
"click",
]
Cada uma das chaves define um “extra de empacotamento”. No exemplo acima, pode-se usar, por exemplo, pip install seu-projeto-de-nome[gui]
para instalar seu projeto com suporte GUI, adicionando a dependência PyQt5.
requires-python
¶
Isso permite que você declare a versão mínima de Python que você suporta [1].
[project]
requires-python = ">= 3.8"
Criando scripts executáveis¶
Para instalar um comando como parte do seu pacote, declare-o na tabela [project.scripts]
.
[project.scripts]
spam-cli = "spam:main_cli"
In this example, after installing your project, a spam-cli
command
will be available. Executing this command will do the equivalent of
import sys; from spam import main_cli; sys.exit(main_cli())
.
No Windows, scripts empacotados desta forma precisam de um terminal, então se você lançá-los de dentro de uma aplicação gráfica, eles vão fazer um pop up de terminal. Para evitar que isso aconteça, use o [project.gui-scripts]
tabela em vez de [project.scripts]
.
[project.gui-scripts]
spam-gui = "spam:main_gui"
Nesse caso, a inicialização do seu script a partir da linha de comando devolve o controle imediatamente, deixando o script a ser executado em segundo plano.
A diferença entre [project.scripts]
e [project.gui-scripts]
é apenas relevante no Windows.
Sobre o seu projeto¶
description
¶
Esta deve ser uma descrição de uma linha do seu projeto, para mostrar como o “título” da sua página do projeto no PyPI (exemplo), e outros lugares como listas de resultados de pesquisa (exemplo).
[project]
description = "Lovely Spam! Wonderful Spam!"
readme
¶
Esta é uma descrição mais longa do seu projeto, para exibir em sua página do projeto em PyPI. Tipicamente, seu projeto terá um arquivo README.md
ou README.rst
e você acabou de colocar seu nome de arquivo aqui.
[project]
readme = "README.md"
O formato do README é detectado automaticamente a partir da extensão:
README.md
→ Markdown no estilo do GitHub,README.rst
→ reStructuredText <rest>`_ (sem extensões do Sphinx).
Você também pode especificar o formato explicitamente assim:
[project]
readme = {file = "README.txt", content-type = "text/markdown"}
# or
readme = {file = "README.txt", content-type = "text/x-rst"}
license
and license-files
¶
As per PEP 639 licenses should be declared with two fields:
license
is an SPDX license expression consisting of one or more license identifiers.license-files
is a list of license file glob patterns.
A previous PEP had specified license
to be a table with a file
or a
text
key, this format is now deprecated. Most build backends now support the new format as shown in the following table.
hatchling |
setuptools |
flit-core [2] |
pdm-backend |
poetry-core |
---|---|---|---|---|
1.27.0 |
77.0.3 |
3.12 |
2.4.0 |
license
¶
The new format for license
is a valid SPDX license expression
consisting of one or more license identifiers.
The full license list is available at the
SPDX license list page. The supported list version is
3.17 or any later compatible one.
[project]
license = "GPL-3.0-or-later"
# or
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
Nota
If you get a build error that license
should be a dict/table,
your build backend doesn’t yet support the new format. See the
above section for more context.
The now deprecated format is described in PEP 621.
As a general rule, it is a good idea to use a standard, well-known license, both to avoid confusion and because some organizations avoid software whose license is unapproved.
If your project is licensed with a license that doesn’t have an existing SPDX
identifier, you can create a custom one in format LicenseRef-[idstring]
.
The custom identifiers must follow the SPDX specification,
clause 10.1 of the version 2.2 or any later compatible one.
[project]
license = "LicenseRef-My-Custom-License"
license-files
¶
This is a list of license files and files containing other legal information you want to distribute with your package.
[project]
license-files = ["LICEN[CS]E*", "vendored/licenses/*.txt", "AUTHORS.md"]
The glob patterns must follow the specification:
Alphanumeric characters, underscores (
_
), hyphens (-
) and dots (.
) will be matched verbatim.Special characters:
*
,?
,**
and character ranges: [] are supported.Path delimiters must be the forward slash character (
/
).Patterns are relative to the directory containing
pyproject.toml
, and thus may not start with a slash character.Parent directory indicators (
..
) must not be used.Each glob must match at least one file.
Literal paths are valid globs. Any characters or character sequences not covered by this specification are invalid.
keywords
¶
Isso ajudará a caixa de pesquisa do PyPI a sugerir o seu projeto quando as pessoas procuram essas palavras-chave.
[project]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers
¶
Uma lista de classificadores do PyPI que se aplicam ao seu projeto. Verifique a lista completa de possibilidades.
classifiers = [
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
"Development Status :: 4 - Beta",
# Indicate who your project is intended for
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
# Specify the Python versions you support here.
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
]
Although the list of classifiers is often used to declare what Python versions a project supports, this information is only used for searching and browsing projects on PyPI, not for installing projects. To actually restrict what Python versions a project can be installed on, use the requires-python argument.
To prevent a package from being uploaded to PyPI, use the special Private ::
Do Not Upload
classifier. PyPI will always reject packages with classifiers
beginning with Private ::
.
urls
¶
Uma lista de URLs associadas ao seu projeto, exibida na barra lateral esquerda da página do projeto PyPI.
Nota
See Well-known labels for a listing of labels that PyPI and other packaging tools are specifically aware of, and PyPI’s project metadata docs for PyPI-specific URL processing.
[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
Issues = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
Note that if the label contains spaces, it needs to be quoted, e.g.,
Website = "https://example.com"
but
"Official Website" = "https://example.com"
.
Users are advised to use Well-known labels for their project URLs where appropriate, since consumers of metadata (like package indices) can specialize their presentation.
For example in the following metadata, neither MyHomepage
nor
"Download Link"
is a well-known label, so they will be rendered verbatim:
[project.urls]
MyHomepage = "https://example.com"
"Download Link" = "https://example.com/abc.tar.gz"
Whereas in this metadata HomePage
and DOWNLOAD
both have
well-known equivalents (homepage
and download
), and can be presented
with those semantics in mind (the project’s home page and its external
download location, respectively).
[project.urls]
HomePage = "https://example.com"
DOWNLOAD = "https://example.com/abc.tar.gz"
Plugins avançados¶
Alguns pacotes podem ser estendidos através de plugins. Exemplos incluem Pytest e Pygments. Para criar tal plugin, você precisa declará-lo em uma subtabela de [project.entry-points]
assim:
[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"
Veja o guia Plugin para mais informações.
Um exemplo completo¶
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "spam-eggs"
version = "2020.0.0"
dependencies = [
"httpx",
"gidgethub[httpx]>4.0.0",
"django>2.1; os_name != 'nt'",
"django>2.0; os_name == 'nt'",
]
requires-python = ">=3.8"
authors = [
{name = "Pradyun Gedam", email = "pradyun@example.com"},
{name = "Tzu-Ping Chung", email = "tzu-ping@example.com"},
{name = "Another person"},
{email = "different.person@example.com"},
]
maintainers = [
{name = "Brett Cannon", email = "brett@example.com"}
]
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
license = "MIT"
license-files = ["LICEN[CS]E.*"]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python"
]
[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
"rich",
"click",
]
[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
"Bug Tracker" = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
[project.scripts]
spam-cli = "spam:main_cli"
[project.gui-scripts]
spam-gui = "spam:main_gui"
[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"