807 lines
57 KiB
HTML
807 lines
57 KiB
HTML
|
||
<!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 650 – Specifying Installer Requirements for Python Projects | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0650/">
|
||
<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 650 – Specifying Installer Requirements for Python Projects | peps.python.org'>
|
||
<meta property="og:description" content="Python package installers are not completely interoperable with each other. While pip is the most widely used installer and a de facto standard, other installers such as Poetry or Pipenv are popular as well due to offering unique features which are opti...">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0650/">
|
||
<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="Python package installers are not completely interoperable with each other. While pip is the most widely used installer and a de facto standard, other installers such as Poetry or Pipenv are popular as well due to offering unique features which are opti...">
|
||
<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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 650</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 650 – Specifying Installer Requirements for Python Projects</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Vikram Jayanthi <vikramjayanthi at google.com>,
|
||
Dustin Ingram <di at python.org>,
|
||
Brett Cannon <brett at python.org></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/pep-650-specifying-installer-requirements-for-python-projects/6657">Discourse thread</a></dd>
|
||
<dt class="field-odd">Status<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Removed from consideration by sponsor or authors">Withdrawn</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">16-Jul-2020</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd">14-Jan-2021</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="#terminology">Terminology</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#providers">Providers</a><ul>
|
||
<li><a class="reference internal" href="#platform-infrastructure-providers">Platform/Infrastructure Providers</a></li>
|
||
<li><a class="reference internal" href="#ide-providers">IDE Providers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#developers">Developers</a><ul>
|
||
<li><a class="reference internal" href="#developers-using-paas-iaas-providers">Developers using PaaS & IaaS providers</a></li>
|
||
<li><a class="reference internal" href="#developers-using-ides">Developers using IDEs</a></li>
|
||
<li><a class="reference internal" href="#developers-working-with-other-developers">Developers working with other developers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#upgraders-package-infrastructure-providers">Upgraders & Package Infrastructure Providers</a></li>
|
||
<li><a class="reference internal" href="#open-source-community">Open Source Community</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#install-system">[install-system]</a><ul>
|
||
<li><a class="reference internal" href="#installer-requirements">Installer Requirements:</a></li>
|
||
<li><a class="reference internal" href="#additional-parameters-or-tool-specific-data">Additional parameters or tool specific data</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#installer-interface">Installer interface:</a></li>
|
||
<li><a class="reference internal" href="#mandatory-hooks">Mandatory hooks:</a><ul>
|
||
<li><a class="reference internal" href="#invoke-install">invoke_install</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#optional-hooks">Optional hooks:</a><ul>
|
||
<li><a class="reference internal" href="#invoke-uninstall">invoke_uninstall</a></li>
|
||
<li><a class="reference internal" href="#get-dependencies-to-install">get_dependencies_to_install</a></li>
|
||
<li><a class="reference internal" href="#get-dependency-groups">get_dependency_groups</a></li>
|
||
<li><a class="reference internal" href="#update-dependencies">update_dependencies</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#example">Example</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#a-standardized-lock-file">A standardized lock file</a></li>
|
||
<li><a class="reference internal" href="#have-installer-backends-support-creating-virtual-environments">Have installer backends support creating virtual environments</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
|
||
<li><a class="reference internal" href="#should-the-dependency-group-argument-take-an-iterable">Should the <code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> argument take an iterable?</a></li>
|
||
<li><a class="reference internal" href="#is-the-installer-backend-executed-in-process">Is the installer backend executed in-process?</a></li>
|
||
<li><a class="reference internal" href="#enforce-that-results-from-the-proposed-interface-feed-into-other-parts">Enforce that results from the proposed interface feed into other parts?</a></li>
|
||
<li><a class="reference internal" href="#raising-exceptions-instead-of-exit-codes-for-failure-conditions">Raising exceptions instead of exit codes for failure conditions</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>Python package installers are not completely interoperable with each
|
||
other. While pip is the most widely used installer and a de facto
|
||
standard, other installers such as <a class="reference external" href="https://python-poetry.org/">Poetry</a> or <a class="reference external" href="https://pipenv-fork.readthedocs.io/en/latest/">Pipenv</a> are popular as
|
||
well due to offering unique features which are optimal for certain
|
||
workflows and not directly in line with how pip operates.</p>
|
||
<p>While the abundance of installer options is good for end-users with
|
||
specific needs, the lack of interoperability between them makes it
|
||
hard to support all potential installers. Specifically, the lack of a
|
||
standard requirements file for declaring dependencies means that each
|
||
tool must be explicitly used in order to install dependencies
|
||
specified with their respective format. Otherwise tools must emit a
|
||
requirements file which leads to potential information loss for the
|
||
installer as well as an added export step as part of a developer’s
|
||
workflow.</p>
|
||
<p>By providing a standardized API that can be used to invoke a
|
||
compatible installer, we can solve this problem without needing to
|
||
resolve individual concerns, unique requirements, and
|
||
incompatibilities between different installers and their lock files.</p>
|
||
<p>Installers that implement the specification can be invoked in a
|
||
uniform way, allowing users to use their installer of choice as if
|
||
they were invoking it directly.</p>
|
||
</section>
|
||
<section id="terminology">
|
||
<h2><a class="toc-backref" href="#terminology" role="doc-backlink">Terminology</a></h2>
|
||
<dl class="simple">
|
||
<dt>Installer interface</dt><dd>The interface by which an <em>installer backend</em> and a
|
||
<em>universal installer</em> interact.</dd>
|
||
<dt>Universal installer</dt><dd>An installer that can invoke an <em>installer backend</em> by calling the
|
||
optional invocation methods of the <em>installer interface</em>. This can
|
||
also be thought of as the installer frontend, à la the <a class="reference external" href="https://github.com/pypa/build">build</a>
|
||
project for <a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a>.</dd>
|
||
<dt>Installer backend</dt><dd>An installer that implements the <em>installer interface</em>, allowing
|
||
it to be invoked by a <em>universal installer</em>. An
|
||
<em>installer backend</em> may also be a <em>universal installer</em> as well,
|
||
but it is not required. In comparison to <a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a>, this would
|
||
be <a class="reference external" href="https://flit.readthedocs.io">Flit</a>. <em>Installer backends</em> may be wrapper packages around
|
||
a backing installer, e.g. Poetry could choose to not support this
|
||
API, but a package could act as a wrapper to invoke Poetry as
|
||
appropriate to use Poetry to perform an installation.</dd>
|
||
<dt>Dependency group</dt><dd>A set of dependencies that are related and required to be
|
||
installed simultaneously for some purpose. For example, a
|
||
“test” dependency group could include the dependencies required to
|
||
run the test suite. How dependency groups are specified is up to
|
||
the <em>installer backend</em>.</dd>
|
||
</dl>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>This specification allows anyone to invoke and interact with
|
||
<em>installer backends</em> that implement the specified interface, allowing
|
||
for a universally supported layer on top of existing tool-specific
|
||
installation processes.</p>
|
||
<p>This in turn would enable the use of all installers that implement the
|
||
specified interface to be used in environments that support a single
|
||
<em>universal installer</em>, as long as that installer implements this
|
||
specification as well.</p>
|
||
<p>Below, we identify various use-cases applicable to stakeholders in the
|
||
Python community and anyone who interacts with Python package
|
||
installers. For developers or companies, this PEP would allow for
|
||
increased functionality and flexibility with Python package
|
||
installers.</p>
|
||
<section id="providers">
|
||
<h3><a class="toc-backref" href="#providers" role="doc-backlink">Providers</a></h3>
|
||
<p>Providers are the parties (organization, person, community, etc.) that
|
||
supply a service or software tool which interacts with Python
|
||
packaging and consequently Python package installers. Two different
|
||
types of providers are considered:</p>
|
||
<section id="platform-infrastructure-providers">
|
||
<h4><a class="toc-backref" href="#platform-infrastructure-providers" role="doc-backlink">Platform/Infrastructure Providers</a></h4>
|
||
<p>Platform providers (cloud environments, application hosting, etc.) and
|
||
infrastructure service providers need to support package installers
|
||
for their users to install Python dependencies. Most only support pip,
|
||
however there is user demand for other Python installers. Most
|
||
providers do not want to maintain support for more than one installer
|
||
because of the complexity it adds to their software or service and the
|
||
resources it takes to do so.</p>
|
||
<p>Via this specification, we can enable a provider-supported
|
||
<em>universal installer</em> to invoke the user-desired <em>installer backend</em>
|
||
without the provider’s platform needing to have specific knowledge of
|
||
said backend. What this means is if Poetry implemented the installer
|
||
backend API proposed by this PEP (or some other package wrapped Poetry
|
||
to provide the API), then platform providers would support Poetry
|
||
implicitly.</p>
|
||
</section>
|
||
<section id="ide-providers">
|
||
<h4><a class="toc-backref" href="#ide-providers" role="doc-backlink">IDE Providers</a></h4>
|
||
<p>Integrated development environments may interact with Python package
|
||
installation and management. Most only support pip as a Python package
|
||
installer, and users are required to find work arounds to install
|
||
their dependencies using other package installers. Similar to the
|
||
situation with PaaS & IaaS providers, IDE providers do not want to
|
||
maintain support for N different Python installers. Instead,
|
||
implementers of the installer interface (<em>installer backends</em>) could
|
||
be invoked by the IDE by it acting as a <em>universal installer</em>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="developers">
|
||
<h3><a class="toc-backref" href="#developers" role="doc-backlink">Developers</a></h3>
|
||
<p>Developers are teams, people, or communities that code and use Python
|
||
package installers and Python packages. Three different types of
|
||
developers are considered:</p>
|
||
<section id="developers-using-paas-iaas-providers">
|
||
<h4><a class="toc-backref" href="#developers-using-paas-iaas-providers" role="doc-backlink">Developers using PaaS & IaaS providers</a></h4>
|
||
<p>Most PaaS and IaaS providers only support one Python package
|
||
installer: <a class="reference external" href="https://pip.pypa.io">pip</a>. (Some exceptions include Heroku’s Python <a class="reference external" href="https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-python">buildpack</a>,
|
||
which supports pip and <a class="reference external" href="https://pipenv-fork.readthedocs.io/en/latest/">Pipenv</a>). This dictates the installers that
|
||
developers can use while working with these providers, which might not
|
||
be optimal for their application or workflow.</p>
|
||
<p>Installers adopting this PEP to become <em>installer backends</em> would allow
|
||
users to use third party platforms/infrastructure without having to
|
||
worry about which Python package installer they are required to use as
|
||
long as the provider uses a <em>universal installer</em>.</p>
|
||
</section>
|
||
<section id="developers-using-ides">
|
||
<h4><a class="toc-backref" href="#developers-using-ides" role="doc-backlink">Developers using IDEs</a></h4>
|
||
<p>Most IDEs only support pip or a few Python package installers.
|
||
Consequently, developers must use workarounds or hacky methods to
|
||
install their dependencies if they use an unsupported package
|
||
installer.</p>
|
||
<p>If the IDE uses/provides a <em>universal installer</em> it would allow for
|
||
any <em>installer backend</em> that the developer wanted to be used to
|
||
install dependencies, freeing them of any extra work to install their
|
||
dependencies in order to integrate into the IDE’s workflow more
|
||
closely.</p>
|
||
</section>
|
||
<section id="developers-working-with-other-developers">
|
||
<h4><a class="toc-backref" href="#developers-working-with-other-developers" role="doc-backlink">Developers working with other developers</a></h4>
|
||
<p>Developers want to be able to use the installer of their choice while
|
||
working with other developers, but currently have to synchronize their
|
||
installer choice for compatibility of dependency installation. If all
|
||
preferred installers instead implemented the specified interface, it
|
||
would allow for cross use of installers, allowing developers to choose
|
||
an installer regardless of their collaborator’s preference.</p>
|
||
</section>
|
||
</section>
|
||
<section id="upgraders-package-infrastructure-providers">
|
||
<h3><a class="toc-backref" href="#upgraders-package-infrastructure-providers" role="doc-backlink">Upgraders & Package Infrastructure Providers</a></h3>
|
||
<p>Package upgraders and package infrastructure in CI/CD such as
|
||
<a class="reference external" href="https://dependabot.com/">Dependabot</a>, <a class="reference external" href="https://pyup.io/">PyUP</a>, etc. currently support a few installers. They work
|
||
by parsing and editing the installer-specific dependency files
|
||
directly (such as <code class="docutils literal notranslate"><span class="pre">requirements.txt</span></code> or <code class="docutils literal notranslate"><span class="pre">poetry.lock</span></code>) with
|
||
relevant package information such as upgrades, downgrades, or new
|
||
hashes. Similar to Platform and IDE providers, most of these providers
|
||
do not want to support N different Python package installers as that
|
||
would require supporting N different file types.</p>
|
||
<p>Currently, these services/bots have to implement support for each
|
||
package installer individually. Inevitably, the most popular
|
||
installers are supported first, and less popular tools are often never
|
||
supported. By implementing this specification, these services/bots can
|
||
support any (compliant) installer, allowing users to select the tool
|
||
of their choice. This will allow for more innovation in the space, as
|
||
platforms and IDEs are no longer forced to prematurely select a
|
||
“winner”.</p>
|
||
</section>
|
||
<section id="open-source-community">
|
||
<h3><a class="toc-backref" href="#open-source-community" role="doc-backlink">Open Source Community</a></h3>
|
||
<p>Specifying installer requirements and adopting this PEP will reduce
|
||
the friction between Python package installers and people’s workflows.
|
||
Consequently, it will reduce the friction between Python package
|
||
installers and 3rd party infrastructure/technologies such as PaaS or
|
||
IDEs. Overall, it will allow for easier development, deployment and
|
||
maintenance of Python projects as Python package installation becomes
|
||
simpler and more interoperable.</p>
|
||
<p>Specifying requirements and creating an interface for installers can
|
||
also increase the pace of innovation around installers. This would
|
||
allow for installers to experiment and add unique functionality
|
||
without requiring the rest of the ecosystem to do the same. Support
|
||
becomes easier and more likely for a new installer regardless of the
|
||
functionality it adds and the format in which it writes dependencies,
|
||
while reducing the developer time and resources needed to do so.</p>
|
||
</section>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>Similar to how <a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a> specifies build systems, the install system
|
||
information will live in the <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> file under the
|
||
<code class="docutils literal notranslate"><span class="pre">install-system</span></code> table.</p>
|
||
<section id="install-system">
|
||
<h3><a class="toc-backref" href="#install-system" role="doc-backlink">[install-system]</a></h3>
|
||
<p>The install-system table is used to store install-system relevant data
|
||
and information. There are multiple required keys for this table:
|
||
<code class="docutils literal notranslate"><span class="pre">requires</span></code> and <code class="docutils literal notranslate"><span class="pre">install-backend</span></code>. The <code class="docutils literal notranslate"><span class="pre">requires</span></code> key holds the
|
||
minimum requirements for the <em>installer backend</em> to execute and which
|
||
will be installed by the <em>universal installer</em>. The <code class="docutils literal notranslate"><span class="pre">install-backend</span></code>
|
||
key holds the name of the install backend’s entry point. This will
|
||
allow the <em>universal installer</em> to install the requirements for the
|
||
<em>installer backend</em> itself to execute (not the requirements that the
|
||
<em>installer backend</em> itself will install) as well as invoke the
|
||
<em>installer backend</em>.</p>
|
||
<p>If either of the required keys are missing or empty then the
|
||
<em>universal installer</em> SHOULD raise an error.</p>
|
||
<p>All package names interacting with this interface are assumed to
|
||
follow <a class="pep reference internal" href="../pep-0508/" title="PEP 508 – Dependency specification for Python Software Packages">PEP 508</a>’s “Dependency specification for Python Software
|
||
Packages” format.</p>
|
||
<p>An example <code class="docutils literal notranslate"><span class="pre">install-system</span></code> table:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">#pyproject.toml</span>
|
||
<span class="p">[</span><span class="n">install</span><span class="o">-</span><span class="n">system</span><span class="p">]</span>
|
||
<span class="c1">#Eg : pipenv</span>
|
||
<span class="n">requires</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"pipenv"</span><span class="p">]</span>
|
||
<span class="n">install</span><span class="o">-</span><span class="n">backend</span> <span class="o">=</span> <span class="s2">"pipenv.api:main"</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="installer-requirements">
|
||
<h4><a class="toc-backref" href="#installer-requirements" role="doc-backlink">Installer Requirements:</a></h4>
|
||
<p>The requirements specified by the <code class="docutils literal notranslate"><span class="pre">requires</span></code> key must be within the
|
||
constraints specified by <a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a>. Specifically, that dependency
|
||
cycles are not permitted and the <em>universal installer</em> SHOULD refuse
|
||
to install the dependencies if a cycle is detected.</p>
|
||
</section>
|
||
<section id="additional-parameters-or-tool-specific-data">
|
||
<h4><a class="toc-backref" href="#additional-parameters-or-tool-specific-data" role="doc-backlink">Additional parameters or tool specific data</a></h4>
|
||
<p>Additional parameters or tool (<em>installer backend</em>) data may also be
|
||
stored in the <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> file. This would be in the “tool.*”
|
||
table as specified by <a class="pep reference internal" href="../pep-0518/" title="PEP 518 – Specifying Minimum Build System Requirements for Python Projects">PEP 518</a>. For example, if the
|
||
<em>installer backend</em> is Poetry and you wanted to specify multiple
|
||
dependency groups, the tool.poetry tables could look like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">poetry</span><span class="o">.</span><span class="n">dev</span><span class="o">-</span><span class="n">dependencies</span><span class="p">]</span>
|
||
<span class="n">dependencies</span> <span class="o">=</span> <span class="s2">"dev"</span>
|
||
|
||
<span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">poetry</span><span class="o">.</span><span class="n">deploy</span><span class="p">]</span>
|
||
<span class="n">dependencies</span> <span class="o">=</span> <span class="s2">"deploy"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Data may also be stored in other ways as the installer backend sees
|
||
fit (e.g. separate configuration file).</p>
|
||
</section>
|
||
</section>
|
||
<section id="installer-interface">
|
||
<h3><a class="toc-backref" href="#installer-interface" role="doc-backlink">Installer interface:</a></h3>
|
||
<p>The <em>installer interface</em> contains mandatory and optional hooks.
|
||
Compliant <em>installer backends</em> MUST implement the mandatory hooks and
|
||
MAY implement the optional hooks. A <em>universal installer</em> MAY
|
||
implement any of the <em>installer backend</em> hooks itself, to act as both
|
||
a <em>universal installer</em> and <em>installer backend</em>, but this is not
|
||
required.</p>
|
||
<p>All hooks take <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> arbitrary parameters that a
|
||
<em>installer backend</em> may require that are not already specified,
|
||
allowing for backwards compatibility. If unexpected parameters are
|
||
passed to the <em>installer backend</em>, it should ignore them.</p>
|
||
<p>The following information is akin to the corresponding section in
|
||
<a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a>. The hooks may be called with keyword arguments, so
|
||
<em>installer backends</em> implementing them should be careful to make sure
|
||
that their signatures match both the order and the names of the
|
||
arguments above.</p>
|
||
<p>All hooks MAY print arbitrary informational text to <code class="docutils literal notranslate"><span class="pre">stdout</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">stderr</span></code>. They MUST NOT read from <code class="docutils literal notranslate"><span class="pre">stdin</span></code>, and the
|
||
<em>universal installer</em> MAY close <code class="docutils literal notranslate"><span class="pre">stdin</span></code> before invoking the hooks.</p>
|
||
<p>The <em>universal installer</em> may capture <code class="docutils literal notranslate"><span class="pre">stdout</span></code> and/or <code class="docutils literal notranslate"><span class="pre">stderr</span></code>
|
||
from the backend. If the backend detects that an output stream is not
|
||
a terminal/console (e.g. not <code class="docutils literal notranslate"><span class="pre">sys.stdout.isatty()</span></code>), it SHOULD
|
||
ensure that any output it writes to that stream is <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code> encoded.
|
||
The <em>universal installer</em> MUST NOT fail if captured output is not
|
||
valid UTF-8, but it MAY not preserve all the information in that case
|
||
(e.g. it may decode using the replace error handler in Python). If the
|
||
output stream is a terminal, the <em>installer backend</em> is responsible
|
||
for presenting its output accurately, as for any program running in a
|
||
terminal.</p>
|
||
<p>If a hook raises an exception, or causes the process to terminate,
|
||
then this indicates an error.</p>
|
||
</section>
|
||
<section id="mandatory-hooks">
|
||
<h3><a class="toc-backref" href="#mandatory-hooks" role="doc-backlink">Mandatory hooks:</a></h3>
|
||
<section id="invoke-install">
|
||
<h4><a class="toc-backref" href="#invoke-install" role="doc-backlink">invoke_install</a></h4>
|
||
<p>Installs the dependencies:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">invoke_install</span><span class="p">(</span>
|
||
<span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">PathLike</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
|
||
<span class="o">*</span><span class="p">,</span>
|
||
<span class="n">dependency_group</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||
<span class="o">**</span><span class="n">kwargs</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">path</span></code> : An absolute path where the <em>installer backend</em> should be
|
||
invoked from (e.g. the directory where <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is
|
||
located).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> : An optional flag specifying a dependency
|
||
group that the <em>installer backend</em> should install. The install will
|
||
error if the dependency group doesn’t exist. A user can find all
|
||
dependency groups by calling
|
||
<code class="docutils literal notranslate"><span class="pre">get_dependency_groups()</span></code> if dependency groups are
|
||
supported by the <em>installer backend</em>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> : Arbitrary parameters that a <em>installer backend</em> may
|
||
require that are not already specified, allows for backwards
|
||
compatibility.</li>
|
||
<li>Returns : An exit code (int). 0 if successful, any positive integer
|
||
if unsuccessful.</li>
|
||
</ul>
|
||
<p>The <em>universal installer</em> will use the exit code to determine if the
|
||
installation is successful and SHOULD return the exit code itself.</p>
|
||
</section>
|
||
</section>
|
||
<section id="optional-hooks">
|
||
<h3><a class="toc-backref" href="#optional-hooks" role="doc-backlink">Optional hooks:</a></h3>
|
||
<section id="invoke-uninstall">
|
||
<h4><a class="toc-backref" href="#invoke-uninstall" role="doc-backlink">invoke_uninstall</a></h4>
|
||
<p>Uninstall the specified dependencies:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">invoke_uninstall</span><span class="p">(</span>
|
||
<span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">PathLike</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
|
||
<span class="o">*</span><span class="p">,</span>
|
||
<span class="n">dependency_group</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||
<span class="o">**</span><span class="n">kwargs</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">path</span></code> : An absolute path where the <em>installer backend</em> should be
|
||
invoked from (e.g. the directory where <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is
|
||
located).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> : An optional flag specifying a dependency
|
||
group that the <em>installer backend</em> should uninstall.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> : Arbitrary parameters that a <em>installer backend</em> may
|
||
require that are not already specified, allows for backwards
|
||
compatibility.</li>
|
||
<li>Returns : An exit code (int). 0 if successful, any positive integer
|
||
if unsuccessful.</li>
|
||
</ul>
|
||
<p>The <em>universal installer</em> MUST invoke the <em>installer backend</em> at the
|
||
same path that the <em>universal installer</em> itself was invoked.</p>
|
||
<p>The <em>universal installer</em> will use the exit code to determine if the
|
||
uninstall is successful and SHOULD return the exit code itself.</p>
|
||
</section>
|
||
<section id="get-dependencies-to-install">
|
||
<h4><a class="toc-backref" href="#get-dependencies-to-install" role="doc-backlink">get_dependencies_to_install</a></h4>
|
||
<p>Returns the dependencies that would be installed by
|
||
<code class="docutils literal notranslate"><span class="pre">invoke_install(...)</span></code>. This allows package upgraders
|
||
(e.g., Dependabot) to retrieve the dependencies attempting to be
|
||
installed without parsing the dependency file:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_dependencies_to_install</span><span class="p">(</span>
|
||
<span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">PathLike</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
|
||
<span class="o">*</span><span class="p">,</span>
|
||
<span class="n">dependency_group</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||
<span class="o">**</span><span class="n">kwargs</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">path</span></code> : An absolute path where the <em>installer backend</em> should be
|
||
invoked from (e.g. the directory where <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is
|
||
located).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> : Specify a dependency group to get the
|
||
dependencies <code class="docutils literal notranslate"><span class="pre">invoke_install(...)</span></code> would install for that
|
||
dependency group.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> : Arbitrary parameters that a <em>installer backend</em> may
|
||
require that are not already specified, allows for backwards
|
||
compatibility.</li>
|
||
<li>Returns: A list of dependencies (<a class="pep reference internal" href="../pep-0508/" title="PEP 508 – Dependency specification for Python Software Packages">PEP 508</a> strings) to install.</li>
|
||
</ul>
|
||
<p>If the group is specified, the <em>installer backend</em> MUST return the
|
||
dependencies corresponding to the provided dependency group. If the
|
||
specified group doesn’t exist, or dependency groups are not supported
|
||
by the <em>installer backend</em>, the <em>installer backend</em> MUST raise an
|
||
error.</p>
|
||
<p>If the group is not specified, and the <em>installer backend</em> provides
|
||
the concept of a default/unspecified group, the <em>installer backend</em>
|
||
MAY return the dependencies for the default/unspecified group, but
|
||
otherwise MUST raise an error.</p>
|
||
</section>
|
||
<section id="get-dependency-groups">
|
||
<h4><a class="toc-backref" href="#get-dependency-groups" role="doc-backlink">get_dependency_groups</a></h4>
|
||
<p>Returns the dependency groups available to be installed. This allows
|
||
<em>universal installers</em> to enumerate all dependency groups the
|
||
<em>installer backend</em> is aware of:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_dependency_groups</span><span class="p">(</span>
|
||
<span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">PathLike</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
|
||
<span class="o">**</span><span class="n">kwargs</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="n">AbstractSet</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">path</span></code> : An absolute path where the <em>installer backend</em> should be
|
||
invoked from (e.g. the directory where <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is
|
||
located).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> : Arbitrary parameters that a <em>installer backend</em> may
|
||
require that are not already specified, allows for backwards
|
||
compatibility.</li>
|
||
<li>Returns: A set of known dependency groups, as strings The empty set
|
||
represents no dependency groups.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="update-dependencies">
|
||
<h4><a class="toc-backref" href="#update-dependencies" role="doc-backlink">update_dependencies</a></h4>
|
||
<p>Outputs a dependency file based on inputted package list:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">update_dependencies</span><span class="p">(</span>
|
||
<span class="n">path</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">PathLike</span><span class="p">[</span><span class="nb">str</span><span class="p">]],</span>
|
||
<span class="n">dependency_specifiers</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span>
|
||
<span class="o">*</span><span class="p">,</span>
|
||
<span class="n">dependency_group</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||
<span class="o">**</span><span class="n">kwargs</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">path</span></code> : An absolute path where the <em>installer backend</em> should be
|
||
invoked from (e.g. the directory where <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is
|
||
located).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dependency_specifiers</span></code> : An iterable of dependencies as
|
||
<a class="pep reference internal" href="../pep-0508/" title="PEP 508 – Dependency specification for Python Software Packages">PEP 508</a> strings that are being updated, for example :
|
||
<code class="docutils literal notranslate"><span class="pre">["requests==2.8.1",</span> <span class="pre">...]</span></code>. Optionally for a specific dependency
|
||
group.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> : The dependency group that the list of
|
||
packages is for.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> : Arbitrary parameters that a <em>installer backend</em> may
|
||
require that are not already specified, allows for backwards
|
||
compatibility.</li>
|
||
<li>Returns : An exit code (int). 0 if successful, any positive integer
|
||
if unsuccessful.</li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="example">
|
||
<h2><a class="toc-backref" href="#example" role="doc-backlink">Example</a></h2>
|
||
<p>Let’s consider implementing an <em>installer backend</em> that uses pip and
|
||
its requirements files for <em>dependency groups</em>. An implementation may
|
||
(very roughly) look like the following:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">subprocess</span>
|
||
<span class="kn">import</span> <span class="nn">sys</span>
|
||
|
||
|
||
<span class="k">def</span> <span class="nf">invoke_install</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">dependency_group</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
|
||
<span class="p">[</span>
|
||
<span class="n">sys</span><span class="o">.</span><span class="n">executable</span><span class="p">,</span>
|
||
<span class="s2">"-m"</span><span class="p">,</span>
|
||
<span class="s2">"pip"</span><span class="p">,</span>
|
||
<span class="s2">"install"</span><span class="p">,</span>
|
||
<span class="s2">"-r"</span><span class="p">,</span>
|
||
<span class="n">dependency_group</span> <span class="ow">or</span> <span class="s2">"requirements.txt"</span><span class="p">,</span>
|
||
<span class="p">],</span>
|
||
<span class="n">cwd</span><span class="o">=</span><span class="n">path</span><span class="p">,</span>
|
||
<span class="p">)</span><span class="o">.</span><span class="n">returncode</span>
|
||
<span class="k">except</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">CalledProcessError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">e</span><span class="o">.</span><span class="n">returncode</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If we named this package <code class="docutils literal notranslate"><span class="pre">pep650pip</span></code>, then we could specify in
|
||
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">install</span><span class="o">-</span><span class="n">system</span><span class="p">]</span>
|
||
<span class="c1">#Eg : pipenv</span>
|
||
<span class="n">requires</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"pep650pip"</span><span class="p">,</span> <span class="s2">"pip"</span><span class="p">]</span>
|
||
<span class="n">install</span><span class="o">-</span><span class="n">backend</span> <span class="o">=</span> <span class="s2">"pep650pip:main"</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>All hooks take <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> to allow for backwards compatibility and
|
||
allow for tool specific <em>installer backend</em> functionality which
|
||
requires a user to provide additional information not required by the
|
||
hook.</p>
|
||
<p>While <em>installer backends</em> must be Python packages, what they do when
|
||
invoked is an implementation detail of that tool. For example, an
|
||
<em>installer backend</em> could act as a wrapper for a platform package
|
||
manager (e.g., <code class="docutils literal notranslate"><span class="pre">apt</span></code>).</p>
|
||
<p>The interface does not in any way try to specify <em>how</em>
|
||
<em>installer backends</em> should function. This is on purpose so that
|
||
<em>installer backends</em> can be allowed to innovate and solve problem in
|
||
their own way. This also means this PEP takes no stance on OS
|
||
packaging as that would be an <em>installer backend</em>’s domain.</p>
|
||
<p>Defining the API in Python does mean that <em>some</em> Python code will
|
||
eventually need to be executed. That does not preclude non-Python
|
||
<em>installer backends</em> from being used, though (e.g. <a class="reference external" href="https://github.com/mamba-org/mamba">mamba</a>), as they
|
||
could be executed as a subprocess from Python code.</p>
|
||
</section>
|
||
<section id="backwards-compatibility">
|
||
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
|
||
<p>This PEP would have no impact on pre-existing code and functionality
|
||
as it only adds new functionality to a <em>universal installer</em>. Any
|
||
existing installer should maintain its existing functionality and use
|
||
cases, therefore having no backwards compatibility issues. Only code
|
||
aiming to take advantage of this new functionality will have
|
||
motivation to make changes to their pre existing code.</p>
|
||
</section>
|
||
<section id="security-implications">
|
||
<h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2>
|
||
<p>A malicious user has no increased ability or easier access to anything
|
||
with the addition of standardized installer specifications. The
|
||
installer that could be invoked by a <em>universal installer</em> via the
|
||
interface specified in this PEP would be explicitly declared by the
|
||
user. If the user has chosen a malicious installer, then invoking it
|
||
with a <em>universal installer</em> is no different than the user invoking
|
||
the installer directly. A malicious installer being an
|
||
<em>installer backend</em> doesn’t give it additional permissions or
|
||
abilities.</p>
|
||
</section>
|
||
<section id="rejected-ideas">
|
||
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
|
||
<section id="a-standardized-lock-file">
|
||
<h3><a class="toc-backref" href="#a-standardized-lock-file" role="doc-backlink">A standardized lock file</a></h3>
|
||
<p>A standardized lock file would solve a lot of the same problems that
|
||
specifying installer requirements would. For example, it would allow
|
||
for PaaS/IaaS to just support one installer that could read the
|
||
standardized lock file regardless of the installer that created it.
|
||
The problem with a standardized lock file is the difference in needs
|
||
between Python package installers as well as a fundamental issue with
|
||
creating reproducible environments via the lockfile (one of the main
|
||
benefits).</p>
|
||
<p>Needs and information stored in dependency files between installers
|
||
differ significantly and are dependent on installer functionality. For
|
||
example, a Python package installer such as Poetry requires
|
||
information for all Python versions and platforms and calculates
|
||
appropriate hashes while pip doesn’t. Additionally, pip would not be
|
||
able to guarantee recreating the same environment (install the exact
|
||
same dependencies) as it is outside the scope of its functionality.
|
||
This makes a standardized lock file harder to implement and makes it
|
||
seem more appropriate to make lock files tool specific.</p>
|
||
</section>
|
||
<section id="have-installer-backends-support-creating-virtual-environments">
|
||
<h3><a class="toc-backref" href="#have-installer-backends-support-creating-virtual-environments" role="doc-backlink">Have installer backends support creating virtual environments</a></h3>
|
||
<p>Because <em>installer backends</em> will very likely have a concept of virtual
|
||
environments and how to install into them, it was briefly considered
|
||
to have them also support creating virtual environments. In the end,
|
||
though, it was considered an orthogonal idea.</p>
|
||
</section>
|
||
</section>
|
||
<section id="open-issues">
|
||
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
|
||
<section id="should-the-dependency-group-argument-take-an-iterable">
|
||
<h3><a class="toc-backref" href="#should-the-dependency-group-argument-take-an-iterable" role="doc-backlink">Should the <code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> argument take an iterable?</a></h3>
|
||
<p>This would allow for specifying non-overlapping dependency groups in
|
||
a single call, e.g. “docs” and “test” groups which have independent
|
||
dependencies but which a developer may want to install simultaneously
|
||
while doing development.</p>
|
||
</section>
|
||
<section id="is-the-installer-backend-executed-in-process">
|
||
<h3><a class="toc-backref" href="#is-the-installer-backend-executed-in-process" role="doc-backlink">Is the installer backend executed in-process?</a></h3>
|
||
<p>If the <em>installer backend</em> is executed in-process then it greatly
|
||
simplifies knowing what environment to install for/into, as the live
|
||
Python environment can be queried for appropriate information.</p>
|
||
<p>Executing out-of-process allows for minimizing potential issues of
|
||
clashes between the environment being installed into and the
|
||
<em>installer backend</em> (and potentially <em>universal installer</em>).</p>
|
||
</section>
|
||
<section id="enforce-that-results-from-the-proposed-interface-feed-into-other-parts">
|
||
<h3><a class="toc-backref" href="#enforce-that-results-from-the-proposed-interface-feed-into-other-parts" role="doc-backlink">Enforce that results from the proposed interface feed into other parts?</a></h3>
|
||
<p>E.g. the results from <code class="docutils literal notranslate"><span class="pre">get_dependencies_to_install()</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">get_dependency_groups()</span></code> can be passed into <code class="docutils literal notranslate"><span class="pre">invoke_install()</span></code>.
|
||
This would prevent drift between the results of various parts of the
|
||
proposed interface, but it makes more of the interface required
|
||
instead of optional.</p>
|
||
</section>
|
||
<section id="raising-exceptions-instead-of-exit-codes-for-failure-conditions">
|
||
<h3><a class="toc-backref" href="#raising-exceptions-instead-of-exit-codes-for-failure-conditions" role="doc-backlink">Raising exceptions instead of exit codes for failure conditions</a></h3>
|
||
<p>It has been suggested that instead of returning an exit code the API
|
||
should raise exceptions. If you view this PEP as helping to translate
|
||
current installers into <em>installer backends</em>, then relying on exit
|
||
codes makes sense. There’s is also the point that the APIs have no
|
||
specific return value, so passing along an exit code does not
|
||
interfere with what the functions return.</p>
|
||
<p>Compare that to raising exceptions in case of an error. That could
|
||
potentially provide a more structured approach to error raising,
|
||
although to be able to capture errors it would require specifying
|
||
exception types as part of the interface.</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-0650.rst">https://github.com/python/peps/blob/main/peps/pep-0650.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0650.rst">2023-09-09 17:39:29 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="#terminology">Terminology</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#providers">Providers</a><ul>
|
||
<li><a class="reference internal" href="#platform-infrastructure-providers">Platform/Infrastructure Providers</a></li>
|
||
<li><a class="reference internal" href="#ide-providers">IDE Providers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#developers">Developers</a><ul>
|
||
<li><a class="reference internal" href="#developers-using-paas-iaas-providers">Developers using PaaS & IaaS providers</a></li>
|
||
<li><a class="reference internal" href="#developers-using-ides">Developers using IDEs</a></li>
|
||
<li><a class="reference internal" href="#developers-working-with-other-developers">Developers working with other developers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#upgraders-package-infrastructure-providers">Upgraders & Package Infrastructure Providers</a></li>
|
||
<li><a class="reference internal" href="#open-source-community">Open Source Community</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#install-system">[install-system]</a><ul>
|
||
<li><a class="reference internal" href="#installer-requirements">Installer Requirements:</a></li>
|
||
<li><a class="reference internal" href="#additional-parameters-or-tool-specific-data">Additional parameters or tool specific data</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#installer-interface">Installer interface:</a></li>
|
||
<li><a class="reference internal" href="#mandatory-hooks">Mandatory hooks:</a><ul>
|
||
<li><a class="reference internal" href="#invoke-install">invoke_install</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#optional-hooks">Optional hooks:</a><ul>
|
||
<li><a class="reference internal" href="#invoke-uninstall">invoke_uninstall</a></li>
|
||
<li><a class="reference internal" href="#get-dependencies-to-install">get_dependencies_to_install</a></li>
|
||
<li><a class="reference internal" href="#get-dependency-groups">get_dependency_groups</a></li>
|
||
<li><a class="reference internal" href="#update-dependencies">update_dependencies</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#example">Example</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#a-standardized-lock-file">A standardized lock file</a></li>
|
||
<li><a class="reference internal" href="#have-installer-backends-support-creating-virtual-environments">Have installer backends support creating virtual environments</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
|
||
<li><a class="reference internal" href="#should-the-dependency-group-argument-take-an-iterable">Should the <code class="docutils literal notranslate"><span class="pre">dependency_group</span></code> argument take an iterable?</a></li>
|
||
<li><a class="reference internal" href="#is-the-installer-backend-executed-in-process">Is the installer backend executed in-process?</a></li>
|
||
<li><a class="reference internal" href="#enforce-that-results-from-the-proposed-interface-feed-into-other-parts">Enforce that results from the proposed interface feed into other parts?</a></li>
|
||
<li><a class="reference internal" href="#raising-exceptions-instead-of-exit-codes-for-failure-conditions">Raising exceptions instead of exit codes for failure conditions</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-0650.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> |