CINXE.COM

PEP 704 – Require virtual environments by default for package installers | peps.python.org

<!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 704 – Require virtual environments by default for package installers | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0704/"> <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 704 – Require virtual environments by default for package installers | peps.python.org'> <meta property="og:description" content="This PEP recommends that package installers like pip require a virtual environment by default on Python 3.13+."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0704/"> <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 recommends that package installers like pip require a virtual environment by default on Python 3.13+."> <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 704</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 704 – Require virtual environments by default for package installers</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Pradyun Gedam &lt;pradyunsg&#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/22846">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-Jan-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/22846" title="Discourse thread">16-Jan-2023</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="#pep-withdrawal">PEP Withdrawal</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#requiring-a-virtual-environment-by-default">Requiring a virtual environment by default</a></li> <li><a class="reference internal" href="#opting-out-of-virtual-environments">Opting out of virtual environments</a></li> <li><a class="reference internal" href="#consistent-timeline-for-the-change">Consistent timeline for the change</a></li> </ul> </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="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#implementation-notes">Implementation Notes</a><ul> <li><a class="reference internal" href="#detecting-an-active-virtual-environment">Detecting an active virtual environment</a></li> <li><a class="reference internal" href="#documentation-on-using-a-virtual-environment">Documentation on using a virtual environment</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#do-not-specify-a-name-for-the-virtual-environment-directory">Do not specify a name for the virtual environment directory</a></li> <li><a class="reference internal" href="#use-a-different-name-for-the-virtual-environment-directory">Use a different name for the virtual environment directory</a></li> <li><a class="reference internal" href="#do-not-couple-tooling-behaviour-with-a-python-version">Do not couple tooling behaviour with a Python version</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a></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 recommends that package installers like <code class="docutils literal notranslate"><span class="pre">pip</span></code> require a virtual environment by default on Python 3.13+.</p> </section> <section id="pep-withdrawal"> <h2><a class="toc-backref" href="#pep-withdrawal" role="doc-backlink">PEP Withdrawal</a></h2> <p>During discussion of this PEP, it became clear that changes to pip’s UX are not controlled by PEPs as proposed. It also became clear that a significant number of users rely on being able to mix managed-by-pip dependencies with managed-by-some-other-tool dependencies (most prominently, when using Conda).</p> <p>Further, a significant subset of the benefits of the proposed change are achievable via <a class="pep reference internal" href="../pep-0668/" title="PEP 668 – Marking Python base environments as “externally managed”">PEP 668</a> (accepted and implemented at the time of writing). It provides redistributors of the Python interpreter control over whether users should be required to use a virtual environment, what the messaging presented to the user is and how the rollout of that change should happen for their users.</p> <p>Since enforcement of virtual environments with <code class="docutils literal notranslate"><span class="pre">pip</span></code> was the primary focus of this PEP, it felt more appropriate to withdraw this PEP than to refocus it on a different topic.</p> <p>A future PEP to resolve the virtual environment naming convention question/issues would still be appropriate, but it’s worth starting any such effort as a fresh PEP focused on the benefits of such a convention, rather than on the enforcement of it.</p> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>Python virtual environments are an essential part of the development workflow for Python. However, they require extra effort since they are an opt-in feature, and requires users to either:</p> <ul class="simple"> <li>take explicit steps to activate/deactivate a virtual environment</li> <li>use <code class="samp docutils literal notranslate"><em><span class="pre">&lt;path-to-venv&gt;</span></em><span class="pre">/</span><em><span class="pre">&lt;bin-path&gt;</span></em><span class="pre">/</span><em><span class="pre">&lt;executable&gt;</span></em></code> to run files</li> </ul> <p>For new users, things will seemingly work correctly when virtual environments are not used -— until they don’t. Further, activating a virtual environment uses slightly different syntax and mechanisms on different platforms. This complicates the introduction to virtual environments, since now information and context about how/why they are useful needs to explained to justify adding additional steps to the workflow.</p> <p>It also creates a scope for mistakes, since users need to remember to activate the virtual environment before running an installer like <code class="docutils literal notranslate"><span class="pre">pip</span></code> or configure those installers to error out. On certain Linux distributions, forgetting to do so can result in the installer modifying files that are owned by the operating system (which is partially mitigated by <a class="pep reference internal" href="../pep-0668/" title="PEP 668 – Marking Python base environments as “externally managed”">PEP 668</a> for distributions that opt-in to marking their environments accordingly).</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Changing the default behaviour of installers like <code class="docutils literal notranslate"><span class="pre">pip</span></code> to require a virtual environment to be active would:</p> <ul class="simple"> <li>make it easier for new users to get started with Python (since there’s a consistent experience and virtual environments are understood as a thing you’re required to use)</li> <li>reduce the scope for accidental installation issues for all users by default (by explicitly flagging when you’re not using a virtual environment).</li> </ul> <p>Setting up a convention of placing the virtual environment in-tree in a directory named <code class="docutils literal notranslate"><span class="pre">.venv</span></code> removes a decision point for common workflows and creates a clear convention within the ecosystem.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="requiring-a-virtual-environment-by-default"> <h3><a class="toc-backref" href="#requiring-a-virtual-environment-by-default" role="doc-backlink">Requiring a virtual environment by default</a></h3> <p>When a user runs an installer without an active virtual environment, the installer SHOULD print an error message and exit with a non-zero exit code.</p> <p>The error message SHOULD inform the user that a virtual environment is required, SHOULD provide shell-specific instructions on how to create and activate a virtual environment named <code class="docutils literal notranslate"><span class="pre">.venv</span></code>, and SHOULD provide a link to a documentation page that explains how to create and activate a virtual environment.</p> <p>See <a class="reference internal" href="#implementation-notes">Implementation Notes</a> for more details.</p> </section> <section id="opting-out-of-virtual-environments"> <h3><a class="toc-backref" href="#opting-out-of-virtual-environments" role="doc-backlink">Opting out of virtual environments</a></h3> <p>The installer SHOULD also provide a explicit opt-in to disable this requirement, allowing an end user to use it outside of a virtual environment. If the installer does not provide this functionality, it SHOULD mention this in the error message and documentation page.</p> </section> <section id="consistent-timeline-for-the-change"> <h3><a class="toc-backref" href="#consistent-timeline-for-the-change" role="doc-backlink">Consistent timeline for the change</a></h3> <p>Installers MAY choose to implement this default behaviour on any Python versions, but SHOULD implement it on Python 3.13 or newer.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>This PEP is backwards incompatible with workflows where users are using installers outside of virtual environments. Such users will be prompted with an error message and will need to either:</p> <ul class="simple"> <li>explicitly opt-in to running the installer outside of a virtual environment, or</li> <li>create and use a virtual environment</li> </ul> <p>Users who are already using virtual environments will not be affected by this change.</p> <p>Workflow tools (which manage virtual environments for the user, under the hood) should be unaffected, since they should already be using a virtual environment for running the installer.</p> </section> <section id="security-implications"> <h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <p>This PEP does not introduce any new security implications.</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 PEP requires that new users create and use a virtual environment to get started with using Python packages. This is, however, a best practice, as <a class="reference external" href="https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments">demonstrated</a> by the section on “basics of how to install Python packages” in the Python Packaging User Guide, which explains how/what virtual environments are before discussing using <code class="docutils literal notranslate"><span class="pre">pip</span></code>.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>There is no reference implementation for this PEP. However, the proposed behaviour is largely already implemented in <code class="docutils literal notranslate"><span class="pre">pip</span></code> and can be activated by setting the <code class="docutils literal notranslate"><span class="pre">PIP_REQUIRE_VENV</span></code> environment variable to <code class="docutils literal notranslate"><span class="pre">1</span></code>. (Leaving it unset results in the proposed opt-in behaviour of not requiring a virtual environment for installation.)</p> </section> <section id="implementation-notes"> <h2><a class="toc-backref" href="#implementation-notes" role="doc-backlink">Implementation Notes</a></h2> <section id="detecting-an-active-virtual-environment"> <h3><a class="toc-backref" href="#detecting-an-active-virtual-environment" role="doc-backlink">Detecting an active virtual environment</a></h3> <p><a class="pep reference internal" href="../pep-0668/#backwards-compatibility" title="PEP 668 – Marking Python base environments as “externally managed” § Backwards Compatibility">As discussed in PEP 668</a>, the logic for robustly detecting a virtual environment is something like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">is_virtual_environment</span><span class="p">():</span> <span class="k">return</span> <span class="n">sys</span><span class="o">.</span><span class="n">base_prefix</span> <span class="o">!=</span> <span class="n">sys</span><span class="o">.</span><span class="n">prefix</span> <span class="ow">or</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">sys</span><span class="p">,</span> <span class="s2">&quot;real_prefix&quot;</span><span class="p">)</span> </pre></div> </div> </section> <section id="documentation-on-using-a-virtual-environment"> <h3><a class="toc-backref" href="#documentation-on-using-a-virtual-environment" role="doc-backlink">Documentation on using a virtual environment</a></h3> <p>Package installers are expected to provide a link to a documentation page in the error message.</p> <p>Ideally, such a documentation page would explain what virtual environments are, why they are required, and how to create and activate a virtual environment using <code class="docutils literal notranslate"><span class="pre">venv</span></code>. It should include instructions for the most common shells and platforms.</p> <p>Such a documentation page should be made available in the <a class="reference external" href="https://packaging.python.org">Python Packaging User Guide</a> to reduce duplicated effort across installers for covering this topic.</p> </section> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="do-not-specify-a-name-for-the-virtual-environment-directory"> <h3><a class="toc-backref" href="#do-not-specify-a-name-for-the-virtual-environment-directory" role="doc-backlink">Do not specify a name for the virtual environment directory</a></h3> <p>Using a consistent name for the virtual environment directory is important for a few reasons:</p> <ol class="arabic simple"> <li>It makes it easier for users to find the virtual environment directory, and to activate it.</li> <li>It removes a decision point for new users, since they do not need to decide on a name for the virtual environment directory.</li> <li>It creates a clear convention within the ecosystem, which makes it easier for users to find documentation.</li> <li>It ensures consistency across different tools, so that differences in the error messages do not confuse users.</li> </ol> </section> <section id="use-a-different-name-for-the-virtual-environment-directory"> <h3><a class="toc-backref" href="#use-a-different-name-for-the-virtual-environment-directory" role="doc-backlink">Use a different name for the virtual environment directory</a></h3> <p>Functionally, the directory name does not matter much as long as there is a single consistent suggestion.</p> <p>The name <code class="docutils literal notranslate"><span class="pre">.venv</span></code> was picked since it:</p> <ol class="arabic simple"> <li>does not conflict with any valid Python import name</li> <li>does not conflict <code class="docutils literal notranslate"><span class="pre">venv</span></code> module in the standard library</li> <li>has pre-existing usage in the Python community</li> <li>has support for auto-detection in common text editors</li> <li>can be typed without modifier keys on common keyboard layouts</li> </ol> </section> <section id="do-not-couple-tooling-behaviour-with-a-python-version"> <h3><a class="toc-backref" href="#do-not-couple-tooling-behaviour-with-a-python-version" role="doc-backlink">Do not couple tooling behaviour with a Python version</a></h3> <p>This PEP creates a coupling between the behaviour of installers and the Python version.</p> <p>This is already a rollout mechanism being used for behaviour changes in the installation tooling. For example, <code class="docutils literal notranslate"><span class="pre">pip</span></code> on Python 3.11 will use <code class="docutils literal notranslate"><span class="pre">importlib.metadata</span></code> instead of <code class="docutils literal notranslate"><span class="pre">pkg_resources</span></code> for parsing/fetching package metadata, and <code class="docutils literal notranslate"><span class="pre">sysconfig</span></code> instead of <code class="docutils literal notranslate"><span class="pre">distutils.sysconfig</span></code> for getting the paths to unpack wheels into.</p> <p>The difference with those cases is that they’re supposed to be largely transparent to end users. This PEP is proposing a behaviour change that is not transparent to end users, and requires them to take action.</p> <p>The primary benefit of this is that it allows for redistributors to adapt their tooling in time for the new Python version and provides a clear and consistent point for change across the ecosystem. It also puts a clear deadline on when the default behaviour will consistently require a virtual environment by default (once Python 3.12 goes end-of-life).</p> <p>The primary issue with this approach is that it enforces a behaviour change on users when they upgrade to a new Python version, which can hamper the adoption of a new Python version. However, this is a migration/upgrade for existing users and it is a common expectation that <em>some</em> changes will be needed for migration/upgrades.</p> <p>The author of this PEP believes that the benefits of applying this consistently throughout the ecosystem with a deadline outweigh the drawbacks of enforcing a best-practice on users when they upgrade.</p> </section> </section> <section id="open-issues"> <h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2> <p>None.</p> </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-0704.rst">https://github.com/python/peps/blob/main/peps/pep-0704.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0704.rst">2025-02-01 08:55:40 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="#pep-withdrawal">PEP Withdrawal</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#requiring-a-virtual-environment-by-default">Requiring a virtual environment by default</a></li> <li><a class="reference internal" href="#opting-out-of-virtual-environments">Opting out of virtual environments</a></li> <li><a class="reference internal" href="#consistent-timeline-for-the-change">Consistent timeline for the change</a></li> </ul> </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="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#implementation-notes">Implementation Notes</a><ul> <li><a class="reference internal" href="#detecting-an-active-virtual-environment">Detecting an active virtual environment</a></li> <li><a class="reference internal" href="#documentation-on-using-a-virtual-environment">Documentation on using a virtual environment</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#do-not-specify-a-name-for-the-virtual-environment-directory">Do not specify a name for the virtual environment directory</a></li> <li><a class="reference internal" href="#use-a-different-name-for-the-virtual-environment-directory">Use a different name for the virtual environment directory</a></li> <li><a class="reference internal" href="#do-not-couple-tooling-behaviour-with-a-python-version">Do not couple tooling behaviour with a Python version</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a></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-0704.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>

Pages: 1 2 3 4 5 6 7 8 9 10