Skip to content

Commit

Permalink
Move part part of PEP 517 to the pyproject.toml spec
Browse files Browse the repository at this point in the history
The description of the data format in pyproject.toml is now part of the
pyproject.toml spec, while how the build backend is used remains in the
build system interfaces spec.
  • Loading branch information
jeanas committed Nov 23, 2023
1 parent 40cbf91 commit 9f860c6
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 127 deletions.
79 changes: 2 additions & 77 deletions source/specifications/build-system-interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,83 +24,6 @@ combination of wheels and sdists. In a command like ``pip install
lxml==2.4.0``, pip is acting as an integration frontend.


Source trees
============

There is an existing, legacy source tree format involving
``setup.py``. We don't try to specify it further; its de facto
specification is encoded in the source code and documentation of
``distutils``, ``setuptools``, ``pip``, and other tools. We'll refer
to it as the ``setup.py``\-style.

Here we define a new style of source tree based around the
``pyproject.toml`` file defined in :pep:`518`, extending the
``[build-system]`` table in that file with one additional key,
``build-backend``. Here's an example of how it would look::

[build-system]
# Defined by PEP 518:
requires = ["flit"]
# Defined by this PEP:
build-backend = "flit.api:main"

``build-backend`` is a string naming a Python object that will be
used to perform the build (see below for details). This is formatted
following the same ``module:object`` syntax as a ``setuptools`` entry
point. For instance, if the string is ``"flit.api:main"`` as in the
example above, this object would be looked up by executing the
equivalent of::

import flit.api
backend = flit.api.main

It's also legal to leave out the ``:object`` part, e.g. ::

build-backend = "flit.api"

which acts like::

import flit.api
backend = flit.api

Formally, the string should satisfy this grammar::

identifier = (letter | '_') (letter | '_' | digit)*
module_path = identifier ('.' identifier)*
object_path = identifier ('.' identifier)*
entry_point = module_path (':' object_path)?

And we import ``module_path`` and then lookup
``module_path.object_path`` (or just ``module_path`` if
``object_path`` is missing).

When importing the module path, we do *not* look in the directory containing the
source tree, unless that would be on ``sys.path`` anyway (e.g. because it is
specified in PYTHONPATH). Although Python automatically adds the working
directory to ``sys.path`` in some situations, code to resolve the backend should
not be affected by this.

If the ``pyproject.toml`` file is absent, or the ``build-backend``
key is missing, the source tree is not using this specification, and
tools should revert to the legacy behaviour of running ``setup.py`` (either
directly, or by implicitly invoking the ``setuptools.build_meta:__legacy__``
backend).

Where the ``build-backend`` key exists, this takes precedence and the source tree follows the format and
conventions of the specified backend (as such no ``setup.py`` is needed unless the backend requires it).
Projects may still wish to include a ``setup.py`` for compatibility with tools that do not use this spec.

This PEP also defines a ``backend-path`` key for use in ``pyproject.toml``, see
the "In-Tree Build Backends" section below. This key would be used as follows::

[build-system]
# Defined by PEP 518:
requires = ["flit"]
# Defined by this PEP:
build-backend = "local_backend"
backend-path = ["backend"]


Build requirements
==================

Expand Down Expand Up @@ -451,6 +374,8 @@ package *authors*, while still allowing *end-users* to open up the
hood and apply duct tape when necessary.


.. _in-tree-build-backends:

In-tree build backends
----------------------

Expand Down
173 changes: 123 additions & 50 deletions source/specifications/pyproject-toml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
The ``pyproject.toml`` file acts as a configuration file for packaging-related
tools (as well as other tools).

.. note:: This specification was originally defined in :pep:`518` and :pep:`621`.
.. note:: This specification was originally defined in :pep:`518`,
:pep:`517` and :pep:`621`.

The ``pyproject.toml`` file is written in `TOML <https://toml.io>`_. Three
tables are currently specified, namely
Expand All @@ -29,71 +30,100 @@ Declaring build system dependencies: the ``[build-system]`` table

The ``[build-system]`` table declares any Python level dependencies that
must be installed in order to run the project's build system
successfully.
successfully. The valid keys are ``requires``, ``build-backend`` and
``backend-path``.

.. TODO: merge with PEP 517
Tools should not require the existence of the ``[build-system]`` table.
A ``pyproject.toml`` file may be used to store configuration details
other than build-related data and thus lack a ``[build-system]`` table
legitimately.
If the table is specified but is missing required fields then the tool
should consider it an error.


``requires``
------------

The ``requires`` key must have a value of a list of strings representing
dependencies required to execute the build system [#requires-json-schema]_.
The strings in this list follow the :ref:`version specifier specification
<version-specifiers>`.

The ``[build-system]`` table is used to store build-related data.
Initially, only one key of the table is valid and is mandatory
for the table: ``requires``. This key must have a value of a list
of strings representing dependencies required to execute the
build system. The strings in this list follow the :ref:`version specifier
specification <version-specifiers>`.
This key is mandatory if the ``[build-system]`` table is present. If
the ``pyproject.toml`` file is missing, or exists but is lacking the
``[build-system]`` table, then ``requires`` defaults to ``["setuptools"]``.

An example ``[build-system]`` table for a project built with
``setuptools`` is:


``build-backend``
-----------------

The ``build-backend`` key is a string naming a Python object that will be
used to perform the build. This is formatted following the same
``module:object`` syntax as an :ref:`entry point <entry-points>`.
For instance, with the configuration

.. code-block:: toml
[build-system]
# Minimum requirements for the build system to execute.
requires = ["setuptools"]
requires = ["backend-name"]
build-backend = "backend_name.build_system:backend"
Build tools are expected to use the example configuration file above as
their default semantics when a ``pyproject.toml`` file is not present.
this object would be looked up by executing the equivalent of::

Tools should not require the existence of the ``[build-system]`` table.
A ``pyproject.toml`` file may be used to store configuration details
other than build-related data and thus lack a ``[build-system]`` table
legitimately. If the file exists but is lacking the ``[build-system]``
table then the default values as specified above should be used.
If the table is specified but is missing required fields then the tool
should consider it an error.
import backend_name.build
backend = backend_name.build_system.backend

It is also legal to leave out the ``:object`` part, e.g.

To provide a type-specific representation of the resulting data from
the TOML file for illustrative purposes only, the following
`JSON Schema <https://json-schema.org>`_ would match the data format:
.. code-block:: toml
.. code-block:: json
build-backend = "backend_name.build_system"
{
"$schema": "http://json-schema.org/schema#",
which acts like::

"type": "object",
"additionalProperties": false,
import backend_name.build_system
backend = backend_name.build_system

"properties": {
"build-system": {
"type": "object",
"additionalProperties": false,
Formally, the string should satisfy this grammar:

"properties": {
"requires": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["requires"]
},
.. code-block:: text
identifier = (letter | '_') (letter | '_' | digit)*
module_path = identifier ('.' identifier)*
object_path = identifier ('.' identifier)*
entry_point = module_path (':' object_path)?
The module specified by ``module_path`` is imported and the build
backend object is looked up using ``module_path.object_path`` (or
``module_path`` is directly used if ``object_path`` is missing).
See :ref:`build-system-interface` for how the build backend object
is used to perform the build.

When importing the module path, we do *not* look in the directory
containing the source tree, unless that would be on ``sys.path`` anyway
(e.g. because it is specified in PYTHONPATH). Although Python
automatically adds the working directory to ``sys.path`` in some
situations, code to resolve the backend should not be affected by this.

Unlike the ``requires`` key, the ``build-backend`` key is optional
[#build-backend-optional]_. If ``pyproject.toml`` is absent, or
the ``[build-system]`` table is missing, or it does not contain
the ``build-backend`` key, build frontends should revert to the legacy
behavior of running ``setup.py`` (either directly, or implicitly by
invoking the ``setuptools.build_meta:__legacy__`` backend).


``backend-path``
----------------

This key is for use by projects wishing to include their build backend
directly in their source tree, such as build backends themselves. If
provided, it must be a list of directories, which are prepended to
``sys.path`` during the build. For details, see
:ref:`in-tree-build-backends` in the build system interface
specification.

"tool": {
"type": "object"
}
}
}


.. _pyproject-project-table:
Expand Down Expand Up @@ -441,8 +471,51 @@ History
=======

This specification was originally defined in :pep:`518` (``[build-system]``
and ``[tool]`` tables) and :pep:`621` (``[project]`` table).
and ``[tool]`` tables), :pep:`517` (``build-backend`` and ``backend-path``
in the ``[build-system]`` table), and :pep:`621` (``[project]`` table).


--------------------------------------------------------------------------

.. [#requires-json-schema] The following `JSON Schema <json-schema_>`_ was
originally provided, for illustrative purposes only, and has not been
updated:
.. code-block:: json
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"build-system": {
"type": "object",
"additionalProperties": false,
"properties": {
"requires": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["requires"]
},
"tool": {
"type": "object"
}
}
}
.. [#build-backend-optional] Historically, ``build-backend`` was defined
later than ``requires``, thus making ``build-backend`` optional is to
preserve backwards compatibility.
.. _TOML: https://toml.io
.. _json-schema: https://json-schema.org

0 comments on commit 9f860c6

Please sign in to comment.