Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions README.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussions-To: https://discuss.python.org/t/pep-621-round-3/5472
Status: Final
Type: Standards Track
Topic: Packaging
Created: 22-Jun-2020
Post-History: 22-Jun-2020,
18-Oct-2020,
24-Oct-2020,
31-Oct-2020
Resolution: https://discuss.python.org/t/pep-621-round-3/5472/109

.. canonical-pypa-spec:: :ref:packaging:pyproject-toml-spec

Abstract

This PEP specifies how to write a project's core metadata_ in a
pyproject.toml file for packaging-related tools to consume.

Motivation

The key motivators of this PEP are:

  • Encourage users to specify core metadata statically for speed,
    ease of specification, unambiguity, and deterministic consumption by
    build back-ends
  • Provide a tool-agnostic way of specifying metadata for ease of
    learning and transitioning between build back-ends
  • Allow for more code sharing between build back-ends for the
    "boring parts" of a project's metadata

To speak specifically to the motivation for static metadata, that has
been an overall goal of the packaging ecosystem for some time. As
such, making it easy to specify metadata statically is important. This
also means that raising the cost of specifying data as dynamic is
acceptable as users should skew towards wanting to provide static
metadata.

Requiring the distinction between static and dynamic metadata also
helps with disambiguation for when metadata isn't specified. When any
metadata may be dynamic, it means you never know if the absence of
metadata is on purpose or because it is to be provided later. By
requiring that dynamic metadata be specified, it disambiguates the
intent when metadata goes unspecified.

This PEP does not attempt to standardize all possible metadata
required by a build back-end, only the metadata covered by the
core metadata_ specification which are very common across projects
and would stand to benefit from being static and consistently
specified. This means build back-ends are still free and able to
innovate around patterns like how to specify the files to include in a
wheel. There is also an included escape hatch for users and build
back-ends to use when they choose to partially opt-out of this PEP
(compared to opting-out of this PEP entirely, which is also possible).

This PEP is also not trying to change the underlying core metadata_
in any way. Such considerations should be done in a separate PEP which
may lead to changes or additions to what this PEP specifies.

Rationale

The design guidelines the authors of this PEP followed were:

  • Define a representation of as much of the core metadata_ in
    pyproject.toml as is reasonable
  • Define the metadata statically with an escape hatch for those who
    want to define it dynamically later via a build back-end
  • Use familiar names where it makes sense, but be willing to use more
    modern terminology
  • Try to be ergonomic within a TOML file instead of mirroring how
    build back-ends specify metadata at a low-level when it makes sense
  • Learn from other build back-ends in the packaging ecosystem which
    have used TOML for their metadata
  • Don't try to standardize things which lack a pre-existing standard
    at a lower-level
  • When metadata is specified using this PEP, it is considered
    canonical

Specification

When specifying project metadata, tools MUST adhere and honour the
metadata as specified in this PEP. If metadata is improperly specified
then tools MUST raise an error to notify the user about their mistake.

Data specified using this PEP is considered canonical. Tools CANNOT
remove, add or change data that has been statically specified. Only
when a field is marked as dynamic may a tool provide a "new" value.

Details

Table name
''''''''''

Tools MUST specify fields defined by this PEP in a table named
[project]. No tools may add fields to this table which are not
defined by this PEP or subsequent PEPs. For tools wishing to store
their own settings in pyproject.toml, they may use the [tool]
table as defined in :pep:518. The lack of a [project] table
implicitly means the build back-end will dynamically provide all
fields.

name
''''''''

  • Format: string

  • Core metadata_: Name
    (link <https://packaging.python.org/specifications/core-metadata/#name>__)

  • Synonyms

    • Flit_: module/dist-name
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: name
      (link <https://python-poetry.org/docs/pyproject/#name>__)
    • Setuptools_: name
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The name of the project.

Tools MUST require users to statically define this field.

Tools SHOULD normalize this name, as specified by :pep:503, as soon
as it is read for internal consistency.

version
'''''''''''

  • Format: string

  • Core metadata_: Version
    (link <https://packaging.python.org/specifications/core-metadata/#version>__)

  • Synonyms

    • Flit_: N/A (read from a __version__ attribute)
      (link <https://flit.readthedocs.io/en/latest/index.html#usage>__)
    • Poetry_: version
      (link <https://python-poetry.org/docs/pyproject/#version>__)
    • Setuptools_: version
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The version of the project as supported by :pep:440.

Users SHOULD prefer to specify already-normalized versions.

description
'''''''''''''''

  • Format: string

  • Core metadata_: Summary
    (link <https://packaging.python.org/specifications/core-metadata/#summary>__)

  • Synonyms

    • Flit_: N/A
    • Poetry_: description
      (link <https://python-poetry.org/docs/pyproject/#description>__)
    • Setuptools_: description
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The summary description of the project.

readme
''''''''''

  • Format: String or table

  • Core metadata_: Description
    (link <https://packaging.python.org/specifications/core-metadata/#description>__)

  • Synonyms

    • Flit_: description-file
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: readme
      (link <https://python-poetry.org/docs/pyproject/#readme>__)
    • Setuptools_: long_description
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The full description of the project (i.e. the README).

The field accepts either a string or a table. If it is a string then
it is the relative path to a text file containing the full
description. Tools MUST assume the file's encoding is UTF-8. If the
file path ends in a case-insensitive .md suffix, then tools MUST
assume the content-type is text/markdown. If the file path ends in
a case-insensitive .rst, then tools MUST assume the content-type
is text/x-rst. If a tool recognizes more extensions than this PEP,
they MAY infer the content-type for the user without specifying this
field as dynamic. For all unrecognized suffixes when a
content-type is not provided, tools MUST raise an error.

The readme field may also take a table. The file key has a
string value representing a relative path to a file containing the
full description. The text key has a string value which is the
full description. These keys are mutually-exclusive, thus tools MUST
raise an error if the metadata specifies both keys.

A table specified in the readme field also has a content-type
field which takes a string specifying the content-type of the full
description. A tool MUST raise an error if the metadata does not
specify this field in the table. If the metadata does not specify the
charset parameter, then it is assumed to be UTF-8. Tools MAY
support other encodings if they choose to. Tools MAY support
alternative content-types which they can transform to a content-type
as supported by the core metadata_. Otherwise tools MUST raise an
error for unsupported content-types.

requires-python
'''''''''''''''''''

  • Format: string

  • Core metadata_: Requires-Python
    (link <https://packaging.python.org/specifications/core-metadata/#summary>__)

  • Synonyms

    • Flit_: requires-python
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: As a python dependency in the
      [tool.poetry.dependencies] table
      (link <https://python-poetry.org/docs/pyproject/#dependencies-and-dev-dependencies>__)
    • Setuptools_: python_requires
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The Python version requirements of the project.

license
'''''''''''

  • Format: Table

  • Core metadata_: License
    (link <https://packaging.python.org/specifications/core-metadata/#license>__)

  • Synonyms

    • Flit_: license
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: license
      (link <https://python-poetry.org/docs/pyproject/#license>__)
    • Setuptools_: license, license_file, license_files
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The table may have one of two keys. The file key has a string
value that is a relative file path to the file which contains the
license for the project. Tools MUST assume the file's encoding is
UTF-8. The text key has a string value which is the license of the
project whose meaning is that of the License field from the
core metadata_. These keys are mutually exclusive, so a tool MUST
raise an error if the metadata specifies both keys.

A practical string value for the license key has been purposefully
left out to allow for a future PEP to specify support for SPDX_
expressions (the same logic applies to any sort of "type" field
specifying what license the file or text represents).

authors/maintainers
'''''''''''''''''''''''''''

  • Format: Array of inline tables with string keys and values

  • Core metadata_: Author/Author-email/Maintainer/Maintainer-email
    (link <https://packaging.python.org/specifications/core-metadata/#author>__)

  • Synonyms

    • Flit_: author/author-email/maintainer/maintainer-email
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: authors/maintainers
      (link <https://python-poetry.org/docs/pyproject/#authors>__)
    • Setuptools_: author/author_email/maintainer/maintainer_email
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The people or organizations considered to be the "authors" of the
project. The exact meaning is open to interpretation — it may list the
original or primary authors, current maintainers, or owners of the
package.

The "maintainers" field is similar to "authors" in that its exact
meaning is open to interpretation.

These fields accept an array of tables with 2 keys: name and
email. Both values must be strings. The name value MUST be a
valid email name (i.e. whatever can be put as a name, before an email,
in :rfc:822) and not contain commas. The email value MUST be a
valid email address. Both keys are optional.

Using the data to fill in core metadata_ is as follows:

  1. If only name is provided, the value goes in
    Author/Maintainer as appropriate.
  2. If only email is provided, the value goes in
    Author-email/Maintainer-email as appropriate.
  3. If both email and name are provided, the value goes in
    Author-email/Maintainer-email as appropriate, with the
    format {name} <{email}> (with appropriate quoting, e.g. using
    email.headerregistry.Address).
  4. Multiple values should be separated by commas.

keywords
''''''''''''

  • Format: array of strings

  • Core metadata_: Keywords
    (link <https://packaging.python.org/specifications/core-metadata/#keywords>__)

  • Synonyms

    • Flit_: keywords
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: keywords
      (link <https://python-poetry.org/docs/pyproject/#keywords>_)
    • Setuptools_: keywords
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The keywords for the project.

classifiers
'''''''''''''''

  • Format: array of strings

  • Core metadata_: Classifier
    (link <https://packaging.python.org/specifications/core-metadata/#classifier-multiple-use>__)

  • Synonyms

    • Flit_: classifiers
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: classifiers
      (link <https://python-poetry.org/docs/pyproject/#classifiers>__)
    • Setuptools_: classifiers
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

Trove classifiers_ which apply to the project.

urls
''''''''

  • Format: Table, with keys and values of strings

  • Core metadata_: Project-URL
    (link <https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use>__)

  • Synonyms

    • Flit_: [tool.flit.metadata.urls] table
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: [tool.poetry.urls] table
      (link <https://python-poetry.org/docs/pyproject/#urls>__)
    • Setuptools_: project_urls
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

A table of URLs where the key is the URL label and the value is the
URL itself.

Entry points
''''''''''''

  • Format: Table ([project.scripts], [project.gui-scripts], and
    [project.entry-points])

  • Core metadata: N/A;
    Entry points specification

  • Synonyms

    • Flit_: [tool.flit.scripts] table for console scripts,
      [tool.flit.entrypoints] for the rest
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#scripts-section>__)
    • Poetry_: [tool.poetry.scripts] table for console scripts
      (link <https://python-poetry.org/docs/pyproject/#scripts>__)
    • Setuptools_: entry_points
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

There are three tables related to entry points. The
[project.scripts] table corresponds to the console_scripts
group in the entry points specification_. The key of the table is the name of the
entry point and the value is the object reference.

The [project.gui-scripts] table corresponds to the gui_scripts
group in the entry points specification_. Its format is the same as
[project.scripts].

The [project.entry-points] table is a collection of tables. Each
sub-table's name is an entry point group. The key and value semantics
are the same as [project.scripts]. Users MUST NOT create
nested sub-tables but instead keep the entry point groups to only one
level deep.

Build back-ends MUST raise an error if the metadata defines a
[project.entry-points.console_scripts] or
[project.entry-points.gui_scripts] table, as they would
be ambiguous in the face of [project.scripts] and
[project.gui-scripts], respectively.

dependencies/optional-dependencies
''''''''''''''''''''''''''''''''''''''''''

  • Format: Array of :pep:508 strings (dependencies) and a table
    with values of arrays of :pep:508 strings
    (optional-dependencies)

  • Core metadata_: Requires-Dist and Provides-Extra
    (link <https://packaging.python.org/specifications/core-metadata/#requires-dist-multiple-use>,
    link <https://packaging.python.org/specifications/core-metadata/#provides-extra-multiple-use>
    )

  • Synonyms

    • Flit_: requires for required dependencies, requires-extra
      for optional dependencies
      (link <https://flit.readthedocs.io/en/latest/pyproject_toml.html#metadata-section>__)
    • Poetry_: [tool.poetry.dependencies] for dependencies (both
      required and for development),
      [tool.poetry.extras] for optional dependencies
      (link <https://python-poetry.org/docs/pyproject/#dependencies-and-dev-dependencies>__)
    • Setuptools_: install_requires for required dependencies,
      extras_require for optional dependencies
      (link <https://setuptools.readthedocs.io/en/latest/setuptools.html#metadata>__)

The (optional) dependencies of the project.

For dependencies, it is a key whose value is an array of strings.
Each string represents a dependency of the project and MUST be
formatted as a valid :pep:508 string. Each string maps directly to
a Requires-Dist entry in the core metadata_.

For optional-dependencies, it is a table where each key specifies
an extra and whose value is an array of strings. The strings of the
arrays must be valid :pep:508 strings. The keys MUST be valid values
for the Provides-Extra core metadata_. Each value in the array
thus becomes a corresponding Requires-Dist entry for the matching
Provides-Extra metadata.

dynamic
'''''''''''

  • Format: Array of strings
  • Core metadata_: N/A
  • No synonyms

Specifies which fields listed by this PEP were intentionally
unspecified so another tool can/will provide such metadata
dynamically. This clearly delineates which metadata is purposefully
unspecified and expected to stay unspecified compared to being
provided via tooling later on.

  • A build back-end MUST honour statically-specified metadata (which
    means the metadata did not list the field in dynamic).
  • A build back-end MUST raise an error if the metadata specifies the
    name in dynamic.
  • If the core metadata_ specification lists a field as "Required",
    then the metadata MUST specify the field statically or list it in
    dynamic (build back-ends MUST raise an error otherwise, i.e. it
    should not be possible for a required field to not be listed somehow
    in the [project] table).
  • If the core metadata_ specification lists a field as "Optional",
    the metadata MAY list it in dynamic if the expectation is a
    build back-end will provide the data for the field later.
  • Build back-ends MUST raise an error if the metadata specifies a
    field statically as well as being listed in dynamic.
  • If the metadata does not list a field in dynamic, then a build
    back-end CANNOT fill in the requisite metadata on behalf of the user
    (i.e. dynamic is the only way to allow a tool to fill in
    metadata and the user must opt into the filling in).
  • Build back-ends MUST raise an error if the metadata specifies a
    field in dynamic but the build back-end was unable to provide the
    data for it.

Example

::

[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 = [
{email = "hi@pradyunsg.me"},
{name = "Tzu-ping Chung"}
]
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'"
]

[project.optional-dependencies]
test = [
"pytest < 5.0.0",
"pytest-cov[all]"
]

[project.urls]
homepage = "https://example.com"
documentation = "https://readthedocs.org"
repository = "https://github.com"
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"

Backwards Compatibility

As this prov

Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,9 @@ jobs:
git push
```

## Recommended permissions
*NOTE:* The user email is `{user.id}+{user.login}@users.noreply.github.com`. See users API: https://api.github.com/users/github-actions%5Bbot%5D

# Recommended permissions

When using the `checkout` action in your GitHub Actions workflow, it is recommended to set the following `GITHUB_TOKEN` permissions to ensure proper functionality, unless alternative auth is provided via the `token` or `ssh-key` inputs:

Expand All @@ -321,9 +323,6 @@ permissions:
contents: read
```

*NOTE:* The user email is `{user.id}+{user.login}@users.noreply.github.com`. See users API: https://api.github.com/users/github-actions%5Bbot%5D


# License

The scripts and documentation in this project are released under the [MIT License](LICENSE)