python-peps/pep-0735/index.html

1515 lines
143 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 735 Dependency Groups in pyproject.toml | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0735/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 735 Dependency Groups in pyproject.toml | peps.python.org'>
<meta property="og:description" content="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.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0735/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="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.">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 735</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 735 Dependency Groups in pyproject.toml</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Stephen Rosen &lt;sirosen0&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Brett Cannon &lt;brett&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-odd">PEP-Delegate<span class="colon">:</span></dt>
<dd class="field-odd">Paul Moore &lt;p.f.moore&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/39233">Discourse thread</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative proposal accepted for implementation">Accepted</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-odd">Topic<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../topic/packaging/">Packaging</a></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">20-Nov-2023</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/29684" title="Discourse thread">14-Nov-2023</a>, <a class="reference external" href="https://discuss.python.org/t/39233" title="Discourse thread">20-Nov-2023</a></dd>
<dt class="field-even">Resolution<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/39233/312">10-Oct-2024</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#limitations-of-requirements-txt-files">Limitations of <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files</a></li>
<li><a class="reference internal" href="#limitations-of-extras">Limitations of <code class="docutils literal notranslate"><span class="pre">extras</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#use-cases">Use Cases</a></li>
<li><a class="reference internal" href="#regarding-poetry-and-pdm-dependency-groups">Regarding Poetry and PDM Dependency Groups</a></li>
<li><a class="reference internal" href="#dependency-groups-are-not-hidden-extras">Dependency Groups are not Hidden Extras</a></li>
<li><a class="reference internal" href="#future-compatibility-invalid-data">Future Compatibility &amp; Invalid Data</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#dependency-object-specifiers">Dependency Object Specifiers</a><ul>
<li><a class="reference internal" href="#dependency-group-include">Dependency Group Include</a></li>
</ul>
</li>
<li><a class="reference internal" href="#example-dependency-groups-table">Example Dependency Groups Table</a></li>
<li><a class="reference internal" href="#package-building">Package Building</a></li>
<li><a class="reference internal" href="#installing-dependency-groups">Installing Dependency Groups</a><ul>
<li><a class="reference internal" href="#overlapping-install-ux-with-extras">Overlapping Install UX with Extras</a></li>
</ul>
</li>
<li><a class="reference internal" href="#validation-and-compatibility">Validation and Compatibility</a><ul>
<li><a class="reference internal" href="#linters-and-validators-may-be-stricter">Linters and Validators may be stricter</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#audit-and-update-tools">Audit and Update Tools</a></li>
</ul>
</li>
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
<li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a><ul>
<li><a class="reference internal" href="#interfaces-for-use-of-dependency-groups">Interfaces for Use of Dependency Groups</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#why-not-define-each-dependency-group-as-a-table">Why not define each Dependency Group as a table?</a></li>
<li><a class="reference internal" href="#why-not-define-a-special-string-syntax-to-extend-dependency-specifiers">Why not define a special string syntax to extend Dependency Specifiers?</a></li>
<li><a class="reference internal" href="#why-not-allow-for-more-non-pep-508-dependency-specifiers">Why not allow for more non-PEP 508 dependency specifiers?</a></li>
<li><a class="reference internal" href="#why-is-the-table-not-named-run-project-dependency-groups">Why is the table not named <code class="docutils literal notranslate"><span class="pre">[run]</span></code>, <code class="docutils literal notranslate"><span class="pre">[project.dependency-groups]</span></code>, …?</a></li>
<li><a class="reference internal" href="#why-is-pip-s-planned-implementation-of-only-deps-not-sufficient">Why is pips planned implementation of <code class="docutils literal notranslate"><span class="pre">--only-deps</span></code> not sufficient?</a></li>
<li><a class="reference internal" href="#why-isn-t-environment-manager-a-solution">Why isnt &lt;environment manager&gt; a solution?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
<li><a class="reference internal" href="#why-not-support-dependency-group-includes-in-project-dependencies-or-project-optional-dependencies">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> or <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code>?</a><ul>
<li><a class="reference internal" href="#use-cases-for-dependency-group-includes-from-project">Use Cases for Dependency Group Includes From <code class="docutils literal notranslate"><span class="pre">[project]</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#why-not-support-dependency-group-includes-in-build-system-requires">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[build-system.requires]</span></code>?</a></li>
<li><a class="reference internal" href="#why-not-support-a-dependency-group-which-includes-the-current-project">Why not support a Dependency Group which includes the current project?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-prior-art-in-non-python-languages">Appendix A: Prior Art in Non-Python Languages</a><ul>
<li><a class="reference internal" href="#javascript-and-package-json">JavaScript and <code class="docutils literal notranslate"><span class="pre">package.json</span></code></a><ul>
<li><a class="reference internal" href="#dependencies-data"><code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> data</a></li>
<li><a class="reference internal" href="#dependencies-referencing-urls-and-local-paths">Dependencies Referencing URLs and Local Paths</a></li>
<li><a class="reference internal" href="#devdependencies-data"><code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code> data</a></li>
<li><a class="reference internal" href="#peerdependencies-and-optionaldependencies"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependencies&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;optionalDependencies&quot;</span></code></a><ul>
<li><a class="reference internal" href="#peerdependenciesmeta"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependenciesMeta&quot;</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#omit-and-include"><code class="docutils literal notranslate"><span class="pre">--omit</span></code> and <code class="docutils literal notranslate"><span class="pre">--include</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#ruby-ruby-gems">Ruby &amp; Ruby Gems</a><ul>
<li><a class="reference internal" href="#gemfiles-bundle">Gemfiles &amp; bundle</a></li>
<li><a class="reference internal" href="#gemspec-and-packaged-dependency-data">gemspec and packaged dependency data</a><ul>
<li><a class="reference internal" href="#gemspec-development-dependency-example">gemspec development dependency example</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-b-prior-art-in-python">Appendix B: Prior Art in Python</a><ul>
<li><a class="reference internal" href="#projects-are-packages">Projects are Packages</a></li>
<li><a class="reference internal" href="#non-standard-dependency-specifiers">Non-Standard Dependency Specifiers</a></li>
<li><a class="reference internal" href="#installing-and-referring-to-dependency-groups">Installing and Referring to Dependency Groups</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-c-use-cases">Appendix C: Use Cases</a><ul>
<li><a class="reference internal" href="#web-applications">Web Applications</a></li>
<li><a class="reference internal" href="#libraries">Libraries</a></li>
<li><a class="reference internal" href="#data-science-projects">Data Science Projects</a></li>
<li><a class="reference internal" href="#lockfile-generation">Lockfile Generation</a></li>
<li><a class="reference internal" href="#environment-manager-inputs">Environment Manager Inputs</a></li>
<li><a class="reference internal" href="#ide-and-editor-use-of-requirements-data">IDE and Editor Use of Requirements Data</a></li>
</ul>
</li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP specifies a mechanism for storing package requirements in
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> files such that they are not included in any built distribution of
the project.</p>
<p>This is suitable for creating named groups of dependencies, similar to
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files, which launchers, IDEs, and other tools can find and
identify by name.</p>
<p>The feature defined here is referred to as “Dependency Groups”.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>There are two major use cases for which the Python community has no
standardized answer:</p>
<ul class="simple">
<li>How should development dependencies be defined for packages?</li>
<li>How should dependencies be defined for projects which do not build
distributions (non-package projects)?</li>
</ul>
<p>In support of these two needs, there are two common solutions which are similar
to this proposal:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files</li>
<li>package <a class="reference external" href="https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras">extras</a></li>
</ul>
<p>Both <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files and <code class="docutils literal notranslate"><span class="pre">extras</span></code> have limitations which this
standard seeks to overcome.</p>
<p>Note that the two use cases above describe two different types of projects
which this PEP seeks to support:</p>
<ul class="simple">
<li>Python packages, such as libraries</li>
<li>non-package projects, such as data science projects</li>
</ul>
<p>Several motivating use cases are defined in detail in the <a class="reference internal" href="#id1"><span class="std std-ref">Use Cases Appendix</span></a>.</p>
<section id="limitations-of-requirements-txt-files">
<h3><a class="toc-backref" href="#limitations-of-requirements-txt-files" role="doc-backlink">Limitations of <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files</a></h3>
<p>Many projects may define one or more <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files,
and may arrange them either at the project root (e.g. <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> and
<code class="docutils literal notranslate"><span class="pre">test-requirements.txt</span></code>) or else in a directory (e.g.
<code class="docutils literal notranslate"><span class="pre">requirements/base.txt</span></code> and <code class="docutils literal notranslate"><span class="pre">requirements/test.txt</span></code>). However, there are
major issues with the use of requirements files in this way:</p>
<ul class="simple">
<li>There is no standardized naming convention such that tools can discover or
use these files by name.</li>
<li><code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files are <em>not standardized</em>, but instead provide
options to <code class="docutils literal notranslate"><span class="pre">pip</span></code>.</li>
</ul>
<p>As a result, it is difficult to define tool behaviors based on
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files. They are not trivial to discover or identify by
name, and their contents may contain a mix of package specifiers and additional
<code class="docutils literal notranslate"><span class="pre">pip</span></code> options.</p>
<p>The lack of a standard for <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> contents also means they are
not portable to any alternative tools which wish to process them other than
<code class="docutils literal notranslate"><span class="pre">pip</span></code>.</p>
<p>Additionally, <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files require a file per dependency list.
For some use-cases, this makes the marginal cost of dependency groupings high,
relative to their benefit.
A terser declaration is beneficial to projects with a number of small groups of
dependencies.</p>
<p>In contrast with this, Dependency Groups are defined at a well known location
in <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> with fully standardized contents. Not only will they have
immediate utility, but they will also serve as a starting point for future
standards.</p>
</section>
<section id="limitations-of-extras">
<h3><a class="toc-backref" href="#limitations-of-extras" role="doc-backlink">Limitations of <code class="docutils literal notranslate"><span class="pre">extras</span></code></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">extras</span></code> are additional package metadata declared in the
<code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code> table. They provide names for lists of
package specifiers which are published as part of a packages metadata, and
which a user can request under that name, as in <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">'foo[bar]'</span></code> to
install <code class="docutils literal notranslate"><span class="pre">foo</span></code> with the <code class="docutils literal notranslate"><span class="pre">bar</span></code> extra.</p>
<p>Because <code class="docutils literal notranslate"><span class="pre">extras</span></code> are package metadata, they are not guaranteed to be
statically defined and may require a build system to resolve.
Furthermore, definition of a <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code> indicates to
many tools that a project is a package, and may drive tool behaviors such as
validation of the <code class="docutils literal notranslate"><span class="pre">[project]</span></code> table.</p>
<p>For projects which are packages, <code class="docutils literal notranslate"><span class="pre">extras</span></code> are a common solution for defining
development dependencies, but even under these circumstances they have
downsides:</p>
<ul class="simple">
<li>Because an <code class="docutils literal notranslate"><span class="pre">extra</span></code> defines optional <em>additional</em> dependencies, it is not
possible to install an <code class="docutils literal notranslate"><span class="pre">extra</span></code> without installing the current package and
its dependencies.</li>
<li>Because they are user-installable, <code class="docutils literal notranslate"><span class="pre">extras</span></code> are part of the public interface
for packages. Because <code class="docutils literal notranslate"><span class="pre">extras</span></code> are published, package developers often are
concerned about ensuring that their development extras are not confused with
user-facing extras.</li>
</ul>
</section>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>This PEP defines the storage of requirements data in lists within a
<code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> table.
This name was chosen to match the canonical name of the feature
(“Dependency Groups”).</p>
<p>This format should be as simple and learnable as possible, having a format
very similar to existing <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files for many cases. Each list
in <code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> is defined as a list of package specifiers. For
example:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pytest&gt;7&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coverage&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>There are a number of use cases for <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files which require
data which cannot be expressed in <a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a> dependency specifiers. Such
fields are not valid in Dependency Groups. Including many of the data and
fields which <code class="docutils literal notranslate"><span class="pre">pip</span></code> supports, such as index servers, hashes, and path
dependencies, requires new standards. This standard leaves room for new
standards and developments, but does not attempt to support all valid
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> contents.</p>
<p>The only exception to this is the <code class="docutils literal notranslate"><span class="pre">-r</span></code> flag which <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files
use to include one file in another. Dependency Groups support an “include”
mechanism which is similar in meaning, allowing one dependency group to extend
another.</p>
<p>Dependency Groups have two additional features which are similar to
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files:</p>
<ul class="simple">
<li>they are not published as distinct metadata in any built distribution</li>
<li>installation of a dependency group does not imply installation of a packages
dependencies or the package itself</li>
</ul>
<section id="use-cases">
<h3><a class="toc-backref" href="#use-cases" role="doc-backlink">Use Cases</a></h3>
<p>The following use cases are considered important targets for this PEP. They are
defined in greater detail in the <a class="reference internal" href="#id1"><span class="std std-ref">Use Cases Appendix</span></a>.</p>
<ul class="simple">
<li>Web Applications deployed via a non-python-packaging build process</li>
<li>Libraries with unpublished dev dependency groups</li>
<li>Data science projects with groups of dependencies but no core package</li>
<li><em>Input data</em> to lockfile generation (Dependency Groups should generally not
be used as a location for locked dependency data)</li>
<li>Input data to an environment manager, such as tox, Nox, or Hatch</li>
<li>Configurable IDE discovery of test and linter requirements</li>
</ul>
</section>
<section id="regarding-poetry-and-pdm-dependency-groups">
<h3><a class="toc-backref" href="#regarding-poetry-and-pdm-dependency-groups" role="doc-backlink">Regarding Poetry and PDM Dependency Groups</a></h3>
<p>The existing Poetry and PDM tools already offer a feature which each calls
“Dependency Groups”. However, absent any standard for specifying collections
of dependencies, each tool defines these in a tool-specific way, in the
relevant sections of the <code class="docutils literal notranslate"><span class="pre">[tool]</span></code> table.</p>
<p>(PDM also uses extras for some Dependency Groups, and overlaps the notion
heavily with extras.)</p>
<p>This PEP does not support all of the features of Poetry and PDM, which, like
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files for <code class="docutils literal notranslate"><span class="pre">pip</span></code>, support several non-standard extensions
to common dependency specifiers.</p>
<p>It should be possible for such tools to use standardized Dependency Groups as
extensions of their own Dependency Group mechanisms.
However, defining a new data format which replaces the existing Poetry and PDM
solutions is a non-goal. Doing so would require standardizing several
additional features, such as path dependencies, which are supported by these
tools.</p>
</section>
<section id="dependency-groups-are-not-hidden-extras">
<h3><a class="toc-backref" href="#dependency-groups-are-not-hidden-extras" role="doc-backlink">Dependency Groups are not Hidden Extras</a></h3>
<p>Dependency Groups are very similar to extras which go unpublished.
However, there are two major features which distinguish them from extras
further:</p>
<ul class="simple">
<li>they support non-package projects</li>
<li>installation of a Dependency Group does not imply installation of a packages
dependencies (or the package itself)</li>
</ul>
</section>
<section id="future-compatibility-invalid-data">
<h3><a class="toc-backref" href="#future-compatibility-invalid-data" role="doc-backlink">Future Compatibility &amp; Invalid Data</a></h3>
<p>Dependency Groups are intended to be extensible in future PEPs.
However, Dependency Groups should also be usable by multiple tools in a
single Python project.
With multiple tools using the same data, it is possible that one implements
a future PEP which extends Dependency Groups, while another does not.</p>
<p>To support users in this case, this PEP defines and recommends validation
behaviors in which tools only examine Dependency Groups which they are using.
This allows multiple tools, using different versions of Dependency Groups data,
to share a single table in <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>.</p>
</section>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>This PEP defines a new section (table) in <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> files named
<code class="docutils literal notranslate"><span class="pre">dependency-groups</span></code>. The <code class="docutils literal notranslate"><span class="pre">dependency-groups</span></code> table contains an arbitrary
number of user-defined keys, each of which has, as its value, a list of
requirements (defined below). These keys must be
<a class="reference external" href="https://packaging.python.org/en/latest/specifications/name-normalization/#valid-non-normalized-names">valid non-normalized names</a>,
and must be
<a class="reference external" href="https://packaging.python.org/en/latest/specifications/name-normalization/#normalization">normalized</a>
before comparisons.</p>
<p>Tools SHOULD prefer to present the original, non-normalized name to users by
default. If duplicate names, after normalization, are encountered, tools SHOULD
emit an error.</p>
<p>Requirement lists under <code class="docutils literal notranslate"><span class="pre">dependency-groups</span></code> may contain strings, tables
(“dicts” in Python), or a mix of strings and tables.</p>
<p>Strings in requirement lists must be valid
<a class="reference external" href="https://packaging.python.org/en/latest/specifications/dependency-specifiers/">Dependency Specifiers</a>,
as defined in <a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a>.</p>
<p>Tables in requirement lists must be valid Dependency Object Specifiers.</p>
<section id="dependency-object-specifiers">
<h3><a class="toc-backref" href="#dependency-object-specifiers" role="doc-backlink">Dependency Object Specifiers</a></h3>
<p>Dependency Object Specifiers are tables which define zero or more dependencies.</p>
<p>This PEP standardizes only one type of Dependency Object Specifier, a
“Dependency Group Include”. Other types may be added in future standards.</p>
<section id="dependency-group-include">
<h4><a class="toc-backref" href="#dependency-group-include" role="doc-backlink">Dependency Group Include</a></h4>
<p>A Dependency Group Include includes the dependencies of another Dependency
Group in the current Dependency Group.</p>
<p>An include is defined as a table with exactly one key, <code class="docutils literal notranslate"><span class="pre">&quot;include-group&quot;</span></code>,
whose value is a string, the name of another Dependency Group.</p>
<p>For example, <code class="docutils literal notranslate"><span class="pre">{include-group</span> <span class="pre">=</span> <span class="pre">&quot;test&quot;}</span></code> is an include which expands to the
contents of the <code class="docutils literal notranslate"><span class="pre">test</span></code> Dependency Group.</p>
<p>Includes are defined to be exactly equivalent to the contents of the named
Dependency Group, inserted into the current group at the location of the include.
For example, if <code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">=</span> <span class="pre">[&quot;a&quot;,</span> <span class="pre">&quot;b&quot;]</span></code> is one group, and
<code class="docutils literal notranslate"><span class="pre">bar</span> <span class="pre">=</span> <span class="pre">[&quot;c&quot;,</span> <span class="pre">{include-group</span> <span class="pre">=</span> <span class="pre">&quot;foo&quot;},</span> <span class="pre">&quot;d&quot;]</span></code> is another, then <code class="docutils literal notranslate"><span class="pre">bar</span></code> should
evaluate to <code class="docutils literal notranslate"><span class="pre">[&quot;c&quot;,</span> <span class="pre">&quot;a&quot;,</span> <span class="pre">&quot;b&quot;,</span> <span class="pre">&quot;d&quot;]</span></code> when Dependency Group Includes are expanded.</p>
<p>Dependency Group Includes may specify the same package multiple times. Tools
SHOULD NOT deduplicate or otherwise alter the list contents produced by the
include. For example, given the following table:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">group-a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">]</span>
<span class="n">group-b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;foo&gt;1.0&quot;</span><span class="p">]</span>
<span class="n">group-c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;foo&lt;1.0&quot;</span><span class="p">]</span>
<span class="n">all</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;group-a&quot;</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;group-b&quot;</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;group-c&quot;</span><span class="p">}]</span>
</pre></div>
</div>
<p>The resolved value of <code class="docutils literal notranslate"><span class="pre">all</span></code> SHOULD be <code class="docutils literal notranslate"><span class="pre">[&quot;foo&quot;,</span> <span class="pre">&quot;foo&quot;,</span> <span class="pre">&quot;foo&gt;1.0&quot;,</span> <span class="pre">&quot;foo&lt;1.0&quot;]</span></code>.
Tools should handle such a list exactly as they would handle any other case in
which they are asked to process the same requirement multiple times with
different version constraints.</p>
<p>Dependency Group Includes may include lists containing Dependency Group
Includes, in which case those includes should be expanded as well. Dependency
Group Includes MUST NOT include cycles, and tools SHOULD report an error if
they detect a cycle.</p>
</section>
</section>
<section id="example-dependency-groups-table">
<h3><a class="toc-backref" href="#example-dependency-groups-table" role="doc-backlink">Example Dependency Groups Table</a></h3>
<p>The following is an example of a partial <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> which uses this to
define four Dependency Groups: <code class="docutils literal notranslate"><span class="pre">test</span></code>, <code class="docutils literal notranslate"><span class="pre">docs</span></code>, <code class="docutils literal notranslate"><span class="pre">typing</span></code>, and
<code class="docutils literal notranslate"><span class="pre">typing-test</span></code>:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pytest&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coverage&quot;</span><span class="p">]</span>
<span class="n">docs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;sphinx&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;sphinx-rtd-theme&quot;</span><span class="p">]</span>
<span class="n">typing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;mypy&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;types-requests&quot;</span><span class="p">]</span>
<span class="n">typing-test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;typing&quot;</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;test&quot;</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;useful-types&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>Note that none of these Dependency Group declarations implicitly install the
current package, its dependencies, or any optional dependencies.
Use of a Dependency Group like <code class="docutils literal notranslate"><span class="pre">test</span></code> to test a package requires that the
users configuration or toolchain also installs the current package (<code class="docutils literal notranslate"><span class="pre">.</span></code>).
For example,</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="nv">$TOOL</span><span class="w"> </span>install-dependency-group<span class="w"> </span><span class="nb">test</span>
pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span>.
</pre></div>
</div>
<p>could be used (supposing <code class="docutils literal notranslate"><span class="pre">$TOOL</span></code> is a tool which supports installing
Dependency Groups) to build a testing environment.</p>
<p>This also allows for the <code class="docutils literal notranslate"><span class="pre">docs</span></code> dependency group to be used without
installing the project as a package:</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="nv">$TOOL</span><span class="w"> </span>install-dependency-group<span class="w"> </span>docs
</pre></div>
</div>
</section>
<section id="package-building">
<h3><a class="toc-backref" href="#package-building" role="doc-backlink">Package Building</a></h3>
<p>Build backends MUST NOT include Dependency Group data in built distributions as
package metadata. This means that PKG-INFO in sdists and METADATA in wheels
do not include any referencable fields containing Dependency Groups.</p>
<p>It is valid to use Dependency Groups in the evaluation of dynamic metadata, and
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> files included in sdists will naturally still contain the
<code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> table. However, the table contents are not part of a
published packages interfaces.</p>
</section>
<section id="installing-dependency-groups">
<h3><a class="toc-backref" href="#installing-dependency-groups" role="doc-backlink">Installing Dependency Groups</a></h3>
<p>Tools which support Dependency Groups are expected to provide new options and
interfaces to allow users to install from Dependency Groups.</p>
<p>No syntax is defined for expressing the Dependency Group of a package, for two
reasons:</p>
<ul class="simple">
<li>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)</li>
<li>there is not guaranteed to be a current package for Dependency Groups part
of their purpose is to support non-package projects</li>
</ul>
<p>For example, a possible pip interface for installing Dependency Groups
would be:</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>--dependency-groups<span class="o">=</span>test,typing
</pre></div>
</div>
<p>Note that this is only an example. This PEP does not declare any requirements
for how tools support the installation of Dependency Groups.</p>
<section id="overlapping-install-ux-with-extras">
<h4><a class="toc-backref" href="#overlapping-install-ux-with-extras" role="doc-backlink">Overlapping Install UX with Extras</a></h4>
<p>Tools MAY choose to provide the same interfaces for installing Dependency
Groups as they do for installing extras.</p>
<p>Note that this specification does not forbid having an extra whose name matches
a Dependency Group.</p>
<p>Users are advised to avoid creating Dependency Groups whose names match extras.
Tools MAY treat such matching as an error.</p>
</section>
</section>
<section id="validation-and-compatibility">
<h3><a class="toc-backref" href="#validation-and-compatibility" role="doc-backlink">Validation and Compatibility</a></h3>
<p>Tools supporting Dependency Groups may want to validate data before using it.
However, tools implementing such validation behavior should be careful to allow
for future expansions to this spec, so that they do not unnecessarily emit
errors or warnings in the presence of new syntax.</p>
<p>Tools SHOULD error when evaluating or processing unrecognized data in
Dependency Groups.</p>
<p>Tools SHOULD NOT eagerly validate the list contents of <strong>all</strong> Dependency
Groups.</p>
<p>This means that in the presence of the following data, most tools will allow
the <code class="docutils literal notranslate"><span class="pre">foo</span></code> group to be used, and will only error when the <code class="docutils literal notranslate"><span class="pre">bar</span></code> group is
used:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">foo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pyparsing&quot;</span><span class="p">]</span>
<span class="n">bar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">set-phasers-to</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;stun&quot;</span><span class="p">}]</span>
</pre></div>
</div>
<section id="linters-and-validators-may-be-stricter">
<h4><a class="toc-backref" href="#linters-and-validators-may-be-stricter" role="doc-backlink">Linters and Validators may be stricter</a></h4>
<p>Eager validation is discouraged for tools which primarily install or resolve
Dependency Groups.
Linters and validation tools may have good cause to ignore this recommendation.</p>
</section>
</section>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>The following Reference Implementation prints the contents of a Dependency
Group to stdout, newline delimited.
The output is therefore valid <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> data.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">tomllib</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>
<span class="kn">from</span> <span class="nn">packaging.requirements</span> <span class="kn">import</span> <span class="n">Requirement</span>
<span class="k">def</span> <span class="nf">_normalize_name</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;[-_.]+&quot;</span><span class="p">,</span> <span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">_normalize_group_names</span><span class="p">(</span><span class="n">dependency_groups</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
<span class="n">original_names</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
<span class="n">normalized_groups</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">group_name</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">dependency_groups</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">normed_group_name</span> <span class="o">=</span> <span class="n">_normalize_name</span><span class="p">(</span><span class="n">group_name</span><span class="p">)</span>
<span class="n">original_names</span><span class="p">[</span><span class="n">normed_group_name</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">group_name</span><span class="p">)</span>
<span class="n">normalized_groups</span><span class="p">[</span><span class="n">normed_group_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">errors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">normed_name</span><span class="p">,</span> <span class="n">names</span> <span class="ow">in</span> <span class="n">original_names</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">names</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">normed_name</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">names</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Duplicate dependency group names: </span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">normalized_groups</span>
<span class="k">def</span> <span class="nf">_resolve_dependency_group</span><span class="p">(</span>
<span class="n">dependency_groups</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">group</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">past_groups</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">()</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">if</span> <span class="n">group</span> <span class="ow">in</span> <span class="n">past_groups</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Cyclic dependency group include: </span><span class="si">{</span><span class="n">group</span><span class="si">}</span><span class="s2"> -&gt; </span><span class="si">{</span><span class="n">past_groups</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">group</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">dependency_groups</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">LookupError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Dependency group &#39;</span><span class="si">{</span><span class="n">group</span><span class="si">}</span><span class="s2">&#39; not found&quot;</span><span class="p">)</span>
<span class="n">raw_group</span> <span class="o">=</span> <span class="n">dependency_groups</span><span class="p">[</span><span class="n">group</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">raw_group</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Dependency group &#39;</span><span class="si">{</span><span class="n">group</span><span class="si">}</span><span class="s2">&#39; is not a list&quot;</span><span class="p">)</span>
<span class="n">realized_group</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">raw_group</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="c1"># packaging.requirements.Requirement parsing ensures that this is a valid</span>
<span class="c1"># PEP 508 Dependency Specifier</span>
<span class="c1"># raises InvalidRequirement on failure</span>
<span class="n">Requirement</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="n">realized_group</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span> <span class="o">!=</span> <span class="p">(</span><span class="s2">&quot;include-group&quot;</span><span class="p">,):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid dependency group item: </span><span class="si">{</span><span class="n">item</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">include_group</span> <span class="o">=</span> <span class="n">_normalize_name</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">values</span><span class="p">())))</span>
<span class="n">realized_group</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span>
<span class="n">_resolve_dependency_group</span><span class="p">(</span>
<span class="n">dependency_groups</span><span class="p">,</span> <span class="n">include_group</span><span class="p">,</span> <span class="n">past_groups</span> <span class="o">+</span> <span class="p">(</span><span class="n">group</span><span class="p">,)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid dependency group item: </span><span class="si">{</span><span class="n">item</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">realized_group</span>
<span class="k">def</span> <span class="nf">resolve</span><span class="p">(</span><span class="n">dependency_groups</span><span class="p">:</span> <span class="nb">dict</span><span class="p">,</span> <span class="n">group</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dependency_groups</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;Dependency Groups table is not a dict&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">group</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;Dependency group name is not a str&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_resolve_dependency_group</span><span class="p">(</span><span class="n">dependency_groups</span><span class="p">,</span> <span class="n">group</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&quot;pyproject.toml&quot;</span><span class="p">,</span> <span class="s2">&quot;rb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="n">pyproject</span> <span class="o">=</span> <span class="n">tomllib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">fp</span><span class="p">)</span>
<span class="n">dependency_groups_raw</span> <span class="o">=</span> <span class="n">pyproject</span><span class="p">[</span><span class="s2">&quot;dependency-groups&quot;</span><span class="p">]</span>
<span class="n">dependency_groups</span> <span class="o">=</span> <span class="n">_normalize_group_names</span><span class="p">(</span><span class="n">dependency_groups_raw</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">resolve</span><span class="p">(</span><span class="n">pyproject</span><span class="p">[</span><span class="s2">&quot;dependency-groups&quot;</span><span class="p">],</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])))</span>
</pre></div>
</div>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>At time of writing, the <code class="docutils literal notranslate"><span class="pre">dependency-groups</span></code> namespace within a
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> file is unused. Since the top-level namespace is
reserved for use only by standards specified at packaging.python.org,
there are no direct backwards compatibility concerns.</p>
<p>However, the introduction of the feature has implications for a
number of ecosystem tools, especially those which attempt to support
examination of data in <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> and <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code>.</p>
<section id="audit-and-update-tools">
<h3><a class="toc-backref" href="#audit-and-update-tools" role="doc-backlink">Audit and Update Tools</a></h3>
<p>A wide range of tools understand Python dependency data as expressed in
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files. (e.g., Dependabot, Tidelift, etc)</p>
<p>Such tools inspect dependency data and, in some cases, offer tool-assisted or
fully automated updates.
It is our expectation that no such tools would support the new Dependency
Groups at first, and broad ecosystem support could take many months or even some
number of years to arrive.</p>
<p>As a result, users of Dependency Groups would experience a degradation in their
workflows and tool support at the time that they start using Dependency Groups.
This is true of any new standard for where and how dependency data are encoded.</p>
</section>
</section>
<section id="security-implications">
<h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2>
<p>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.</p>
<p>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
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files.</p>
</section>
<section id="how-to-teach-this">
<h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to Teach This</a></h2>
<p>This feature should be referred to by its canonical name, “Dependency Groups”.</p>
<p>The basic form of usage should be taught as a variant on typical
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> data. Standard dependency specifiers (<a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a>) can be
added to a named list. Rather than asking pip to install from a
<code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> file, either pip or a relevant workflow tool will install
from a named Dependency Group.</p>
<p>For new Python users, they may be taught directly to create a section in
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> containing their Dependency Groups, similarly to how they
are currently taught to use <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files.
This also allows new Python users to learn about <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> files
without needing to learn about package building.
A <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> file with only <code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> and no other tables
is valid.</p>
<p>For both new and experienced users, the Dependency Group Includes will need to
be explained. For users with experience using <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code>, this can be
described as an analogue for <code class="docutils literal notranslate"><span class="pre">-r</span></code>. For new users, they should be taught that
an include allows one Dependency Group to extend another. Similar configuration
interfaces and the Python <code class="docutils literal notranslate"><span class="pre">list.extend</span></code> method may be used to explain the
idea by analogy.</p>
<p>Python users who have used <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> packaging may be familiar with common
practices which predate <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>, in which package metadata is
defined dynamically. Requirements loaded from <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files and
definitions of static lists prior to <code class="docutils literal notranslate"><span class="pre">setup()</span></code> invocation readily analogize
with Dependency Groups.</p>
<section id="interfaces-for-use-of-dependency-groups">
<h3><a class="toc-backref" href="#interfaces-for-use-of-dependency-groups" role="doc-backlink">Interfaces for Use of Dependency Groups</a></h3>
<p>This specification provides no universal interface for interacting with
Dependency Groups, other than inclusion in a built package via the <code class="docutils literal notranslate"><span class="pre">project</span></code>
table. This has implications both for tool authors and for users.</p>
<p>Tool authors should determine how or if Dependency Groups are relevant to their
user stories, and build their own interfaces to fit.
For environment managers, resolvers, installers, and related non-build tools,
they will be able to document that they support “PEP 735 Dependency Groups”,
but they will be responsible for documenting their usage modes.
For build backends, supporting Dependency Groups will require support for
inclusion from the <code class="docutils literal notranslate"><span class="pre">project</span></code> table, but set no other strict requirements.</p>
<p>For users, the primary consequence is that they must consult relevant tool
documentation whenever they wish to use Dependency Groups outside of package
builds.
Users should be advised by tools, either through documentation or runtime
warnings or errors, about usages which are disrecommended or not supported.
For example, if a tool wishes to require that all Dependency Groups are
mutually compatible, containing no contradictory package specifiers, it
should document that restriction and advise users on how to appropriately
leverage Dependency Groups for its purposes.</p>
</section>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
<section id="why-not-define-each-dependency-group-as-a-table">
<h3><a class="toc-backref" href="#why-not-define-each-dependency-group-as-a-table" role="doc-backlink">Why not define each Dependency Group as a table?</a></h3>
<p>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.</p>
<p>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 <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> use-cases.</p>
</section>
<section id="why-not-define-a-special-string-syntax-to-extend-dependency-specifiers">
<h3><a class="toc-backref" href="#why-not-define-a-special-string-syntax-to-extend-dependency-specifiers" role="doc-backlink">Why not define a special string syntax to extend Dependency Specifiers?</a></h3>
<p>Earlier drafts of this specification defined syntactic forms for Dependency
Group Includes and Path Dependencies.</p>
<p>However, there were three major issues with this approach:</p>
<ul class="simple">
<li>it complicates the string syntax which must be taught, beyond PEP 508</li>
<li>the resulting strings would always need to be disambiguated from PEP 508
specifiers, complicating implementations</li>
</ul>
</section>
<section id="why-not-allow-for-more-non-pep-508-dependency-specifiers">
<h3><a class="toc-backref" href="#why-not-allow-for-more-non-pep-508-dependency-specifiers" role="doc-backlink">Why not allow for more non-PEP 508 dependency specifiers?</a></h3>
<p>Several use cases surfaced during discussion which need more expressive
specifiers than are possible with <a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a>.</p>
<p>“Path Dependencies”, referring to local paths, and references to
<code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> were of particular interest.</p>
<p>However, there are no existing standards for these features (excepting the
de-facto standard of <code class="docutils literal notranslate"><span class="pre">pip</span></code>s implementation details).</p>
<p>As a result, attempting to include these features in this PEP results in a
significant growth in scope, to attempt to standardize these various features
and <code class="docutils literal notranslate"><span class="pre">pip</span></code> behaviors.</p>
<p>Special attention was devoted to attempting to standardize the expression of
editable installations, as expressed by <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-e</span></code> and <a class="pep reference internal" href="../pep-0660/" title="PEP 660 Editable installs for pyproject.toml based builds (wheel based)">PEP 660</a>.
However, although the creation of editable installs is standardized for build
backends, the behavior of editables is not standardized for installers.
Inclusion of editables in this PEP requires that any supporting tool allows for
the installation of editables.</p>
<p>Therefore, although Poetry and PDM provide syntaxes for some of these features,
they are considered insufficiently standardized at present for inclusion in
Dependency Groups.</p>
</section>
<section id="why-is-the-table-not-named-run-project-dependency-groups">
<h3><a class="toc-backref" href="#why-is-the-table-not-named-run-project-dependency-groups" role="doc-backlink">Why is the table not named <code class="docutils literal notranslate"><span class="pre">[run]</span></code>, <code class="docutils literal notranslate"><span class="pre">[project.dependency-groups]</span></code>, …?</a></h3>
<p>There are many possible names for this concept.
It will have to live alongside the already existing <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code>
and <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code> tables, and possibly a new
<code class="docutils literal notranslate"><span class="pre">[external]</span></code> dependency table as well (at time of writing, <a class="pep reference internal" href="../pep-0725/" title="PEP 725 Specifying external dependencies in pyproject.toml">PEP 725</a>, which
defines the <code class="docutils literal notranslate"><span class="pre">[external]</span></code> table, is in progress).</p>
<p><code class="docutils literal notranslate"><span class="pre">[run]</span></code> 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 <code class="docutils literal notranslate"><span class="pre">[run]</span></code> a less
appropriate fit this is not just dependency data for a specific runtime
context, but for multiple contexts.</p>
<p><code class="docutils literal notranslate"><span class="pre">[project.dependency-groups]</span></code> would offer a nice parallel with
<code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> and <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code>, but has
major downsides for non-package projects.
<code class="docutils literal notranslate"><span class="pre">[project]</span></code> requires several keys to be defined, such as <code class="docutils literal notranslate"><span class="pre">name</span></code> and
<code class="docutils literal notranslate"><span class="pre">version</span></code>. Using this name would either require redefining the <code class="docutils literal notranslate"><span class="pre">[project]</span></code>
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.</p>
</section>
<section id="why-is-pip-s-planned-implementation-of-only-deps-not-sufficient">
<h3><a class="toc-backref" href="#why-is-pip-s-planned-implementation-of-only-deps-not-sufficient" role="doc-backlink">Why is pips planned implementation of <code class="docutils literal notranslate"><span class="pre">--only-deps</span></code> not sufficient?</a></h3>
<p>pip currently has a feature on the roadmap to add an
<a class="reference external" href="https://github.com/pypa/pip/issues/11440">only-deps flag</a>.
This flag is intended to allow users to install package dependencies and extras
without installing the current package.</p>
<p>It does not address the needs of non-package projects, nor does it allow for
the installation of an extra without the package dependencies.</p>
</section>
<section id="why-isn-t-environment-manager-a-solution">
<h3><a class="toc-backref" href="#why-isn-t-environment-manager-a-solution" role="doc-backlink">Why isnt &lt;environment manager&gt; a solution?</a></h3>
<p>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 <em>good</em> but they are not <em>sufficient</em>.</p>
<p>First, they do not address the needs of non-package projects.</p>
<p>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 <code class="docutils literal notranslate"><span class="pre">tox.ini</span></code> files.)</p>
</section>
</section>
<section id="deferred-ideas">
<h2><a class="toc-backref" href="#deferred-ideas" role="doc-backlink">Deferred Ideas</a></h2>
<section id="why-not-support-dependency-group-includes-in-project-dependencies-or-project-optional-dependencies">
<h3><a class="toc-backref" href="#why-not-support-dependency-group-includes-in-project-dependencies-or-project-optional-dependencies" role="doc-backlink">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> or <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code>?</a></h3>
<p>Earlier drafts of this specification allowed Dependency Group Includes to be
used in the <code class="docutils literal notranslate"><span class="pre">[project]</span></code> table.
However, there were several issues raised during community feedback which led
to its removal.</p>
<p>Only a small number of additional use cases would be addressed by the inclusion
of Dependency Groups, and it increased the scope of the specification
significantly. In particular, this inclusion would increase the number of parties
impacted by the addition. Many readers of the <code class="docutils literal notranslate"><span class="pre">[project]</span></code> table, including build
backends, SBOM generators, and dependency analyzers are implicated by a change to
<code class="docutils literal notranslate"><span class="pre">[project]</span></code> but may continue to operate as-is in the presence of a new (but
unconnected) <code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> table.</p>
<p>Separately from the above concern, allowing inclusion of dependency groups from the
<code class="docutils literal notranslate"><span class="pre">[project]</span></code> table encourages package maintainers to move dependency metadata out
of the current standard location.
This complicates static <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> metadata and conflicts with the goal of
<a class="pep reference internal" href="../pep-0621/" title="PEP 621 Storing project metadata in pyproject.toml">PEP 621</a> to store dependency metadata in a single location.</p>
<p>Finally, exclusion of <code class="docutils literal notranslate"><span class="pre">[project]</span></code> support from this PEP is not final. The
use of includes from that table, or an inclusion syntax from
<code class="docutils literal notranslate"><span class="pre">[dependency-groups]</span></code> into <code class="docutils literal notranslate"><span class="pre">[project]</span></code>, could be introduced by a future
PEP and considered on its own merits.</p>
<section id="use-cases-for-dependency-group-includes-from-project">
<h4><a class="toc-backref" href="#use-cases-for-dependency-group-includes-from-project" role="doc-backlink">Use Cases for Dependency Group Includes From <code class="docutils literal notranslate"><span class="pre">[project]</span></code></a></h4>
<p>Although deferred in this PEP, allowing includes from the <code class="docutils literal notranslate"><span class="pre">[project]</span></code>
table would address several use cases.</p>
<p>In particular, there are cases in which package developers would like to
install only the dependencies of a package, without the package itself.</p>
<p>For example:</p>
<ul class="simple">
<li>Specify different environment variables or options when building dependencies
vs when building the package itself</li>
<li>Creating layered container images in which the dependencies are isolated from
the package being installed</li>
<li>Providing the dependencies to analysis environments (e.g., type checking)
without having to build and install the package itself</li>
</ul>
<p>For an example of the last case, consider the following sample
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[project]</span>
<span class="n">dependencies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;runtime&quot;</span><span class="p">}]</span>
<span class="k">[optional-dependencies]</span>
<span class="n">foo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;foo&quot;</span><span class="p">}]</span>
<span class="k">[dependency-groups]</span>
<span class="n">runtime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;a&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;b&quot;</span><span class="p">]</span>
<span class="n">foo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;c&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;d&quot;</span><span class="p">]</span>
<span class="n">typing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;mypy&quot;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="n">include</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;runtime&quot;</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="n">include</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;foo&quot;</span><span class="p">}]</span>
</pre></div>
</div>
<p>In this case, a <code class="docutils literal notranslate"><span class="pre">typing</span></code> group can be defined, with all of the packages
runtime dependencies, but without the package itself. This allows uses of the
<code class="docutils literal notranslate"><span class="pre">typing</span></code> Dependency Group to skip installation of the package not only is
this more efficient, but it may reduce the requirements for testing systems.</p>
</section>
</section>
<section id="why-not-support-dependency-group-includes-in-build-system-requires">
<h3><a class="toc-backref" href="#why-not-support-dependency-group-includes-in-build-system-requires" role="doc-backlink">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[build-system.requires]</span></code>?</a></h3>
<p>Given that we will not allow for <code class="docutils literal notranslate"><span class="pre">[project]</span></code> usage of Dependency Groups,
<code class="docutils literal notranslate"><span class="pre">[build-system.requires]</span></code> can be considered in comparison with
<code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code>.</p>
<p>There are fewer theoretical usages for build requirements specified in a group
than package requirements. Additionally, the impact of such a change implicates
<a class="pep reference internal" href="../pep-0517/" title="PEP 517 A build-system independent format for source trees">PEP 517</a> frontend, which would need to support Dependency Groups in order to
prepare a build environment.</p>
<p>Compared with changes to <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> and
<code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code>, changing the behaviors of
<code class="docutils literal notranslate"><span class="pre">[build-system.requires]</span></code> is higher impact and has fewer potential uses.
Therefore, given that this PEP declines to make changes to the <code class="docutils literal notranslate"><span class="pre">[project]</span></code>
table, changing <code class="docutils literal notranslate"><span class="pre">[build-system]</span></code> is also deferred.</p>
</section>
<section id="why-not-support-a-dependency-group-which-includes-the-current-project">
<h3><a class="toc-backref" href="#why-not-support-a-dependency-group-which-includes-the-current-project" role="doc-backlink">Why not support a Dependency Group which includes the current project?</a></h3>
<p>Several usage scenarios for dependency groups revolve around installing a
dependency group alongside a package defined in the <code class="docutils literal notranslate"><span class="pre">[project]</span></code> table.
For example, testing a package involves installing testing dependencies and the
package itself. Additionally, the compatibility of a dependency group with the
main package is a valuable input to lockfile generators.</p>
<p>In such cases, it is desirable for a Dependency Group to declare that it
depends upon the project itself. Example syntaxes from discussions included
<code class="docutils literal notranslate"><span class="pre">{include-project</span> <span class="pre">=</span> <span class="pre">true}</span></code> and <code class="docutils literal notranslate"><span class="pre">{include-group</span> <span class="pre">=</span> <span class="pre">&quot;:project:&quot;}</span></code>.</p>
<p>However, if a specification is established to extend <a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a> with Path
Dependencies, this would result in Dependency Groups having two ways of
specifying the main package. For example, if <code class="docutils literal notranslate"><span class="pre">.</span></code> becomes formally supported,
and <code class="docutils literal notranslate"><span class="pre">{include-project</span> <span class="pre">=</span> <span class="pre">true}</span></code> is included in this PEP, then dependency
groups may specify any of the following groups</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">case1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-project</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">true</span><span class="p">}]</span>
<span class="n">case2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;.&quot;</span><span class="p">]</span>
<span class="n">case3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-project</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">true</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;.&quot;</span><span class="p">]</span>
<span class="n">case4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-project</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">false</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;.&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>In order to avoid a confusing future in which multiple different options
specify the package defined in <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>, any syntax for declaring
this relationship is omitted from this PEP.</p>
</section>
</section>
<section id="appendix-a-prior-art-in-non-python-languages">
<span id="prior-art"></span><h2><a class="toc-backref" href="#appendix-a-prior-art-in-non-python-languages" role="doc-backlink">Appendix A: Prior Art in Non-Python Languages</a></h2>
<p>This section is primarily informational and serves to document how other
language ecosystems solve similar problems.</p>
<section id="javascript-and-package-json">
<span id="javascript-prior-art"></span><h3><a class="toc-backref" href="#javascript-and-package-json" role="doc-backlink">JavaScript and <code class="docutils literal notranslate"><span class="pre">package.json</span></code></a></h3>
<p>In the JavaScript community, packages contain a canonical configuration and
data file, similar in scope to <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>, at <code class="docutils literal notranslate"><span class="pre">package.json</span></code>.</p>
<p>Two keys in <code class="docutils literal notranslate"><span class="pre">package.json</span></code> control dependency data: <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> and
<code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code>. The role of <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> is effectively the same
as that of <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> in <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>, declaring the
direct dependencies of a package.</p>
<section id="dependencies-data">
<h4><a class="toc-backref" href="#dependencies-data" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> data</a></h4>
<p>Dependency data is declared in <code class="docutils literal notranslate"><span class="pre">package.json</span></code> as a mapping from package names
to version specifiers.</p>
<p>Version specifiers support a small grammar of possible versions, ranges, and
other values, similar to Pythons <a class="pep reference internal" href="../pep-0440/" title="PEP 440 Version Identification and Dependency Specification">PEP 440</a> version specifiers.</p>
<p>For example, here is a partial <code class="docutils literal notranslate"><span class="pre">package.json</span></code> file declaring a few
dependencies:</p>
<div class="highlight-json notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;dependencies&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;@angular/compiler&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;^17.0.2&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;camelcase&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;8.0.0&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;diff&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;&gt;=5.1.0 &lt;6.0.0&quot;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The use of the <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> symbol is a <a class="reference external" href="https://docs.npmjs.com/cli/v10/using-npm/scope">scope</a> which declares the package
owner, for organizationally owned packages.
<code class="docutils literal notranslate"><span class="pre">&quot;&#64;angular/compiler&quot;</span></code> therefore declares a package named <code class="docutils literal notranslate"><span class="pre">compiler</span></code> grouped
under <code class="docutils literal notranslate"><span class="pre">angular</span></code> ownership.</p>
</section>
<section id="dependencies-referencing-urls-and-local-paths">
<h4><a class="toc-backref" href="#dependencies-referencing-urls-and-local-paths" role="doc-backlink">Dependencies Referencing URLs and Local Paths</a></h4>
<p>Dependency specifiers support a syntax for URLs and Git repositories, similar
to the provisions in Python packaging.</p>
<p>URLs may be used in lieu of version numbers.
When used, they implicitly refer to tarballs of package source code.</p>
<p>Git repositories may be similarly used, including support for committish
specifiers.</p>
<p>Unlike <a class="pep reference internal" href="../pep-0440/" title="PEP 440 Version Identification and Dependency Specification">PEP 440</a>, NPM allows for the use of local paths to package source code
directories for dependencies. When these data are added to <code class="docutils literal notranslate"><span class="pre">package.json</span></code> via
the standard <code class="docutils literal notranslate"><span class="pre">npm</span> <span class="pre">install</span> <span class="pre">--save</span></code> command, the path is normalized to a
relative path, from the directory containing <code class="docutils literal notranslate"><span class="pre">package.json</span></code>, and prefixed
with <code class="docutils literal notranslate"><span class="pre">file:</span></code>. For example, the following partial <code class="docutils literal notranslate"><span class="pre">package.json</span></code> contains a
reference to a sibling of the current directory:</p>
<div class="highlight-json notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;dependencies&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;my-package&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;file:../foo&quot;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The <a class="reference external" href="https://docs.npmjs.com/cli/v8/configuring-npm/package-json#local-paths">official NPM documentation</a>
states that local path dependencies “should not” be published to public package
repositories, but makes no statement about the inherent validity or invalidity
of such dependency data in published packages.</p>
</section>
<section id="devdependencies-data">
<h4><a class="toc-backref" href="#devdependencies-data" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code> data</a></h4>
<p><code class="docutils literal notranslate"><span class="pre">package.json</span></code> is permitted to contain a second section named
<code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code>, in the same format as <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code>.
The dependencies declared in <code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code> are not installed by default
when a package is installed from the package repository (e.g. as part of a
dependency being resolved) but are installed when <code class="docutils literal notranslate"><span class="pre">npm</span> <span class="pre">install</span></code> is run in the
source tree containing <code class="docutils literal notranslate"><span class="pre">package.json</span></code>.</p>
<p>Just as <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> supports URLs and local paths, so does
<code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code>.</p>
</section>
<section id="peerdependencies-and-optionaldependencies">
<h4><a class="toc-backref" href="#peerdependencies-and-optionaldependencies" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependencies&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;optionalDependencies&quot;</span></code></a></h4>
<p>There are two additional, related sections in <code class="docutils literal notranslate"><span class="pre">package.json</span></code> which have
relevance.</p>
<p><code class="docutils literal notranslate"><span class="pre">&quot;peerDependencies&quot;</span></code> declares a list of dependencies in the same format as
<code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code>, but with the meaning that these are a compatibility
declaration.
For example, the following data declares compatibility with package <code class="docutils literal notranslate"><span class="pre">foo</span></code>
version 2:</p>
<div class="highlight-json notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;peerDependencies&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;foo&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2.x&quot;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">&quot;optionalDependencies&quot;</span></code> declares a list of dependencies which should be
installed if possible, but which should not be treated as failures if they are
unavailable. It also uses the same mapping format as <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code>.</p>
<section id="peerdependenciesmeta">
<h5><a class="toc-backref" href="#peerdependenciesmeta" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependenciesMeta&quot;</span></code></a></h5>
<p><code class="docutils literal notranslate"><span class="pre">&quot;peerDependenciesMeta&quot;</span></code> is a section which allows for additional control
over how <code class="docutils literal notranslate"><span class="pre">&quot;peerDependencies&quot;</span></code> are treated.</p>
<p>Warnings about missing dependencies can be disabled by setting packages to
<code class="docutils literal notranslate"><span class="pre">optional</span></code> in this section, as in the following sample:</p>
<div class="highlight-json notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;peerDependencies&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;foo&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2.x&quot;</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">&quot;peerDependenciesMeta&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;foo&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;optional&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
</section>
<section id="omit-and-include">
<h4><a class="toc-backref" href="#omit-and-include" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">--omit</span></code> and <code class="docutils literal notranslate"><span class="pre">--include</span></code></a></h4>
<p>The <code class="docutils literal notranslate"><span class="pre">npm</span> <span class="pre">install</span></code> command supports two options, <code class="docutils literal notranslate"><span class="pre">--omit</span></code> and <code class="docutils literal notranslate"><span class="pre">--include</span></code>,
which can control whether “prod”, “dev”, “optional”, or “peer” dependencies are installed.</p>
<p>The “prod” name refers to dependencies listed under <code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code>.</p>
<p>By default, all four groups are installed when <code class="docutils literal notranslate"><span class="pre">npm</span> <span class="pre">install</span></code> is executed
against a source tree, but these options can be used to control installation
behavior more precisely.
Furthermore, these values can be declared in <code class="docutils literal notranslate"><span class="pre">.npmrc</span></code> files, allowing
per-user and per-project configurations to control installation behaviors.</p>
</section>
</section>
<section id="ruby-ruby-gems">
<span id="ruby-prior-art"></span><h3><a class="toc-backref" href="#ruby-ruby-gems" role="doc-backlink">Ruby &amp; Ruby Gems</a></h3>
<p>Ruby projects may or may not be intended to produce packages (“gems”) in the
Ruby ecosystem. In fact, the expectation is that most users of the language do
not want to produce gems and have no interest in producing their own packages.
Many tutorials do not touch on how to produce packages, and the toolchain never
requires user code to be packaged for supported use-cases.</p>
<p>Ruby splits requirement specification into two separate files.</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">Gemfile</span></code>: a dedicated file which only supports requirement data in the form
of dependency groups</li>
<li><code class="docutils literal notranslate"><span class="pre">&lt;package&gt;.gemspec</span></code>: a dedicated file for declaring package (gem) metadata</li>
</ul>
<p>The <code class="docutils literal notranslate"><span class="pre">bundler</span></code> tool, providing the <code class="docutils literal notranslate"><span class="pre">bundle</span></code> command, is the primary interface
for using <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> data.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">gem</span></code> tool is responsible for building gems from <code class="docutils literal notranslate"><span class="pre">.gemspec</span></code> data, via the
<code class="docutils literal notranslate"><span class="pre">gem</span> <span class="pre">build</span></code> command.</p>
<section id="gemfiles-bundle">
<h4><a class="toc-backref" href="#gemfiles-bundle" role="doc-backlink">Gemfiles &amp; bundle</a></h4>
<p>A <a class="reference external" href="https://bundler.io/v1.12/man/gemfile.5.html">Gemfile</a> is a Ruby file
containing <code class="docutils literal notranslate"><span class="pre">gem</span></code> directives enclosed in any number of <code class="docutils literal notranslate"><span class="pre">group</span></code> declarations.
<code class="docutils literal notranslate"><span class="pre">gem</span></code> directives may also be used outside of the <code class="docutils literal notranslate"><span class="pre">group</span></code> declaration, in which
case they form an implicitly unnamed group of dependencies.</p>
<p>For example, the following <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> lists <code class="docutils literal notranslate"><span class="pre">rails</span></code> as a project dependency.
All other dependencies are listed under groups:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="n">source</span><span class="w"> </span><span class="s1">&#39;https://rubygems.org&#39;</span>
<span class="n">gem</span><span class="w"> </span><span class="s1">&#39;rails&#39;</span>
<span class="n">group</span><span class="w"> </span><span class="ss">:test</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;rspec&#39;</span>
<span class="k">end</span>
<span class="n">group</span><span class="w"> </span><span class="ss">:lint</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;rubocop&#39;</span>
<span class="k">end</span>
<span class="n">group</span><span class="w"> </span><span class="ss">:docs</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;kramdown&#39;</span>
<span class="w"> </span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;nokogiri&#39;</span>
<span class="k">end</span>
</pre></div>
</div>
<p>If a user executes <code class="docutils literal notranslate"><span class="pre">bundle</span> <span class="pre">install</span></code> with these data, all groups are
installed. Users can deselect groups by creating or modifying a bundler config
in <code class="docutils literal notranslate"><span class="pre">.bundle/config</span></code>, either manually or via the CLI. For example, <code class="docutils literal notranslate"><span class="pre">bundle</span>
<span class="pre">config</span> <span class="pre">set</span> <span class="pre">--local</span> <span class="pre">without</span> <span class="pre">'lint:docs'</span></code>.</p>
<p>It is not possible, with the above data, to exclude the top-level use of the
<code class="docutils literal notranslate"><span class="pre">'rails'</span></code> gem or to refer to that implicit grouping by name.</p>
</section>
<section id="gemspec-and-packaged-dependency-data">
<h4><a class="toc-backref" href="#gemspec-and-packaged-dependency-data" role="doc-backlink">gemspec and packaged dependency data</a></h4>
<p>A <a class="reference external" href="https://guides.rubygems.org/specification-reference/">gemspec file</a> is a
ruby file containing a <a class="reference external" href="https://ruby-doc.org/stdlib-3.0.1/libdoc/rubygems/rdoc/Gem/Specification.html">Gem::Specification</a>
instance declaration.</p>
<p>Only two fields in a <code class="docutils literal notranslate"><span class="pre">Gem::Specification</span></code> pertain to package dependency data.
These are <code class="docutils literal notranslate"><span class="pre">add_development_dependency</span></code> and <code class="docutils literal notranslate"><span class="pre">add_runtime_dependency</span></code>.
A <code class="docutils literal notranslate"><span class="pre">Gem::Specification</span></code> object also provides methods for adding dependencies
dynamically, including <code class="docutils literal notranslate"><span class="pre">add_dependency</span></code> (which adds a runtime dependency).</p>
<p>Here is a variant of the <code class="docutils literal notranslate"><span class="pre">rails.gemspec</span></code> file, with many fields removed or
shortened to simplify:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="n">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;7.1.2&#39;</span>
<span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="o">.</span><span class="n">new</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">platform</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">Gem</span><span class="o">::</span><span class="no">Platform</span><span class="o">::</span><span class="no">RUBY</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;rails&quot;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">version</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">summary</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Full-stack web application framework.&quot;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">license</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;MIT&quot;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;David Heinemeier Hansson&quot;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span><span class="s2">&quot;README.md&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;MIT-LICENSE&quot;</span><span class="o">]</span>
<span class="w"> </span><span class="c1"># shortened from the real &#39;rails&#39; project</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;activesupport&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">version</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;activerecord&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">version</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;actionmailer&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">version</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;activestorage&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">version</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;railties&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">version</span>
<span class="k">end</span>
</pre></div>
</div>
<p>Note that there is no use of <code class="docutils literal notranslate"><span class="pre">add_development_dependency</span></code>.
Some other mainstream, major packages (e.g. <code class="docutils literal notranslate"><span class="pre">rubocop</span></code>) do not use development
dependencies in their gems.</p>
<p>Other projects <em>do</em> use this feature. For example, <code class="docutils literal notranslate"><span class="pre">kramdown</span></code> makes use of
development dependencies, containing the following specification in its
<code class="docutils literal notranslate"><span class="pre">Rakefile</span></code>:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s2">&quot;rexml&quot;</span>
<span class="n">s</span><span class="o">.</span><span class="n">add_development_dependency</span><span class="w"> </span><span class="s1">&#39;minitest&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;~&gt; 5.0&#39;</span>
<span class="n">s</span><span class="o">.</span><span class="n">add_development_dependency</span><span class="w"> </span><span class="s1">&#39;rouge&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;~&gt; 3.0&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;&gt;= 3.26.0&#39;</span>
<span class="n">s</span><span class="o">.</span><span class="n">add_development_dependency</span><span class="w"> </span><span class="s1">&#39;stringex&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;~&gt; 1.5.1&#39;</span>
</pre></div>
</div>
<p>The purpose of development dependencies is only to declare an implicit group,
as part of the <code class="docutils literal notranslate"><span class="pre">.gemspec</span></code>, which can then be used by <code class="docutils literal notranslate"><span class="pre">bundler</span></code>.</p>
<p>For full details, see the <code class="docutils literal notranslate"><span class="pre">gemspec</span></code> directive in <code class="docutils literal notranslate"><span class="pre">bundler</span></code>'s
<a class="reference external" href="https://bundler.io/v1.12/man/gemfile.5.html#GEMSPEC-gemspec-">documentation on Gemfiles</a>.
However, the integration between <code class="docutils literal notranslate"><span class="pre">.gemspec</span></code> development dependencies and
<code class="docutils literal notranslate"><span class="pre">Gemfile</span></code>/<code class="docutils literal notranslate"><span class="pre">bundle</span></code> usage is best understood via an example.</p>
<section id="gemspec-development-dependency-example">
<h5><a class="toc-backref" href="#gemspec-development-dependency-example" role="doc-backlink">gemspec development dependency example</a></h5>
<p>Consider the following simple project in the form of a <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> and <code class="docutils literal notranslate"><span class="pre">.gemspec</span></code>.
The <code class="docutils literal notranslate"><span class="pre">cool-gem.gemspec</span></code> file:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="o">.</span><span class="n">new</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="o">|</span><span class="n">s</span><span class="o">|</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Stephen Rosen&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;cool-gem&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;0.0.1&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">summary</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;A very cool gem that does cool stuff&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">license</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;MIT&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[]</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="w"> </span><span class="s1">&#39;rails&#39;</span>
<span class="w"> </span><span class="n">s</span><span class="o">.</span><span class="n">add_development_dependency</span><span class="w"> </span><span class="s1">&#39;kramdown&#39;</span>
<span class="k">end</span>
</pre></div>
</div>
<p>and the <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code>:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="n">source</span><span class="w"> </span><span class="s1">&#39;https://rubygems.org&#39;</span>
<span class="n">gemspec</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">gemspec</span></code> directive in <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> declares a dependency on the local
package, <code class="docutils literal notranslate"><span class="pre">cool-gem</span></code>, defined in the locally available <code class="docutils literal notranslate"><span class="pre">cool-gem.gemspec</span></code>
file. It <em>also</em> implicitly adds all development dependencies to a dependency
group named <code class="docutils literal notranslate"><span class="pre">development</span></code>.</p>
<p>Therefore, in this case, the <code class="docutils literal notranslate"><span class="pre">gemspec</span></code> directive is equivalent to the
following <code class="docutils literal notranslate"><span class="pre">Gemfile</span></code> content:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;cool-gem&#39;</span><span class="p">,</span><span class="w"> </span><span class="ss">:path</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="s1">&#39;.&#39;</span>
<span class="n">group</span><span class="w"> </span><span class="ss">:development</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="n">gem</span><span class="w"> </span><span class="s1">&#39;kramdown&#39;</span>
<span class="k">end</span>
</pre></div>
</div>
</section>
</section>
</section>
</section>
<section id="appendix-b-prior-art-in-python">
<span id="python-prior-art"></span><h2><a class="toc-backref" href="#appendix-b-prior-art-in-python" role="doc-backlink">Appendix B: Prior Art in Python</a></h2>
<p>In the absence of any prior standard for Dependency Groups, two known workflow
tools, PDM and Poetry, have defined their own solutions.</p>
<p>This section will primarily focus on these two tools as cases of prior art
regarding the definition and use of Dependency Groups in Python.</p>
<section id="projects-are-packages">
<h3><a class="toc-backref" href="#projects-are-packages" role="doc-backlink">Projects are Packages</a></h3>
<p>Both PDM and Poetry treat the projects they support as packages.
This allows them to use and interact with standard <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> metadata
for some of their needs, and allows them to support installation of the
“current project” by doing a build and install using their build backends.</p>
<p>Effectively, this means that neither Poetry nor PDM supports non-package projects.</p>
</section>
<section id="non-standard-dependency-specifiers">
<h3><a class="toc-backref" href="#non-standard-dependency-specifiers" role="doc-backlink">Non-Standard Dependency Specifiers</a></h3>
<p>PDM and Poetry extend <a class="pep reference internal" href="../pep-0508/" title="PEP 508 Dependency specification for Python Software Packages">PEP 508</a> dependency specifiers with additional features
which are not part of any shared standard.
The two tools use slightly different approaches to these problems, however.</p>
<p>PDM supports specifying local paths, and editable installs, via a syntax which
looks like a set of arguments to <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span></code>. For example, the following
dependency group includes a local package in editable mode:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[tool.pdm.dev-dependencies]</span>
<span class="n">mygroup</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;-e file:///${PROJECT_ROOT}/foo&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>This declares a dependency group <code class="docutils literal notranslate"><span class="pre">mygroup</span></code> which includes a local editable
install from the <code class="docutils literal notranslate"><span class="pre">foo</span></code> directory.</p>
<p>Poetry describes dependency groups as tables, mapping package names to
specifiers. For example, the same configuration as the above <code class="docutils literal notranslate"><span class="pre">mygroup</span></code>
example might appear as follows under Poetry:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[tool.poetry.group.mygroup]</span>
<span class="n">foo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;foo&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">editable</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="p">}</span>
</pre></div>
</div>
<p>PDM restricts itself to a string syntax, and Poetry introduces tables which
describe dependencies.</p>
</section>
<section id="installing-and-referring-to-dependency-groups">
<h3><a class="toc-backref" href="#installing-and-referring-to-dependency-groups" role="doc-backlink">Installing and Referring to Dependency Groups</a></h3>
<p>Both PDM and Poetry have tool-specific support for installing dependency
groups. Because both projects support their own lockfile formats, they also
both have the capability to transparently use a dependency group name to refer
to the <em>locked</em> dependency data for that group.</p>
<p>However, neither tools dependency groups can be referenced natively from other
tools like <code class="docutils literal notranslate"><span class="pre">tox</span></code>, <code class="docutils literal notranslate"><span class="pre">nox</span></code>, or <code class="docutils literal notranslate"><span class="pre">pip</span></code>.
Attempting to install a dependency group under <code class="docutils literal notranslate"><span class="pre">tox</span></code>, for example, requires
an explicit call to PDM or Poetry to parse their dependency data and do the
relevant installation step.</p>
</section>
</section>
<section id="appendix-c-use-cases">
<span id="id1"></span><h2><a class="toc-backref" href="#appendix-c-use-cases" role="doc-backlink">Appendix C: Use Cases</a></h2>
<section id="web-applications">
<h3><a class="toc-backref" href="#web-applications" role="doc-backlink">Web Applications</a></h3>
<p>A web application (e.g. a Django or Flask app) often does not need to build a
distribution, but bundles and ships its source to a deployment toolchain.</p>
<p>For example, a source code repository may define Python packaging metadata as
well as containerization or other build pipeline metadata (<code class="docutils literal notranslate"><span class="pre">Dockerfile</span></code>,
etc).
The Python application is built by copying the entire repository into a
build context, installing dependencies, and bundling the result as a machine
image or container.</p>
<p>Such applications have dependency groups for the build, but also for linting,
testing, etc. In practice, today, these applications often define themselves as
packages to be able to use packaging tools and mechanisms like <code class="docutils literal notranslate"><span class="pre">extras</span></code> to
manage their dependency groups. However, they are not conceptually packages,
meant for distribution in sdist or wheel format.</p>
<p>Dependency Groups allow these applications to define their various dependencies
without relying on packaging metadata, and without trying to express their
needs in packaging terms.</p>
</section>
<section id="libraries">
<h3><a class="toc-backref" href="#libraries" role="doc-backlink">Libraries</a></h3>
<p>Libraries are Python packages which build distributions (sdist and wheel) and
publish them to PyPI.</p>
<p>For libraries, Dependency Groups represent an alternative to <code class="docutils literal notranslate"><span class="pre">extras</span></code> for
defining groups of development dependencies, with the important advantages
noted above.</p>
<p>A library may define groups for <code class="docutils literal notranslate"><span class="pre">test</span></code> and <code class="docutils literal notranslate"><span class="pre">typing</span></code> which allow testing and
type-checking, and therefore rely on the librarys own dependencies (as
specified in <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code>).</p>
<p>Other development needs may not require installation of the package at all. For
example, a <code class="docutils literal notranslate"><span class="pre">lint</span></code> Dependency Group may be valid and faster to install without
the library, as it only installs tools like <code class="docutils literal notranslate"><span class="pre">black</span></code>, <code class="docutils literal notranslate"><span class="pre">ruff</span></code>, or <code class="docutils literal notranslate"><span class="pre">flake8</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">lint</span></code> and <code class="docutils literal notranslate"><span class="pre">test</span></code> environments may also be valuable locations to hook in
IDE or editor support. See the case below for a fuller description of such
usage.</p>
<p>Heres an example Dependency Groups table which might be suitable for a
library:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pytest&lt;8&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;coverage&quot;</span><span class="p">]</span>
<span class="n">typing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;mypy==1.7.1&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;types-requests&quot;</span><span class="p">]</span>
<span class="n">lint</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;black&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;flake8&quot;</span><span class="p">]</span>
<span class="n">typing-test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;typing&quot;</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;pytest&lt;8&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>Note that none of these implicitly install the library itself.
It is therefore the responsibility of any environment management toolchain to
install the appropriate Dependency Groups along with the library when needed,
as in the case of <code class="docutils literal notranslate"><span class="pre">test</span></code>.</p>
</section>
<section id="data-science-projects">
<h3><a class="toc-backref" href="#data-science-projects" role="doc-backlink">Data Science Projects</a></h3>
<p>Data Science Projects typically take the form of a logical collection of
scripts and utilities for processing and analyzing data, using a common
toolchain. Components may be defined in the Jupyter Notebook format (ipynb),
but rely on the same common core set of utilities.</p>
<p>In such a project, there is no package to build or install. Therefore,
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> currently does not offer any solution for dependency
management or declaration.</p>
<p>It is valuable for such a project to be able to define at least one major
grouping of dependencies. For example:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">main</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;numpy&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;pandas&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;matplotlib&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>However, it may also be necessary for various scripts to have additional
supporting tools. Projects may even have conflicting or incompatible tools or
tool versions for different components, as they evolve over time.</p>
<p>Consider the following more elaborate configuration:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">main</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;numpy&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;pandas&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;matplotlib&quot;</span><span class="p">]</span>
<span class="n">scikit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;main&quot;</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;scikit-learn==1.3.2&quot;</span><span class="p">]</span>
<span class="n">scikit-old</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[{</span><span class="n">include-group</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s2">&quot;main&quot;</span><span class="p">},</span><span class="w"> </span><span class="s2">&quot;scikit-learn==0.24.2&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>This defines <code class="docutils literal notranslate"><span class="pre">scikit</span></code> and <code class="docutils literal notranslate"><span class="pre">scikit-old</span></code> as two similar variants of the
common suite of dependencies, pulling in different versions of <code class="docutils literal notranslate"><span class="pre">scikit-learn</span></code>
to suit different scripts.</p>
<p>This PEP only defines these data. It does not formalize any mechanism for a
Data Science Project (or any other type of project) to install the dependencies
into known environments or associate those environments with the various
scripts. Such combinations of data are left as a problem for tool authors to
solve, and perhaps eventually standardize.</p>
</section>
<section id="lockfile-generation">
<h3><a class="toc-backref" href="#lockfile-generation" role="doc-backlink">Lockfile Generation</a></h3>
<p>There are a number of tools which generate lockfiles in the Python ecosystem
today. PDM and Poetry each use their own lockfile formats, and pip-tools
generates <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files with version pins and hashes.</p>
<p>Dependency Groups are not an appropriate place to store lockfiles, as they lack
many of the necessary features. Most notably, they cannot store hashes, which
most lockfile users consider essential.</p>
<p>However, Dependency Groups are a valid input to tools which generate lockfiles.
Furthermore, PDM and Poetry both allow a Dependency Group name (under their
notions of Dependency Groups) to be used to refer to its locked variant.</p>
<p>Therefore, consider a tool which produces lockfiles, here called <code class="docutils literal notranslate"><span class="pre">$TOOL</span></code>.
It might be used as follows:</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="nv">$TOOL</span><span class="w"> </span>lock<span class="w"> </span>--dependency-group<span class="o">=</span><span class="nb">test</span>
<span class="nv">$TOOL</span><span class="w"> </span>install<span class="w"> </span>--dependency-group<span class="o">=</span><span class="nb">test</span><span class="w"> </span>--use-locked
</pre></div>
</div>
<p>All that such a tool needs to do is to ensure that its lockfile data records
the name <code class="docutils literal notranslate"><span class="pre">test</span></code> in order to support such usage.</p>
<p>The mutual compatibility of Dependency Groups is not guaranteed. For example,
the Data Science example above shows conflicting versions of <code class="docutils literal notranslate"><span class="pre">scikit-learn</span></code>.
Therefore, installing multiple locked dependency groups in tandem may require
that tools apply additional constraints or generate additional lockfile data.
These problems are considered out of scope for this PEP.</p>
<p>As two examples of how combinations might be locked:</p>
<ul class="simple">
<li>A tool might require that lockfile data be explicitly generated for any
combination to be considered valid</li>
<li>Poetry implements the requirement that all Dependency Groups be mutually
compatible, and generates only one locked version. (Meaning it finds a single
solution, rather than a set or matrix of solutions.)</li>
</ul>
</section>
<section id="environment-manager-inputs">
<h3><a class="toc-backref" href="#environment-manager-inputs" role="doc-backlink">Environment Manager Inputs</a></h3>
<p>A common usage in tox, Nox, and Hatch is to install a set of dependencies into
a testing environment.</p>
<p>For example, under <code class="docutils literal notranslate"><span class="pre">tox.ini</span></code>, type checking dependencies may be defined
inline:</p>
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="k">[testenv:typing]</span>
<span class="na">deps</span><span class="w"> </span><span class="o">=</span>
<span class="w"> </span><span class="na">pyright</span>
<span class="w"> </span><span class="na">useful-types</span>
<span class="na">commands</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">pyright src/</span>
</pre></div>
</div>
<p>This combination provides a desirable developer experience within a limited
context. Under the relevant environment manager, the dependencies which are
needed for the test environment are declared alongside the commands which need
those dependencies. They are not published in package metadata, as <code class="docutils literal notranslate"><span class="pre">extras</span></code>
would be, and they are discoverable for the tool which needs them to build the
relevant environment.</p>
<p>Dependency Groups apply to such usages by effectively “lifting” these
requirements data from a tool-specific location into a more broadly available
one. In the example above, only <code class="docutils literal notranslate"><span class="pre">tox</span></code> has access to the declared list of
dependencies. Under an implementation supporting dependency groups, the same
data might be available in a Dependency Group:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">typing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pyright&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;useful-types&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>The data can then be used under multiple tools. For example, <code class="docutils literal notranslate"><span class="pre">tox</span></code> might
implement support as <code class="docutils literal notranslate"><span class="pre">dependency_groups</span> <span class="pre">=</span> <span class="pre">typing</span></code>, replacing the <code class="docutils literal notranslate"><span class="pre">deps</span></code>
usage above.</p>
<p>In order for Dependency Groups to be a viable alternative for users of
environment managers, the environment managers will need to support processing
Dependency Groups similarly to how they support inline dependency declaration.</p>
</section>
<section id="ide-and-editor-use-of-requirements-data">
<h3><a class="toc-backref" href="#ide-and-editor-use-of-requirements-data" role="doc-backlink">IDE and Editor Use of Requirements Data</a></h3>
<p>IDE and editor integrations may benefit from conventional or configurable name
definitions for Dependency Groups which are used for integrations.</p>
<p>There are at least two known scenarios in which it is valuable for an editor or
IDE to be capable of discovering the non-published dependencies of a project:</p>
<ul class="simple">
<li>testing: IDEs such as VS Code support GUI interfaces for running particular
tests</li>
<li>linting: editors and IDEs often support linting and autoformatting
integrations which highlight or autocorrect errors</li>
</ul>
<p>These cases could be handled by defining conventional group names like
<code class="docutils literal notranslate"><span class="pre">test</span></code>, <code class="docutils literal notranslate"><span class="pre">lint</span></code>, and <code class="docutils literal notranslate"><span class="pre">fix</span></code>, or by defining configuration mechanisms which
allow the selection of Dependency Groups.</p>
<p>For example, the following <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> declares the three aforementioned
groups:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[dependency-groups]</span>
<span class="n">test</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;pytest&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;pytest-timeout&quot;</span><span class="p">]</span>
<span class="n">lint</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;flake8&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;mypy&quot;</span><span class="p">]</span>
<span class="n">fix</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;black&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;isort&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;pyupgrade&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>This PEP makes no attempt to standardize such names or reserve them for such
uses. IDEs may standardize or may allow users to configure the group names used
for various purposes.</p>
<p>This declaration allows the project authors knowledge of the appropriate tools
for the project to be shared with all editors of that project.</p>
</section>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0735.rst">https://github.com/python/peps/blob/main/peps/pep-0735.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0735.rst">2024-10-16 16:05:18 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#limitations-of-requirements-txt-files">Limitations of <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> files</a></li>
<li><a class="reference internal" href="#limitations-of-extras">Limitations of <code class="docutils literal notranslate"><span class="pre">extras</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#use-cases">Use Cases</a></li>
<li><a class="reference internal" href="#regarding-poetry-and-pdm-dependency-groups">Regarding Poetry and PDM Dependency Groups</a></li>
<li><a class="reference internal" href="#dependency-groups-are-not-hidden-extras">Dependency Groups are not Hidden Extras</a></li>
<li><a class="reference internal" href="#future-compatibility-invalid-data">Future Compatibility &amp; Invalid Data</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#dependency-object-specifiers">Dependency Object Specifiers</a><ul>
<li><a class="reference internal" href="#dependency-group-include">Dependency Group Include</a></li>
</ul>
</li>
<li><a class="reference internal" href="#example-dependency-groups-table">Example Dependency Groups Table</a></li>
<li><a class="reference internal" href="#package-building">Package Building</a></li>
<li><a class="reference internal" href="#installing-dependency-groups">Installing Dependency Groups</a><ul>
<li><a class="reference internal" href="#overlapping-install-ux-with-extras">Overlapping Install UX with Extras</a></li>
</ul>
</li>
<li><a class="reference internal" href="#validation-and-compatibility">Validation and Compatibility</a><ul>
<li><a class="reference internal" href="#linters-and-validators-may-be-stricter">Linters and Validators may be stricter</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#audit-and-update-tools">Audit and Update Tools</a></li>
</ul>
</li>
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
<li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a><ul>
<li><a class="reference internal" href="#interfaces-for-use-of-dependency-groups">Interfaces for Use of Dependency Groups</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#why-not-define-each-dependency-group-as-a-table">Why not define each Dependency Group as a table?</a></li>
<li><a class="reference internal" href="#why-not-define-a-special-string-syntax-to-extend-dependency-specifiers">Why not define a special string syntax to extend Dependency Specifiers?</a></li>
<li><a class="reference internal" href="#why-not-allow-for-more-non-pep-508-dependency-specifiers">Why not allow for more non-PEP 508 dependency specifiers?</a></li>
<li><a class="reference internal" href="#why-is-the-table-not-named-run-project-dependency-groups">Why is the table not named <code class="docutils literal notranslate"><span class="pre">[run]</span></code>, <code class="docutils literal notranslate"><span class="pre">[project.dependency-groups]</span></code>, …?</a></li>
<li><a class="reference internal" href="#why-is-pip-s-planned-implementation-of-only-deps-not-sufficient">Why is pips planned implementation of <code class="docutils literal notranslate"><span class="pre">--only-deps</span></code> not sufficient?</a></li>
<li><a class="reference internal" href="#why-isn-t-environment-manager-a-solution">Why isnt &lt;environment manager&gt; a solution?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
<li><a class="reference internal" href="#why-not-support-dependency-group-includes-in-project-dependencies-or-project-optional-dependencies">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[project.dependencies]</span></code> or <code class="docutils literal notranslate"><span class="pre">[project.optional-dependencies]</span></code>?</a><ul>
<li><a class="reference internal" href="#use-cases-for-dependency-group-includes-from-project">Use Cases for Dependency Group Includes From <code class="docutils literal notranslate"><span class="pre">[project]</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#why-not-support-dependency-group-includes-in-build-system-requires">Why not support Dependency Group Includes in <code class="docutils literal notranslate"><span class="pre">[build-system.requires]</span></code>?</a></li>
<li><a class="reference internal" href="#why-not-support-a-dependency-group-which-includes-the-current-project">Why not support a Dependency Group which includes the current project?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-prior-art-in-non-python-languages">Appendix A: Prior Art in Non-Python Languages</a><ul>
<li><a class="reference internal" href="#javascript-and-package-json">JavaScript and <code class="docutils literal notranslate"><span class="pre">package.json</span></code></a><ul>
<li><a class="reference internal" href="#dependencies-data"><code class="docutils literal notranslate"><span class="pre">&quot;dependencies&quot;</span></code> data</a></li>
<li><a class="reference internal" href="#dependencies-referencing-urls-and-local-paths">Dependencies Referencing URLs and Local Paths</a></li>
<li><a class="reference internal" href="#devdependencies-data"><code class="docutils literal notranslate"><span class="pre">&quot;devDependencies&quot;</span></code> data</a></li>
<li><a class="reference internal" href="#peerdependencies-and-optionaldependencies"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependencies&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;optionalDependencies&quot;</span></code></a><ul>
<li><a class="reference internal" href="#peerdependenciesmeta"><code class="docutils literal notranslate"><span class="pre">&quot;peerDependenciesMeta&quot;</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#omit-and-include"><code class="docutils literal notranslate"><span class="pre">--omit</span></code> and <code class="docutils literal notranslate"><span class="pre">--include</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#ruby-ruby-gems">Ruby &amp; Ruby Gems</a><ul>
<li><a class="reference internal" href="#gemfiles-bundle">Gemfiles &amp; bundle</a></li>
<li><a class="reference internal" href="#gemspec-and-packaged-dependency-data">gemspec and packaged dependency data</a><ul>
<li><a class="reference internal" href="#gemspec-development-dependency-example">gemspec development dependency example</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-b-prior-art-in-python">Appendix B: Prior Art in Python</a><ul>
<li><a class="reference internal" href="#projects-are-packages">Projects are Packages</a></li>
<li><a class="reference internal" href="#non-standard-dependency-specifiers">Non-Standard Dependency Specifiers</a></li>
<li><a class="reference internal" href="#installing-and-referring-to-dependency-groups">Installing and Referring to Dependency Groups</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-c-use-cases">Appendix C: Use Cases</a><ul>
<li><a class="reference internal" href="#web-applications">Web Applications</a></li>
<li><a class="reference internal" href="#libraries">Libraries</a></li>
<li><a class="reference internal" href="#data-science-projects">Data Science Projects</a></li>
<li><a class="reference internal" href="#lockfile-generation">Lockfile Generation</a></li>
<li><a class="reference internal" href="#environment-manager-inputs">Environment Manager Inputs</a></li>
<li><a class="reference internal" href="#ide-and-editor-use-of-requirements-data">IDE and Editor Use of Requirements Data</a></li>
</ul>
</li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0735.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>