PEP 735: Dependency Groups in pyproject.toml (#3541)
Co-authored-by: James Webber <jamestwebber@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> Co-authored-by: Brett Cannon <brett@python.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Thomas Grainger <tagrain@gmail.com> Co-authored-by: chrysle <fritzihab@posteo.de>
This commit is contained in:
parent
66d1fc80bd
commit
1a089b850e
|
@ -612,6 +612,7 @@ peps/pep-0731.rst @gvanrossum @encukou @vstinner @zooba @iritkatriel
|
||||||
peps/pep-0732.rst @Mariatta
|
peps/pep-0732.rst @Mariatta
|
||||||
peps/pep-0733.rst @encukou @vstinner @zooba @iritkatriel
|
peps/pep-0733.rst @encukou @vstinner @zooba @iritkatriel
|
||||||
peps/pep-0734.rst @ericsnowcurrently
|
peps/pep-0734.rst @ericsnowcurrently
|
||||||
|
peps/pep-0735.rst @brettcannon
|
||||||
# ...
|
# ...
|
||||||
# peps/pep-0754.rst
|
# peps/pep-0754.rst
|
||||||
# ...
|
# ...
|
||||||
|
|
|
@ -0,0 +1,652 @@
|
||||||
|
PEP: 735
|
||||||
|
Title: Dependency Groups in pyproject.toml
|
||||||
|
Author: Stephen Rosen <sirosen0@gmail.com>
|
||||||
|
Sponsor: Brett Cannon <brett@python.org>
|
||||||
|
PEP-Delegate: Paul Moore <p.f.moore@gmail.com>
|
||||||
|
Discussions-To: https://discuss.python.org/t/39233
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Topic: Packaging
|
||||||
|
Created: 20-Nov-2023
|
||||||
|
Post-History: `14-Nov-2023 <https://discuss.python.org/t/29684>`__, `20-Nov-2023 <https://discuss.python.org/t/39233>`__
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
This PEP specifies a mechanism for storing package requirements in
|
||||||
|
``pyproject.toml`` files such that they are not included in any built distribution of
|
||||||
|
the project.
|
||||||
|
|
||||||
|
This is suitable for creating named groups of dependencies, similar to
|
||||||
|
``requirements.txt`` files, which launchers, IDEs, and other tools can find and
|
||||||
|
identify by name.
|
||||||
|
|
||||||
|
The feature defined here is referred to as "Dependency Groups".
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
There are two major use cases for which the Python community has no
|
||||||
|
standardized answer:
|
||||||
|
|
||||||
|
* How should development dependencies be defined for packages?
|
||||||
|
|
||||||
|
* How should dependencies be defined for projects which do not build
|
||||||
|
distributions (non-package projects)?
|
||||||
|
|
||||||
|
In the absence of any standard, two known workflow tools, PDM and Poetry, have
|
||||||
|
defined their own solutions for Dependency Groups to address the first of these
|
||||||
|
two needs. Their definitions are very similar to one another, although PDM
|
||||||
|
structures them much more similarly to
|
||||||
|
`extras <https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras>`__
|
||||||
|
than Poetry does.
|
||||||
|
Neither of them addresses the needs of non-package projects, and neither can be
|
||||||
|
referenced natively from other tools like ``tox``, ``nox``, or ``pip``.
|
||||||
|
|
||||||
|
There are two pre-existing solutions which are similar to this proposal: the
|
||||||
|
use of ``requirements.txt`` files and package extras.
|
||||||
|
|
||||||
|
Regarding ``requirements.txt``, many projects may define one or more of these files,
|
||||||
|
and may arrange them either at the project root (e.g. ``requirements.txt`` and
|
||||||
|
``test-requirements.txt``) or else in a directory (e.g.
|
||||||
|
``requirements/base.txt`` and ``requirements/test.txt``). However, there are
|
||||||
|
two major issues with the use of requirements files in this way:
|
||||||
|
|
||||||
|
* There is no standardized naming convention such that tools can discover or
|
||||||
|
use these files by name.
|
||||||
|
|
||||||
|
* ``requirements.txt`` files are *not standardized*, but instead provide
|
||||||
|
options to ``pip``.
|
||||||
|
|
||||||
|
Therefore, their use is not portable to any new
|
||||||
|
installer or tool which wishes to process them without relying upon ``pip``.
|
||||||
|
Additionally, ``requirements.txt`` files may be viewed as a heavyweight
|
||||||
|
solution for very small dependency sets of only one or two items, and a terser
|
||||||
|
declaration will be beneficial to projects with a number of small groups of
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
Regarding extras, the use of extras to define development dependencies is a
|
||||||
|
widespread practice, but it has two major downsides:
|
||||||
|
|
||||||
|
* An extra is defined as an optional part of a package which may specify
|
||||||
|
additional dependencies.
|
||||||
|
This means that it cannot be installed without installing all of the package
|
||||||
|
dependencies, and the project must be defined as a package.
|
||||||
|
|
||||||
|
* Many developers view their extras as part of the public interface for their
|
||||||
|
package. Because these are published data, package developers often are
|
||||||
|
concerned about ensuring that their development extras are not confused with
|
||||||
|
user-facing extras. Therefore, their development needs are not appropriate to
|
||||||
|
publish in the manner of extras.
|
||||||
|
|
||||||
|
Providing a standardized place to store dependency data which matches the
|
||||||
|
typical use cases of ``requirements.txt`` files will allow for better
|
||||||
|
cross-compatibility between tools and will onboard beginning users into
|
||||||
|
``pyproject.toml`` data more quickly (before they learn about the
|
||||||
|
``[build-system]`` table, for example). It will also resolve the long-standing
|
||||||
|
ambiguity and tension within the Python community about whether or not extras
|
||||||
|
should be used to declare development dependencies.
|
||||||
|
|
||||||
|
Supported Project Types
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
This PEP aims to serve the needs of two distinct project types:
|
||||||
|
|
||||||
|
* libraries and other packages which want to define development dependencies
|
||||||
|
|
||||||
|
* projects which do not build distributions which want a standardized way to
|
||||||
|
declare their dependency data
|
||||||
|
|
||||||
|
The Python packaging toolchain is oriented towards the production of wheel and
|
||||||
|
sdist files, containing project source code for installation. However, not all
|
||||||
|
projects are designed or intended for this mode of distribution. Primary
|
||||||
|
examples include webapps (which often run from source), and data science
|
||||||
|
projects (which may start as collections of scripts and only later evolve
|
||||||
|
package structures). This PEP seeks to offer these projects a way to specify
|
||||||
|
their package dependencies in a way which is not constrained by the
|
||||||
|
requirements of distribution building -- for example, a data science project
|
||||||
|
does not need to declare a version or authors in order for these data to be
|
||||||
|
valid, nor does it need to define an installable package source tree.
|
||||||
|
|
||||||
|
Simultaneously, this PEP should benefit projects which *are* intended to build
|
||||||
|
distributions.
|
||||||
|
Because Dependency Groups, as specified in this PEP, are explicitly defined to
|
||||||
|
not be included in any built distribution, two common use cases are addressed
|
||||||
|
by this addition:
|
||||||
|
|
||||||
|
* the use of ``extras``, as discussed above
|
||||||
|
|
||||||
|
* the use of ``requirements.txt`` files for distributed libraries and
|
||||||
|
applications, which takes a similar form to their use in
|
||||||
|
non-distribution-building projects
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
This PEP defines the storage of requirements data in lists within a
|
||||||
|
``[dependency-groups]`` table.
|
||||||
|
This name was chosen to match the canonical name of the feature
|
||||||
|
("Dependency Groups").
|
||||||
|
|
||||||
|
This format should be as simple and learnable as possible, having a format
|
||||||
|
very similar to existing ``requirements.txt`` files for many cases. Each list
|
||||||
|
in ``[dependency-groups]`` is defined as a list of package specifiers. However,
|
||||||
|
there are a number of use cases which require data which cannot be expressed in
|
||||||
|
PEP 508 package specifiers. Therefore, this PEP also defines an object-format
|
||||||
|
for package specification, capable of defining these additional data.
|
||||||
|
|
||||||
|
The format does not support many forms of non-package data from
|
||||||
|
``requirements.txt`` files, such as ``pip`` options for package servers or
|
||||||
|
hashes. Including them in the initial stage complicates this proposal and it is
|
||||||
|
not clear that the majority of use-cases require them. Future expansions to
|
||||||
|
this specification may extend the object format for dependencies in
|
||||||
|
``[dependency-groups]`` values. Because this specification provides for an
|
||||||
|
object format for the data, it is possible for these to be added in future
|
||||||
|
specifications.
|
||||||
|
|
||||||
|
The following use cases are considered important targets for this PEP:
|
||||||
|
|
||||||
|
* A web application (e.g. a Django or Flask app) which does not build a
|
||||||
|
distribution, but bundles and ships its source to a deployment toolchain. The
|
||||||
|
app has runtime dependencies, testing dependencies, and development
|
||||||
|
environment dependencies. All of these dependency sets should be declared
|
||||||
|
independently, and none of these runtime contexts should require that the
|
||||||
|
project be built into a wheel.
|
||||||
|
* A library which builds a distribution, but has a variety of testing and
|
||||||
|
development environments it wishes to declare. Some of these rely on the
|
||||||
|
library's own dependencies (``test`` and ``typing`` environments) while
|
||||||
|
others do not (``docs`` and ``lint`` environments).
|
||||||
|
* A data science project which consists of multiple scripts that depend on the same suite
|
||||||
|
of core libraries (e.g. ``numpy``, ``pandas``, ``matplotlib``), and which
|
||||||
|
also has additional libraries, sometimes conflicting, for specific scripts
|
||||||
|
(e.g. ``scikit-learn==1.3.2`` for one script and ``scikit-learn==0.24.2`` for
|
||||||
|
another).
|
||||||
|
* *Input data* to a lockfile generator. Because there is no standardized
|
||||||
|
lockfile format, it is still the prerogative of tools like ``poetry`` and
|
||||||
|
``pip-compile`` to describe their own formats. However, it should be possible
|
||||||
|
for the data from this PEP to be used as an input to these tools.
|
||||||
|
Furthermore, tools may define their own structures and conventions such that
|
||||||
|
the generated lockfiles can be referenced by the names of their originating
|
||||||
|
Dependency Groups in ``pyproject.toml``.
|
||||||
|
* *Input data* to a tox, Nox, or Hatch environment, as can
|
||||||
|
currently be achieved, for example, with ``deps = -r requirements.txt`` in
|
||||||
|
``tox.ini``. These tools will need to add additional options for processing
|
||||||
|
Dependency Groups.
|
||||||
|
* Embeddable data for ``pyproject.toml`` within a script, as in :pep:`723`,
|
||||||
|
which defines embedded ``pyproject.toml`` data within scripts. This
|
||||||
|
PEP does not define exactly how :pep:`723` should be modified, but being
|
||||||
|
consumable by that interface is a stated goal.
|
||||||
|
* IDE discovery of requirements data. For example, VS Code could look for a dependency
|
||||||
|
group named ``test`` to use when running tests.
|
||||||
|
|
||||||
|
Note that this PEP does not reserve any names for specific use cases. It is
|
||||||
|
considered a problem for downstream standards and conventions to define
|
||||||
|
well-known names for certain needs, such as ``test`` or ``docs``.
|
||||||
|
|
||||||
|
Regarding Poetry and PDM Dependency Groups
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
Poetry and PDM already offer a feature which each calls "Dependency Groups",
|
||||||
|
but using non-standard data belonging to the ``poetry`` and ``pdm`` tools.
|
||||||
|
(PDM also uses extras for some Dependency Groups, and overlaps the notion
|
||||||
|
heavily with extras.)
|
||||||
|
|
||||||
|
This PEP is not guaranteed to be a perfectly substitutable solution for the
|
||||||
|
same problem space for each tool. However, the ideas are extremely similar, and
|
||||||
|
it should be possible for Poetry and PDM to support at least some
|
||||||
|
PEP-735-standardized Dependency Group configurations using their own Dependency
|
||||||
|
Group nomenclature.
|
||||||
|
|
||||||
|
A level of interoperability with Poetry and PDM is a goal of this PEP, but
|
||||||
|
certain features and behaviors defined here may not be supported by Poetry and
|
||||||
|
PDM. Matching the existing Poetry and PDM *semantics* for Dependency Groups is
|
||||||
|
a non-goal.
|
||||||
|
|
||||||
|
Dependency Groups are not Hidden Extras
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
One could be forgiven for thinking that Dependency Groups are just extras which
|
||||||
|
go unpublished.
|
||||||
|
|
||||||
|
However, there are two major features which distinguish them from
|
||||||
|
extras:
|
||||||
|
|
||||||
|
* they support non-package projects
|
||||||
|
|
||||||
|
* installation of a Dependency Group does not imply installation of a package's
|
||||||
|
dependencies (or the package itself)
|
||||||
|
|
||||||
|
Object Specification Does Not Allow for "PEP 508 Decomposition"
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
Poetry and PDM both allow for their object formats for dependency data to be
|
||||||
|
used to decompose a PEP 508 specification into parts. For example, a dependency
|
||||||
|
on ``requests==2.21.0`` could be written under these tools in a form like
|
||||||
|
``{name = "requests", version = "==2.21.0"}``.
|
||||||
|
|
||||||
|
This spec does not allow for such a structure. There is only one way to write
|
||||||
|
down a PEP 508 dependency, as a string. This has two positive effects:
|
||||||
|
|
||||||
|
* There are fewer ways of writing identical data
|
||||||
|
|
||||||
|
* It is not possible, by design, to combine a PEP 508 specifier with other
|
||||||
|
key-value pairs in a dependency specifier
|
||||||
|
|
||||||
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
|
This PEP defines a new section (table) in ``pyproject.toml`` files named
|
||||||
|
``dependency-groups``. The ``dependency-groups`` table contains an arbitrary
|
||||||
|
number of user-defined keys, each of which has, as its value, a list of
|
||||||
|
requirements specifiers (defined below). These keys must match the following
|
||||||
|
regular expression: ``[a-z0-9][a-z0-9-]*[a-z0-9]``. Meaning that they must be
|
||||||
|
all lower-case alphanumerics, with ``-`` allowed only in the middle, and at
|
||||||
|
least two characters long. These requirements are chosen so that the
|
||||||
|
normalization rules used for PyPI package names are unnecessary as the names
|
||||||
|
are already normalized.
|
||||||
|
|
||||||
|
Requirements specifiers will use a definition based on standardized
|
||||||
|
`Dependency Specifiers <https://packaging.python.org/en/latest/specifications/dependency-specifiers/>`__
|
||||||
|
introduced in :pep:`508`.
|
||||||
|
|
||||||
|
This PEP also proposes an object format to define a dependency, called a
|
||||||
|
"Dependency Object Specifier" (defined below). The elements in
|
||||||
|
``[dependency-groups]`` lists must either be strings, in which case they must
|
||||||
|
be valid Dependency Specifiers (PEP 508) or else Dependency Object Specifiers.
|
||||||
|
|
||||||
|
Dependency Object Specifiers
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Dependency Object Specifiers are objects (tables in TOML) which define a set of
|
||||||
|
dependencies. They do not necessarily refer to a single package, as will become
|
||||||
|
clear from the definitions below.
|
||||||
|
|
||||||
|
There are two forms of Dependency Object Specifiers: "Dependency Group Includes"
|
||||||
|
and "Path Dependencies".
|
||||||
|
|
||||||
|
Dependency Group Include
|
||||||
|
''''''''''''''''''''''''
|
||||||
|
|
||||||
|
A Dependency Group Include includes the dependencies of another Dependency
|
||||||
|
Group in the current Dependency Group.
|
||||||
|
|
||||||
|
An include is defined as an object with exactly one key, ``"include"``, whose
|
||||||
|
value is a string, the name of another Dependency Group.
|
||||||
|
|
||||||
|
For example, ``{include = "test"}`` is an include which expands to the
|
||||||
|
contents of the ``test`` Dependency Group.
|
||||||
|
|
||||||
|
Path Dependency
|
||||||
|
'''''''''''''''
|
||||||
|
|
||||||
|
A Path Dependency is a dependency on a package found via a local filesystem
|
||||||
|
path OR on dependencies of a package found via a local filesystem path.
|
||||||
|
|
||||||
|
It contains the following keys, with associated types:
|
||||||
|
|
||||||
|
* ``path``: a string, required
|
||||||
|
* ``extras``: a list of strings, optional
|
||||||
|
* ``editable``: a boolean, optional
|
||||||
|
* ``only-deps``: a boolean, optional
|
||||||
|
|
||||||
|
For a simple example, ``{path = ".", editable = true, extras = ["mysql"]}`` is
|
||||||
|
a Path Dependency on the current project including its ``mysql`` extra. In
|
||||||
|
``requirements.txt`` files, a similar idea can be expressed as ``-e '.[mysql]'``.
|
||||||
|
|
||||||
|
``path``
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
The ``path`` must refer to the path to a built distribution (wheel, sdist, or
|
||||||
|
any future file format) or a directory containing python package source code.
|
||||||
|
|
||||||
|
If the ``path`` is relative, it is relative to the directory containing
|
||||||
|
``pyproject.toml``.
|
||||||
|
|
||||||
|
If the path refers to a built distribution, that package should be installed
|
||||||
|
when the Dependency Group is installed.
|
||||||
|
|
||||||
|
If the path refers to a directory, the directory SHOULD be a valid Python
|
||||||
|
package. Implementations MAY refuse to process ``path`` directives which are
|
||||||
|
not packages, even when ``only-deps`` is specified (see below for how
|
||||||
|
``only-deps`` would potentially make it possible to process non-package paths).
|
||||||
|
|
||||||
|
``extras``
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``extras`` key is a list of strings, each of which is the name of an extra
|
||||||
|
which should be included in the package installation.
|
||||||
|
|
||||||
|
``editable``
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If ``editable`` is ``true``, implementations installing the Dependency Group
|
||||||
|
SHOULD install the dependency in editable mode. If it is ``false``, they SHOULD
|
||||||
|
install it in non-editable mode. If ``editable`` is absent, no default behavior
|
||||||
|
is specified and implementations may choose their preferred default.
|
||||||
|
|
||||||
|
Implementations MAY provide options to users to configure or override this behavior.
|
||||||
|
For example, a tool may have an option ``--never-editable`` which always treats
|
||||||
|
``editable`` as ``false``.
|
||||||
|
However, implementations SHOULD prefer to use the ``editable`` value if it is
|
||||||
|
present.
|
||||||
|
|
||||||
|
If ``editable`` is specified on a Path Dependency which refers to a built
|
||||||
|
distribution, implementations MUST treat this as an error.
|
||||||
|
|
||||||
|
``only-deps``
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If ``only-deps`` is ``true``, implementations MUST NOT install the package
|
||||||
|
at the specified ``path``. Instead, they should only install the dependencies
|
||||||
|
of that package. This may still require building a package from a source tree
|
||||||
|
in order to discover ``dynamic`` dependency data.
|
||||||
|
|
||||||
|
If ``only-deps`` is ``false`` or absent, implementations should install the
|
||||||
|
package at the specified ``path``.
|
||||||
|
|
||||||
|
It is possible to specify ``only-deps`` on a Path Dependency which does not
|
||||||
|
refer to a valid python package and for tools to, at least in theory, process
|
||||||
|
such a dependency successfully. For example, a ``pyproject.toml`` file
|
||||||
|
containing only ``[project.dependencies]`` and none of the other required keys
|
||||||
|
in the ``[project]`` table could be supported. Implementations SHOULD NOT
|
||||||
|
support such structures and SHOULD fail if a Path Dependency refers to a python
|
||||||
|
project which is not a package.
|
||||||
|
|
||||||
|
If ``only-deps`` is ``true`` and ``extras`` are specified, implementations
|
||||||
|
should install the ``extras`` as well as all of the non-optional dependencies
|
||||||
|
of the package.
|
||||||
|
|
||||||
|
Handling of Multiple Path Dependencies Referring to the Same Path
|
||||||
|
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
It is possible for resolution of a Dependency Group to refer to the same
|
||||||
|
path multiple times (for example, via two combined includes) using distinct
|
||||||
|
Path Dependencies.
|
||||||
|
|
||||||
|
If the ``path`` values are distinct, but refer to the same concrete file or
|
||||||
|
directory on the filesystem, handling behavior is unspecified. Implementations
|
||||||
|
MAY normalize these paths to a single value.
|
||||||
|
|
||||||
|
If the ``path`` values are identical, implementations MUST treat the result as
|
||||||
|
a singular Path Dependency following the rules below:
|
||||||
|
|
||||||
|
- The ``extras`` keys are concatenated into a single list
|
||||||
|
- If ``editable`` is always ``true`` or always ``false``, it is treated as
|
||||||
|
such. Otherwise, the ``editable`` key is treated as though it were absent.
|
||||||
|
- If the ``only-deps`` key is present, a ``false`` or absent value takes
|
||||||
|
priority over any ``true`` values. In other words, implementations respect
|
||||||
|
``only-deps`` if it is ``true`` for all instances of the same ``path``.
|
||||||
|
Otherwise, they treat it as ``false``.
|
||||||
|
|
||||||
|
|
||||||
|
Example Dependency Groups Table
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The following is an example of a partial ``pyproject.toml`` which uses this to
|
||||||
|
define four Dependency Groups: ``test``, ``docs``, ``typing``, and
|
||||||
|
``typing-test``:
|
||||||
|
|
||||||
|
.. code:: toml
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
test = ["pytest", "coverage", {path = ".", editable = true}]
|
||||||
|
docs = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
typing = ["mypy", "types-requests", {path = ".", extras = ["types"], only-deps = true}]
|
||||||
|
typing-test = [{include = "typing"}, {include = "test"}, "useful-types"]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
types = ["typing-extensions"]
|
||||||
|
|
||||||
|
Note how ``test`` and ``typing`` refer to the current package while ``docs``
|
||||||
|
does not. This reflects the ability of Dependency Groups to be used in the same
|
||||||
|
manner as extras, adding to dependencies, or completely independently.
|
||||||
|
|
||||||
|
``typing-test`` is defined as a union of two existing groups, plus an
|
||||||
|
additional package. ``typing`` includes an extra, ``types``, and this is
|
||||||
|
included by extension under ``typing-test``.
|
||||||
|
Under ``typing-test`` implementations may choose whether or not to use an
|
||||||
|
editable installation of the current package or not, but they MUST treat
|
||||||
|
``only-deps`` as ``false``.
|
||||||
|
|
||||||
|
Package Building
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Build backends MUST NOT include Dependency Group data in built distributions.
|
||||||
|
|
||||||
|
Use of Dependency Groups
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Tools which support Dependency Groups are expected to provide new options and
|
||||||
|
interfaces to allow users to install from Dependency Groups.
|
||||||
|
|
||||||
|
No syntax is defined for expressing the Dependency Group of a package, for two
|
||||||
|
reasons:
|
||||||
|
|
||||||
|
* it would not be valid to refer to the Dependency Groups of a third-party
|
||||||
|
package from PyPI (because the data is defined to be unpublished)
|
||||||
|
|
||||||
|
* there is not guaranteed to be a current package for Dependency Groups -- part
|
||||||
|
of their purpose is to support non-package projects
|
||||||
|
|
||||||
|
For example, a possible pip interface for installing Dependency Groups
|
||||||
|
would be:
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
pip install --dependency-groups=test,typing
|
||||||
|
|
||||||
|
Note that this is only an example. This PEP does not declare any requirements
|
||||||
|
for how tools support the installation of Dependency Groups.
|
||||||
|
|
||||||
|
Reference Implementation
|
||||||
|
========================
|
||||||
|
|
||||||
|
There is currently no reference implementation/consumer of this specification.
|
||||||
|
|
||||||
|
Backwards Compatibility
|
||||||
|
=======================
|
||||||
|
|
||||||
|
At time of writing, the ``dependency-groups`` namespace within a
|
||||||
|
``pyproject.toml`` file is unused. Since the top-level namespace is
|
||||||
|
reserved for use only by standards specified at packaging.python.org,
|
||||||
|
there should be no direct backwards compatibility concerns.
|
||||||
|
|
||||||
|
Security Implications
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This PEP introduces new syntaxes and data formats for specifying dependency
|
||||||
|
information in projects. However, it does not introduce newly specified
|
||||||
|
mechanisms for handling or resolving dependencies.
|
||||||
|
|
||||||
|
It therefore does not carry security concerns other than those inherent in any
|
||||||
|
tools which may already be used to install dependencies -- i.e. malicious
|
||||||
|
dependencies may be specified here, just as they may be specified in
|
||||||
|
``requirements.txt`` files.
|
||||||
|
|
||||||
|
How to Teach This
|
||||||
|
=================
|
||||||
|
|
||||||
|
This feature should be referred to by its canonical name, "Dependency Groups".
|
||||||
|
|
||||||
|
The basic form of usage should be taught as a variant on typical
|
||||||
|
``requirements.txt`` data. Standard dependency specifiers (:pep:`508`) can be
|
||||||
|
added to a named list. Rather than asking pip to install from a
|
||||||
|
``requirements.txt`` file, either pip or a relevant workflow tool will install
|
||||||
|
from a named Dependency Group.
|
||||||
|
|
||||||
|
For new Python users, they may be taught directly to create a section in
|
||||||
|
``pyproject.toml`` containing their Dependency Groups, similarly to how they
|
||||||
|
are currently taught to use ``requirements.txt`` files.
|
||||||
|
This also allows new Python users to learn about ``pyproject.toml`` files
|
||||||
|
without needing to learn about package building.
|
||||||
|
A ``pyproject.toml`` file with only ``[dependency-groups]`` and no other tables
|
||||||
|
is valid.
|
||||||
|
|
||||||
|
For both new and experienced users, the object style used in Dependency Object
|
||||||
|
Specifiers will need to be explained. Support for
|
||||||
|
``{path = ".", editable = true}`` and
|
||||||
|
``{path = ".", editable = true, extras = ["extra"]}`` should be taught
|
||||||
|
similarly to teaching ``pip install -e .`` and ``pip install -e '.[extra]'``
|
||||||
|
-- it intentionally mirrors the effects of those commands.
|
||||||
|
|
||||||
|
Support for inclusion of one Dependency Group in another can be
|
||||||
|
taught as a homologue for one requirements file including another using ``-r``.
|
||||||
|
|
||||||
|
Rejected Ideas
|
||||||
|
==============
|
||||||
|
|
||||||
|
Why not define each Dependency Group as a table?
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
If our goal is to allow for future expansion, then defining each Dependency
|
||||||
|
Group as a subtable, thus enabling us to attach future keys to each group,
|
||||||
|
allows for the greatest future flexibility.
|
||||||
|
|
||||||
|
However, it also makes the structure nested more deeply, and therefore harder
|
||||||
|
to teach and learn. One of the goals of this PEP is to be an easy replacement
|
||||||
|
for many ``requirements.txt`` use-cases.
|
||||||
|
|
||||||
|
Why not define a special string syntax to extend Dependency Specifiers?
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Earlier drafts of this specification defined syntactic forms for Dependency
|
||||||
|
Group Includes and Path Dependencies.
|
||||||
|
|
||||||
|
However, there were three major issues with this approach:
|
||||||
|
|
||||||
|
* it complicates the string syntax which must be taught, beyond PEP 508
|
||||||
|
|
||||||
|
* the resulting strings would always need to be disambiguated from PEP 508
|
||||||
|
specifiers, complicating implementations
|
||||||
|
|
||||||
|
* support for the matrix of Path Dependency requirements (``editable``, ``only-deps``,
|
||||||
|
``extras``) would require a complex syntax whose design was unclear
|
||||||
|
|
||||||
|
Why not restrict dependencies to PEP 508 only?
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
There are known use cases for:
|
||||||
|
|
||||||
|
* including one Dependency Group in another
|
||||||
|
* including the current package (if the project is a package)
|
||||||
|
* including the current package with extras (if the project is a package)
|
||||||
|
* installing ``project.dependencies`` from the current project but not
|
||||||
|
installing the current project (as can be done with
|
||||||
|
``{path = ".", only-deps = true}``)
|
||||||
|
* specifying that an installation be done in editable mode
|
||||||
|
|
||||||
|
These are not satisfiable without some expansion of syntax beyond what is
|
||||||
|
possible with existing Dependency Specifiers (:pep:`508`).
|
||||||
|
|
||||||
|
Why is the table not named ``[run]``, ``[project.dependency-groups]``, ...?
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
There are many possible names for this concept.
|
||||||
|
It will have to live alongside the already existing ``[project.dependencies]``
|
||||||
|
and ``[project.optional-dependencies]`` tables, and possibly a new
|
||||||
|
``[external]`` dependency table as well (at time of writing, :pep:`725`, which
|
||||||
|
defines the ``[external]`` table, is in progress).
|
||||||
|
|
||||||
|
``[run]`` was a leading proposal in earlier discussions, but its proposed usage
|
||||||
|
centered around a single set of runtime dependencies. This PEP explicitly
|
||||||
|
outlines multiple groups of dependencies, which makes ``[run]`` a less
|
||||||
|
appropriate fit -- this is not just dependency data for a specific runtime
|
||||||
|
context, but for multiple contexts.
|
||||||
|
|
||||||
|
``[project.dependency-groups]`` would be ideal, but has major downsides for
|
||||||
|
non-package projects. ``[project]`` requires several keys to be defined, such
|
||||||
|
as ``name`` and ``version``. Using this name would either require redefining
|
||||||
|
the ``[project]`` table to allow for these keys to be absent, or else would
|
||||||
|
impose a requirement on non-package projects to define and use these keys. By
|
||||||
|
extension, it would effectively require any non-package project allow itself to
|
||||||
|
be treated as a package.
|
||||||
|
|
||||||
|
Why is pip's planned implementation of ``--only-deps`` not sufficient?
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
pip currently has a feature on the roadmap to add an
|
||||||
|
`--only-deps flag <https://github.com/pypa/pip/issues/11440>`_.
|
||||||
|
This flag is intended to allow users to install package dependencies and extras
|
||||||
|
without installing the current package.
|
||||||
|
|
||||||
|
It does not address the needs of non-package projects, nor does it allow for
|
||||||
|
the installation of an extra without the package dependencies.
|
||||||
|
|
||||||
|
Therefore, while it may be a useful feature for pip to pursue, it does not
|
||||||
|
address the same use-cases addressed here.
|
||||||
|
|
||||||
|
Why isn't <environment manager> a solution?
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Existing environment managers like tox, Nox, and Hatch already have
|
||||||
|
the ability to list inlined dependencies as part of their configuration data.
|
||||||
|
This meets many development dependency needs, and clearly associates dependency
|
||||||
|
groups with relevant tasks which can be run.
|
||||||
|
These mechanisms are *good* but they are not *sufficient*.
|
||||||
|
|
||||||
|
First, they do not address the needs of non-package projects.
|
||||||
|
|
||||||
|
Second, there is no standard for other tools to use to access these data. This
|
||||||
|
has impacts on high-level tools like IDEs and Dependabot, which cannot support
|
||||||
|
deep integration with these Dependency Groups. (For example, at time of writing
|
||||||
|
Dependabot will not flag dependencies which are pinned in ``tox.ini`` files.)
|
||||||
|
|
||||||
|
Open Issues
|
||||||
|
===========
|
||||||
|
|
||||||
|
Documenting Distinctions from Poetry and PDM Object Formats
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
The object format here is similar to the ones used by Poetry and PDM, but not
|
||||||
|
identical.
|
||||||
|
The differences should be captured in Appendix B, as a part of documenting Poetry
|
||||||
|
and PDM behaviors and data formats.
|
||||||
|
|
||||||
|
Editable Installation May or May Not Be In Scope
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
The ``editable`` field formalizes a behavior which is supported by setuptools
|
||||||
|
and pip, but which has three major issues:
|
||||||
|
|
||||||
|
- it combines information about the existence of a dependency with information
|
||||||
|
about *how* that dependency should be installed
|
||||||
|
|
||||||
|
- editable installs, as implemented today, do not provide for seamless updates
|
||||||
|
to package metadata
|
||||||
|
|
||||||
|
- there is no specification for the behavior of an editable install -- this is
|
||||||
|
an implementation-specific feature
|
||||||
|
|
||||||
|
Therefore, ``editable`` may need to be removed.
|
||||||
|
Such a removal must account for how existing tools and workflows which rely on
|
||||||
|
editable installs will be impacted.
|
||||||
|
|
||||||
|
Should ``include`` accept a list?
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
This would enable more compact includes of multiple other Dependency Groups, at
|
||||||
|
the cost of a minor complication to the specification.
|
||||||
|
|
||||||
|
Footnotes
|
||||||
|
=========
|
||||||
|
|
||||||
|
Appendix A: Prior Art in Non-Python Languages
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Appendix B: Prior Art in Python
|
||||||
|
===============================
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Appendix C: Use Cases
|
||||||
|
=====================
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document is placed in the public domain or under the
|
||||||
|
CC0-1.0-Universal license, whichever is more permissive.
|
Loading…
Reference in New Issue