Declarando os metadados do projeto

A PEP 621 especifica como escrever metadados principais de um projeto em um arquivo pyproject.toml para ferramentas relacionadas ao empacotamento consumirem. Ele define a seguinte especificação como a fonte canônica para o formato usado.

Especificação

Existem dois tipos de metadados: estáticos e dinâmicos. Metadados estáticos são especificados diretamente no arquivo pyproject.toml e não podem ser especificados ou alterados por uma ferramenta. Os metadados dinâmicos são listados por meio da chave dynamic (definido posteriormente nesta especificação) e representam os metadados que uma ferramenta fornecerá posteriormente.

As chaves definidas nesta especificação DEVEM estar em uma tabela chamada [project] no arquivo pyproject.toml. Nenhuma ferramenta pode adicionar chaves a esta tabela que não sejam definidas por esta especificação. Para ferramentas que desejam armazenar suas próprias configurações em pyproject.toml, elas podem usar a tabela [tool] conforme definido na especificação da declaração de dependências de construção. A falta de uma tabela [project] implicitamente significa que o backend da construção fornecerá dinamicamente todas as chaves.

As únicas chaves que precisam ser definidos estaticamente são:

  • name

As chaves que são obrigatórias, mas podem ser especificadas estaticamente ou listadas como dinâmicas são:

  • version

Todas as outras chaves são consideradas opcionais e podem ser especificadas estaticamente, listadas como dinâmicas ou não especificadas.

A lista completa de chaves permitidas na tabela [project] são:

  • authors

  • classifiers

  • dependencies

  • description

  • dynamic

  • entry-points

  • gui-scripts

  • keywords

  • license

  • maintainers

  • name

  • optional-dependencies

  • readme

  • requires-python

  • scripts

  • urls

  • version

name

O nome do projeto.

Tools SHOULD normalize this name, as soon as it is read for internal consistency.

[project]
name = "spam"

version

A versão do projeto conforme suportado pela PEP 440.

Os usuários DEVEM preferir especificar versões já normalizadas.

[project]
version = "2020.0.0"

description

A descrição resumida do projeto.

[project]
description = "Lovely Spam! Wonderful Spam!"

readme

A descrição completa do projeto (isto é, o README).

A chave aceita uma string ou uma tabela. Se for uma string, então é um caminho relativo ao pyproject.toml para um arquivo texto contendo a descrição completa. As ferramentas DEVEM presumir que a codificação do arquivo é UTF-8. Se o caminho do arquivo termina com um sufixo .md, ou sua versão em caixa alta, então as ferramentas DEVEM presumir que o tipo de conteúdo é text/markdown. Se o caminho do arquivo termina em .rst, então as ferramentas DEVEM presumir que o tipo de conteúdo é text/x-rst. Se uma ferramenta reconhece mais extensões do que esta PEP, elas podem inferir o tipo de conteúdo para o usuário sem especificar esta chave como dynamic. Para todos os sufixos não reconhecidos quando um tipo de conteúdo não é fornecido, as ferramentas DEVEM levantar um erro.

A chave readme também pode receber uma tabela. A chave file tem um valor string que representa um caminho relativo a pyproject.toml para um arquivo contendo a descrição completa. A chave text tem um valor de string que é a descrição completa. Essas chaves são mutuamente exclusivas, portanto, as ferramentas DEVEM levantar um erro se os metadados especificarem ambas as chaves.

Uma tabela especificada na chave readme também possui uma chave content-type que recebe uma string especificando o tipo de conteúdo da descrição completa. Uma ferramenta DEVE levantar um erro se os metadados não especificarem esse campo na tabela. Se os metadados não especificarem o parâmetro charset, será considerado UTF-8. As ferramentas PODEM oferecer suporte a outras codificações, se assim o desejarem. As ferramentas PODEM oferecer suporte a tipos de conteúdo alternativos que podem transformar em um tipo de conteúdo conforme suportado pelos metadados principais. Caso contrário, as ferramentas DEVEM levantar um erro para tipos de conteúdo não suportados.

[project]
# A single pyproject.toml file can only have one of the following.
readme = "README.md"
readme = "README.rst"
readme = {file = "README.txt", content-type = "text/markdown"}

requires-python

Os requisitos de versão do Python do projeto.

[project]
requires-python = ">=3.8"

license

A tabela pode ter uma de duas chaves. A chave file tem um valor de string que é um caminho de arquivo relativo a pyproject.toml para o arquivo que contém a licença do projeto. As ferramentas DEVEM presumir que a codificação do arquivo é UTF-8. A chave text tem um valor de string que é a licença do projeto. Essas chaves são mutuamente exclusivas, portanto, uma ferramenta DEVE levantar um erro se os metadados especificarem ambas as chaves.

[project]
# A single pyproject.toml file can only have one of the following.
license = {file = "LICENSE"}
license = {text = "MIT License"}

authors/maintainers

As pessoas ou organizações consideradas “autoras” do projeto. O significado exato está aberto à interpretação – pode listar os autores originais ou primários, mantenedores atuais ou proprietários do pacote.

A chave “maintainers” é semelhante a “authors” no sentido de que seu significado exato está aberto à interpretação.

Estas chaves aceitam um vetor de tabelas com 2 chaves: name e email. Ambos os valores devem ser strings. O valor name DEVE ser um nome de e-mail válido (ou seja, o que quer que possa ser colocado como um nome, antes de um e-mail, em RFC 822) e não conter vírgulas. O valor email DEVE ser um endereço de email válido. Ambas as chaves são opcionais, mas ao menos uma das chaves deve ser especificada na tabela.

O uso dos dados para preencher metadados principais deve ser feito da seguinte forma:

  1. Se somente name for fornecido, o valor vai em Author ou Maintainer conforme apropriado.

  2. Se somente email é fornecido, o valor vai em Author-email ou Maintainer-email conforme apropriado.

  3. Se email e name são fornecidos, o valor vai em Author-email ou Maintainer-email conforme apropriado, com o formado {name} <{email}>.

  4. Vários valores devem ser separados por vírgulas.

[project]
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@python.org"}
]

keywords

As palavras-chave do projeto.

[project]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]

classifiers

Classificadores Trove que se aplicam ao projeto.

classifiers = [
  "Development Status :: 4 - Beta",
  "Programming Language :: Python"
]

urls

Uma tabela de URLs onde a chave é o rótulo da URL e o valor é a URL em si.

[project.urls]
homepage = "https://example.com"
documentation = "https://readthedocs.org"
repository = "https://github.com/me/spam.git"
changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"

Pontos de entrada

Existem três tabelas relacionadas aos pontos de entrada. A tabela [project.scripts] corresponde ao grupo console_scripts na especificação de pontos de entrada. A chave da tabela é o nome do ponto de entrada e o valor é a referência do objeto.

A tabela [project.gui-scripts] corresponde ao grupo gui_scripts na especificação de pontos de entrada. Seu formato é o mesmo que [project.scripts].

A tabela [project.entry-points] é uma coleção de tabelas. O nome de cada subtabela é um grupo de pontos de entrada. A chave e a semântica do valor são iguais a [project.scripts]. Os usuários NÃO DEVEM criar subtabelas aninhadas, mas sim manter os grupos de pontos de entrada em apenas um nível de profundidade.

Backends de construção DEVEM levantar um erro se os metadados definem uma tabela [project.entry-points.console_scripts] ou [project.entry-points.gui_scripts], pois elas seriam ambíguas perante [project.scripts] e [project.gui-scripts], respectivamente.

[project.scripts]
spam-cli = "spam:main_cli"

[project.gui-scripts]
spam-gui = "spam:main_gui"

[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"

dependencies/optional-dependencies

As dependências (opcionais) do projeto.

Para dependencies, é uma chave cujo valor é um array de strings. Cada string representa uma dependência do projeto e DEVE ser formatada como uma string válida PEP 508. Cada string mapeia diretamente para um Requires-Dist.

Para optional-dependencies, é uma tabela onde cada chave especifica um extra e cujo valor é um vetor de strings. As strings dos vetores devem ser strings válidas da PEP 508. As chaves DEVEM ser valores válidos para Provides-Extra. Cada valor no vetor torna-se assim uma entrada correspondente de Requer-Dist para os metadados correspondentes de Provides-Extra.

[project]
dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]

[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
  "rich",
  "click",
]

dynamic

Especifica quais chaves listadas por esta PEP foram intencionalmente não especificadas para que outra ferramenta possa/vai fornecer tais metadados dinamicamente. Isso delineia claramente quais metadados são propositalmente não especificados e espera-se que permaneçam não especificados em comparação a serem fornecidos por meio de ferramentas posteriormente.

  • Um backend de construção DEVE respeitar metadados especificados estaticamente (o que significa que os metadados não listam a chave em dynamic).

  • Um backend de construção DEVE gerar um erro se os metadados especificarem name em dynamic.

  • Se a especificação de metadados principais lista um campo como “Required”, então os metadados DEVEM especificar a chave estaticamente ou listá-la em dynamic (backends de construção DEVEM gerar um erro, caso contrário , ou seja, não deve ser possível que uma chave obrigatória não seja listada de alguma forma na tabela [project]).

  • Se a especificação de metadados principais listar um campo como “Optional”, os metadados PODEM listá-lo em dynamic se a expectativa for um backend de construção fornecerá os dados para a chave mais tarde.

  • Os backends de construção DEVEM levantar um erro se os metadados especificarem uma chave estaticamente, além de serem listados em dynamic.

  • Se os metadados não listam uma chave em dynamic, então um backend de construção NÃO PODE preencher os metadados necessários em nome do usuário (ou seja, dynamic é a única maneira de permitir que uma ferramenta preencha metadados e o usuário deve optar pelo preenchimento).

  • Os backends de construção DEVEM levantar um erro se os metadados especificarem uma chave em dynamic, mas o backend de construção não foi capaz de determinar os dados para ele (omitir os dados, se determinado como o valor exato, é aceitável) .

dynamic = ["version", "description", "optional-dependencies"]

Exemplo

[project]
name = "spam"
version = "2020.0.0"
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
requires-python = ">=3.8"
license = {file = "LICENSE.txt"}
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
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@python.org"}
]
classifiers = [
  "Development Status :: 4 - Beta",
  "Programming Language :: Python"
]

dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]

# dynamic = ["version", "description"]

[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"
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"