From 9f860c6e57ed3b761a8b46055a4d2a6776e1e415 Mon Sep 17 00:00:00 2001 From: Jean Abou Samra Date: Thu, 23 Nov 2023 00:46:47 +0100 Subject: [PATCH] Move part part of PEP 517 to the pyproject.toml spec 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. --- .../specifications/build-system-interface.rst | 79 +------- source/specifications/pyproject-toml.rst | 173 +++++++++++++----- 2 files changed, 125 insertions(+), 127 deletions(-) diff --git a/source/specifications/build-system-interface.rst b/source/specifications/build-system-interface.rst index 6b4b43133..781b8d797 100644 --- a/source/specifications/build-system-interface.rst +++ b/source/specifications/build-system-interface.rst @@ -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 ================== @@ -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 ---------------------- diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 21cd2340d..102e841af 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -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 `_. Three tables are currently specified, namely @@ -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 +`. -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 `. +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 `. +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 `_ 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: @@ -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 `_ 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