From 4add2ae156a28b057b01c43fe080a4ff98703774 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 19 Jan 2026 16:44:50 -0800 Subject: [PATCH 01/41] Metadata, Abstract, and opening of Motivation --- peps/pep-NNNN.rst | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 peps/pep-NNNN.rst diff --git a/peps/pep-NNNN.rst b/peps/pep-NNNN.rst new file mode 100644 index 00000000000..b070d84d1bb --- /dev/null +++ b/peps/pep-NNNN.rst @@ -0,0 +1,98 @@ +PEP: +Title: Virtual environment discovery +Author: Brett Cannon +Discussions-To: Pending +Status: Draft +Type: Standards Track +Created: 19-Jan-2026 +Python-Version: 3.15 +Post-History: Pending + + +Abstract +======== + +This PEP sets out to help make the discovery of a project's virtual environment +easier for tools by providing a default location as well as a way for a project +to point to its preferred virtual environment when it differs from the default +location. + + +Motivation +========== + +Typically, when someone is working on a project larger than a single file, a +long-lived virtual environment is desirable (the single file case is covered by +:pep:`723`). As such, tools working on the user's behalf may want to create +and/or use the same virtual environment. These tools could be custom scripts in +the project like running the test script or 3rd-party tools like package +installers. + +[Clearly explain why the existing language specification is inadequate to address the problem that the PEP solves.] + + +Rationale +========= + +[Describe why particular design decisions were made.] + + +Specification +============= + +[Describe the syntax and semantics of any new language feature.] + + +Backwards Compatibility +======================= + +[Describe potential impact and severity on pre-existing code.] + + +Security Implications +===================== + +[How could a malicious user take advantage of this new feature?] + + +How to Teach This +================= + +[How to teach users, new and experienced, how to apply the PEP to their work.] + + +Reference Implementation +======================== + +[Link to any existing implementation and details about its state, e.g. proof-of-concept.] + + +Rejected Ideas +============== + +[Why certain ideas that were brought while discussing this PEP were not ultimately pursued.] + + +Open Issues +=========== + +[Any points that are still being decided/discussed.] + + +Acknowledgements +================ + +[Thank anyone who has helped with the PEP.] + + +Footnotes +========= + +[A collection of footnotes cited in the PEP, and a place to list non-inline hyperlink targets.] + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive. From e0782aaca2161b675a06d3794ff533b1e0b17e08 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 21 Jan 2026 16:20:00 -0800 Subject: [PATCH 02/41] Finish Motivation --- peps/pep-NNNN.rst | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/peps/pep-NNNN.rst b/peps/pep-NNNN.rst index b070d84d1bb..276aee85b22 100644 --- a/peps/pep-NNNN.rst +++ b/peps/pep-NNNN.rst @@ -23,12 +23,32 @@ Motivation Typically, when someone is working on a project larger than a single file, a long-lived virtual environment is desirable (the single file case is covered by -:pep:`723`). As such, tools working on the user's behalf may want to create -and/or use the same virtual environment. These tools could be custom scripts in -the project like running the test script or 3rd-party tools like package -installers. - -[Clearly explain why the existing language specification is inadequate to address the problem that the PEP solves.] +:pep:`723` and ephemeral virtual environments). As such, tools working on the +user's behalf may want to create and/or use the same virtual environment. These +tools could be custom scripts in the project like running the test script or +3rd-party tools like package installers. + +Unfortunately, there's no guidance on where tools should put a virtual +environment or how to find where one is ultimately put. There's somewhat of a +convention in the community to put a virtual environment locally at the root of +the project in a directory named ``.venv``, but being a convention means it +isn't consistently followed. As well, there is no mechanism to point to a +virtual environment regardless of its location. + +This lack of knowing where to find a virtual environment for tools causes the +developer experience to not be as smooth as it could be. If you rely on shell +activation to use the proper virtual environment, then you have to make sure to +do that (either manually or by configuring some automatic shell integration) as +well as to not accidentally reuse that activated shell with another project (or +have set up shell automation to handle the deactivation). Otherwise tools need +to guess or have custom logic per tool that creates virtual environments or ask +users to manually specify where the virtual environment is. + +For virtual environment creation, it leads to different instructions per +project on what to do. And those instructions can be critical if scripts and +project configuration rely on the virtual environment being in a certain place. +This can also be an issue when a tool creates a virtual environment +automatically but it isn't obvious where the environment was placed. Rationale From f17b044d0845458bd2c7cbbc6168781bf7ab8265 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 21 Jan 2026 16:20:23 -0800 Subject: [PATCH 03/41] Big chunk of Rationale --- peps/pep-NNNN.rst | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/peps/pep-NNNN.rst b/peps/pep-NNNN.rst index 276aee85b22..5321b035844 100644 --- a/peps/pep-NNNN.rst +++ b/peps/pep-NNNN.rst @@ -54,7 +54,47 @@ automatically but it isn't obvious where the environment was placed. Rationale ========= -[Describe why particular design decisions were made.] +There are three aspects to where a virtual environment is placed. The first is +whether the virtual environment is local to the project or stored globally with +other virtual environments. Keeping the virtual environment local means that it +is isolated and unique to the project. As well, it means that if you delete the +project you also delete the virtual environment. If you store the virtual +environment globally then you can share it among multiple projects and delete +all virtual environments at once by deleting the directory that contains them +all. Keeping virtual environments global also means it won't be backed up +automatically if a project is stored e.g. in a directory automatically backed +up to remote storage where you pay based on how much storage you use. + +Another aspect is the directory name used for the virtual environment +(although this really only affects local virtual environments). If one views +virtual environments as more of a implementation detail, a directory name +starting with ``.`` seemingly makes sense to mark it hidden or de-emphasized +in various tools such as shells and code editors. But hiding it can make +accessing the directory harder by some tools. + +Lastly, there's whether you have one virtual environment at a time or many. +Having only one minimizes disk space and keeps it simple by not trying to +manage multiple virtual environments. Having multiple virtual environments, +though, means not having to constantly recreate virtual environments when e.g. +needing to test against multiple python versions. + +This PEP takes a two-pronged approach to making virtual environments easily +discoverable while supporting all aspects mentioned above. First, by default, +the virtual environment for the project should be put in the ``.venv`` +directory of the project. This name has been chosen due to preexisting tool +support: `Poetry `__ +will detect a virtual environment in such a location, +`PDM `__ +and `uv `__ +create their environments their by default already ( +`Hatch can support `__ +a virtual environment there). `VS Code `__ +will select it automatically while you can configure +`PyCharm `__ +to use it. The default ``.gitignore`` file for +`GitHub `__, +`GitLab `__, +XXX codeberg? Specification @@ -102,6 +142,8 @@ Open Issues Acknowledgements ================ +https://discuss.python.org/t/setting-up-some-guidelines-around-discovering-finding-naming-virtual-environments/22922/ + [Thank anyone who has helped with the PEP.] From e3ed3a76d6061fbfe0ff8fce19747c3c4cbe7b3d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 23 Jan 2026 15:39:09 -0800 Subject: [PATCH 04/41] Finish the Specification --- peps/pep-NNNN.rst | 76 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/peps/pep-NNNN.rst b/peps/pep-NNNN.rst index 5321b035844..4b8f5142021 100644 --- a/peps/pep-NNNN.rst +++ b/peps/pep-NNNN.rst @@ -31,7 +31,7 @@ tools could be custom scripts in the project like running the test script or Unfortunately, there's no guidance on where tools should put a virtual environment or how to find where one is ultimately put. There's somewhat of a convention in the community to put a virtual environment locally at the root of -the project in a directory named ``.venv``, but being a convention means it +the project in a directory named :file:`.venv`, but being a convention means it isn't consistently followed. As well, there is no mechanism to point to a virtual environment regardless of its location. @@ -68,7 +68,7 @@ up to remote storage where you pay based on how much storage you use. Another aspect is the directory name used for the virtual environment (although this really only affects local virtual environments). If one views virtual environments as more of a implementation detail, a directory name -starting with ``.`` seemingly makes sense to mark it hidden or de-emphasized +starting with :file:`.` seemingly makes sense to mark it hidden or de-emphasized in various tools such as shells and code editors. But hiding it can make accessing the directory harder by some tools. @@ -80,9 +80,10 @@ needing to test against multiple python versions. This PEP takes a two-pronged approach to making virtual environments easily discoverable while supporting all aspects mentioned above. First, by default, -the virtual environment for the project should be put in the ``.venv`` -directory of the project. This name has been chosen due to preexisting tool -support: `Poetry `__ +the virtual environment for the project should be put in the :file:`.venv` +directory of the project (this could be a hardlink, symlink, etc). This name +has been chosen due to preexisting tool support: +`Poetry `__ will detect a virtual environment in such a location, `PDM `__ and `uv `__ @@ -91,16 +92,75 @@ create their environments their by default already ( a virtual environment there). `VS Code `__ will select it automatically while you can configure `PyCharm `__ -to use it. The default ``.gitignore`` file for +to use it. The default :file:`.gitignore` file for `GitHub `__, `GitLab `__, -XXX codeberg? +and `Codeberg `__ +already ignore the path. + +But for various reasons (from personal preference to preexisting tool defaults), +the :file:`.venv` directory in the project root may not work. In those cases a +:file:`.venv` **file** which points to the virtual environment by default +should be provided in the project's root directory (i.e. the same location as +specified above for the :file:`.venv` directory). This file should point to the +virtual environment to use by default; there can be other virtual environments +for the project, but the :file:`.venv` file should point to the virtual +environment to be used if no preference is specified. While a hardlink or +symlink could serve the same purpose, not all file systems support such links. +As well, situations like the automatic backup case mentioned previously +requires a level of indirection that backup tools don't implicitly follow. Specification ============= -[Describe the syntax and semantics of any new language feature.] +The virtual environment for a project SHOULD be in a directory named +:file:`.venv` (i.e. :file:`.venv/pyvenv.cfg` will exist which can be used to +detect the existence of a virtual environment) in the root of the project +(typically next to the :file:`pyproject.toml`` file) if it makes sense for it +to reside there (e.g. the tool creating the virtual environment doesn't already +use a different location by default or the user didn't specify a location). +This can be a hardlink or symlink to a virtual environment. + +In all other situations where placing a virtual environment at the project root +in a :file:`.venv` directory is not possible or desirable, a :file:`.venv` +**file** SHOULD be written in the project root instead. The file's contents +are to be a single line containing the path to the directory containing the +virtual environment (i.e. the directory containing :file:`pyvenv.cfg`). A +trailing newline in the file is acceptable, and so code reading the file +should strip off any trailing newline. The path in the file is expected to be +specific to the machine it's on, so there are no requirements on path +formatting (i.e. a POSIX path is not required). The path MAY be relative to +ease in creating the file by hand. + +Tools looking for a virtual environment SHOULD look for the :file:`.venv` +directory or file and handle them appropriately. Tools SHOULD NOT prefer one +format over another when searching for a virtual environment (e.g. if a tool +looks up through parent directories for a virtual environment, it shouldn't +look for a directory first and then a file; the first thing found with the +:file:`.venv` path name should be chosen). + +This PEP proposes some changes to the :mod:`venv` module to go along with the +above recommendations: + +1. A ``DEFAULT_DIR: str`` global that's set to ``".venv"``. +2. :meth:`venv.EnvBuilder.create` gains a keyword-only + ``project_root: os.PathLike | None`` parameter that will write out a + :file:`.venv` file to that directory if the *env_dir* parameter is given a + path that doesn't end in ``DEFAULT_DIR``. +3. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of + ``DEFAULT_DIR`` (it's currently an error not to provide the argument) +4. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the + new parameter to :meth:`venv.EnvBuilder.create`; it will be an error to use + the option when multiple *ENV_DIR* arguments are provided. +5. A function named + ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` + will be added; it will look for a virtual environment in *dir* at + ``DEFAULT_DIR`` (directory or redirect file) and return the path to the + Python executable in the virtual environment, raising + :exc:`FileNotFoundError` if the path to a virtual environment is not found. + If *traverse* is true, then traversal through the parent directories of *dir* + to look for ``DEFAULT_DIR`` will be done. Backwards Compatibility From 43565603fcf7e579d31769ed211fd019ef4f5b98 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 23 Jan 2026 15:42:33 -0800 Subject: [PATCH 05/41] Use a placeholder name so `make html` works --- peps/{pep-NNNN.rst => pep-9999.rst} | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) rename peps/{pep-NNNN.rst => pep-9999.rst} (95%) diff --git a/peps/pep-NNNN.rst b/peps/pep-9999.rst similarity index 95% rename from peps/pep-NNNN.rst rename to peps/pep-9999.rst index 4b8f5142021..3711153abfe 100644 --- a/peps/pep-NNNN.rst +++ b/peps/pep-9999.rst @@ -1,4 +1,4 @@ -PEP: +PEP: 9999 Title: Virtual environment discovery Author: Brett Cannon Discussions-To: Pending @@ -154,13 +154,13 @@ above recommendations: new parameter to :meth:`venv.EnvBuilder.create`; it will be an error to use the option when multiple *ENV_DIR* arguments are provided. 5. A function named - ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` - will be added; it will look for a virtual environment in *dir* at - ``DEFAULT_DIR`` (directory or redirect file) and return the path to the - Python executable in the virtual environment, raising - :exc:`FileNotFoundError` if the path to a virtual environment is not found. - If *traverse* is true, then traversal through the parent directories of *dir* - to look for ``DEFAULT_DIR`` will be done. + ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` + will be added; it will look for a virtual environment in *dir* at + ``DEFAULT_DIR`` (directory or redirect file) and return the path to the + Python executable in the virtual environment, raising + :exc:`FileNotFoundError` if the path to a virtual environment is not found. + If *traverse* is true, then traversal through the parent directories of + *dir* to look for ``DEFAULT_DIR`` will be done. Backwards Compatibility From ee9f5e91ee48526a8086d94c2435c20ff8c0d814 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 23 Jan 2026 16:06:28 -0800 Subject: [PATCH 06/41] Add Backwards Compatibility --- peps/pep-9999.rst | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 3711153abfe..5644f0dd845 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -138,7 +138,9 @@ directory or file and handle them appropriately. Tools SHOULD NOT prefer one format over another when searching for a virtual environment (e.g. if a tool looks up through parent directories for a virtual environment, it shouldn't look for a directory first and then a file; the first thing found with the -:file:`.venv` path name should be chosen). +:file:`.venv` path name should be chosen). Sharing the same path name for both +the directory and file means there is no precedence issue within the same +directory. This PEP proposes some changes to the :mod:`venv` module to go along with the above recommendations: @@ -146,27 +148,34 @@ above recommendations: 1. A ``DEFAULT_DIR: str`` global that's set to ``".venv"``. 2. :meth:`venv.EnvBuilder.create` gains a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a - :file:`.venv` file to that directory if the *env_dir* parameter is given a - path that doesn't end in ``DEFAULT_DIR``. + :file:`.venv` file to that directory. If the value for *env_dir* and + *project_root* are the same then the file will not be created. 3. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of - ``DEFAULT_DIR`` (it's currently an error not to provide the argument) + ``DEFAULT_DIR`` (it's currently an error not to provide the argument). 4. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the - new parameter to :meth:`venv.EnvBuilder.create`; it will be an error to use + new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. 5. A function named ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_DIR`` (directory or redirect file) and return the path to the - Python executable in the virtual environment, raising + Python executable for the virtual environment, raising :exc:`FileNotFoundError` if the path to a virtual environment is not found. If *traverse* is true, then traversal through the parent directories of - *dir* to look for ``DEFAULT_DIR`` will be done. + *dir* to look for ``DEFAULT_DIR`` as a file or directory will be done. Backwards Compatibility ======================= -[Describe potential impact and severity on pre-existing code.] +For the virtual environment location aspect of this PEP, the backwards +compatibility concern would be over some alternative use of :file:`.venv`. But +due to the current usage already in the community, the likelihood of an +alternative usage is probably small. + +The other possible backwards compatibility concern is the new default value for +the ``-m venv`` CLI. But since it's currently an error not to specify the +directory, the impact should be minimal. Security Implications From e7ce165b489efe6bad183677f790008a34d46983 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 23 Jan 2026 16:24:12 -0800 Subject: [PATCH 07/41] Add Security Implications and How to Teach This --- peps/pep-9999.rst | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 5644f0dd845..5b8d99f386d 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -131,7 +131,9 @@ trailing newline in the file is acceptable, and so code reading the file should strip off any trailing newline. The path in the file is expected to be specific to the machine it's on, so there are no requirements on path formatting (i.e. a POSIX path is not required). The path MAY be relative to -ease in creating the file by hand. +ease in creating the file by hand. Tools MUST verify the path exists and is a +file before using the path to prevent from being tricked into e.g. blindly +passing the file contents into ``subprocess.run(..., shell=True)``. Tools looking for a virtual environment SHOULD look for the :file:`.venv` directory or file and handle them appropriately. Tools SHOULD NOT prefer one @@ -181,13 +183,28 @@ directory, the impact should be minimal. Security Implications ===================== -[How could a malicious user take advantage of this new feature?] +Not checking the contents of a potentially malicious :file:`.venv` file and +passing it to a shell process (e.g. ``subprocess.run(..., shell=True)``) would +be a serious security concern. This is why this PEP says tools MUST make sure +the path is valid before using it. + +Setting a :file:`.venv` file to a path that isn't a Python executable is only a +concern if the arguments the user provided to the executable were also a +concern. That then would require the user to then craft appropriate arguments +on top of using the malicious :file:`.venv` file. How to Teach This ================= -[How to teach users, new and experienced, how to apply the PEP to their work.] +For new users, they can be told that ``python -m venv`` creates a virtual +environment in :file:`.venv` as should any other tool that creates a virtual +environment on their behalf. + +For experienced users, they should be taught the default location for a +project's virtual environment is at the root of the project in :file:`.venv`. +If the currently active virtual environment lives elsewhere, a :file:`.venv` +will be there to tell them where to fins the virtual environment. Reference Implementation From 0790eb5b029ed409095cbc7d852207f9c6585883 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 27 Jan 2026 16:17:23 -0800 Subject: [PATCH 08/41] Reject other names --- peps/pep-9999.rst | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 5b8d99f386d..d43d583d610 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -147,24 +147,24 @@ directory. This PEP proposes some changes to the :mod:`venv` module to go along with the above recommendations: -1. A ``DEFAULT_DIR: str`` global that's set to ``".venv"``. +1. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. 2. :meth:`venv.EnvBuilder.create` gains a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a :file:`.venv` file to that directory. If the value for *env_dir* and *project_root* are the same then the file will not be created. 3. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of - ``DEFAULT_DIR`` (it's currently an error not to provide the argument). + ``DEFAULT_NAME`` (it's currently an error not to provide the argument). 4. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. 5. A function named ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at - ``DEFAULT_DIR`` (directory or redirect file) and return the path to the + ``DEFAULT_NAME`` (directory or redirect file) and return the path to the Python executable for the virtual environment, raising :exc:`FileNotFoundError` if the path to a virtual environment is not found. If *traverse* is true, then traversal through the parent directories of - *dir* to look for ``DEFAULT_DIR`` as a file or directory will be done. + *dir* to look for ``DEFAULT_NAME`` as a file or directory will be done. Backwards Compatibility @@ -216,6 +216,26 @@ Reference Implementation Rejected Ideas ============== +Use a name other than ``.venv`` +------------------------------- + +Some people either don't like that ``.venv`` is hidden by some tools by +default thanks to the leading ``.``, or don't like ``venv`` as an +abbreviation. Since there doesn't seem to be a clear concensus on an +alternative, a different name doesn't fundamentally change any semantics, +existing tools seem to already support ``.venv``, one can still use a different +name for an environment thanks to redirect file support as proposed by this +PEP, and the author of this PEP prefers the name, ``.venv`` was chosen. +Discussing alternative names was viewed as bikeshedding. + + +Support multiple virtual environments +------------------------------------- + +XXX multiple environments + +XXX no PEP at all (can't run code, know what version of Python, what it (not) installed for e.g. auto-complete and linting) + [Why certain ideas that were brought while discussing this PEP were not ultimately pursued.] From 35f0c1c7850750cbba2c1a846bd04c92600013a0 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 30 Jan 2026 13:00:28 -0800 Subject: [PATCH 09/41] Finish the initial draft --- peps/pep-9999.rst | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index d43d583d610..3f41f9631bf 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -232,31 +232,37 @@ Discussing alternative names was viewed as bikeshedding. Support multiple virtual environments ------------------------------------- -XXX multiple environments - -XXX no PEP at all (can't run code, know what version of Python, what it (not) installed for e.g. auto-complete and linting) - -[Why certain ideas that were brought while discussing this PEP were not ultimately pursued.] - - -Open Issues -=========== - -[Any points that are still being decided/discussed.] +Some workflow tools like +`Hatch `__, +`PDM `__, +and `Poetry `__ +support having multiple virtual environments for a project. It has been +suggested that any virtual environment location spec try to tackle the problem +of multiple virtual environments and not restrict itself to just one. + +Unfortunately multiple virtual environments actually makes this PEP's goal of +specifying what virtual environment tools should use at any moment even more +important. Having multiple virtual environments means there is ambiguity as to +what virtual environment to use at any one time. Most of these tools do +provide a mechanism to activate a virtual environment, but there is no +guarantee thas mechanism exposes the selection in a way that's easy for tools +to introspect. + +By having this PEP propose :file:`.venv` files to direct tools to a specific +virtual environment, it helps alleviate the need for this PEP to get involved +in how workflow tools manage virtual environments. Tools can store virtual +environments however they want while still communicating to other tools which +virtual environment it considered the active one. + +As well, tools like uv have shown that virtual environments are not a +requirement for a workflow tool to work, it's a (valid) design choice. Acknowledgements ================ -https://discuss.python.org/t/setting-up-some-guidelines-around-discovering-finding-naming-virtual-environments/22922/ - -[Thank anyone who has helped with the PEP.] - - -Footnotes -========= - -[A collection of footnotes cited in the PEP, and a place to list non-inline hyperlink targets.] +Thanks to everyone who participated in an earlier discussion on this topic at +https://discuss.python.org/t/22922/ . Copyright From b9c4aa9f19c7681b7e5e012b8cf6739bd3eb29a4 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 30 Jan 2026 13:04:42 -0800 Subject: [PATCH 10/41] Fix typos --- peps/pep-9999.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 3f41f9631bf..dbc33377f30 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -87,9 +87,9 @@ has been chosen due to preexisting tool support: will detect a virtual environment in such a location, `PDM `__ and `uv `__ -create their environments their by default already ( +create their environments there by default already ( `Hatch can support `__ -a virtual environment there). `VS Code `__ +a virtual environment there). `VS Code `__ will select it automatically while you can configure `PyCharm `__ to use it. The default :file:`.gitignore` file for @@ -117,7 +117,7 @@ Specification The virtual environment for a project SHOULD be in a directory named :file:`.venv` (i.e. :file:`.venv/pyvenv.cfg` will exist which can be used to detect the existence of a virtual environment) in the root of the project -(typically next to the :file:`pyproject.toml`` file) if it makes sense for it +(typically next to the :file:`pyproject.toml` file) if it makes sense for it to reside there (e.g. the tool creating the virtual environment doesn't already use a different location by default or the user didn't specify a location). This can be a hardlink or symlink to a virtual environment. @@ -204,7 +204,7 @@ environment on their behalf. For experienced users, they should be taught the default location for a project's virtual environment is at the root of the project in :file:`.venv`. If the currently active virtual environment lives elsewhere, a :file:`.venv` -will be there to tell them where to fins the virtual environment. +will be there to tell them where to find the virtual environment. Reference Implementation @@ -221,7 +221,7 @@ Use a name other than ``.venv`` Some people either don't like that ``.venv`` is hidden by some tools by default thanks to the leading ``.``, or don't like ``venv`` as an -abbreviation. Since there doesn't seem to be a clear concensus on an +abbreviation. Since there doesn't seem to be a clear consensus on an alternative, a different name doesn't fundamentally change any semantics, existing tools seem to already support ``.venv``, one can still use a different name for an environment thanks to redirect file support as proposed by this @@ -245,7 +245,7 @@ specifying what virtual environment tools should use at any moment even more important. Having multiple virtual environments means there is ambiguity as to what virtual environment to use at any one time. Most of these tools do provide a mechanism to activate a virtual environment, but there is no -guarantee thas mechanism exposes the selection in a way that's easy for tools +guarantee that mechanism exposes the selection in a way that's easy for tools to introspect. By having this PEP propose :file:`.venv` files to direct tools to a specific From 9bbe310f2a045b007570aae4020bdfc27c43907b Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 30 Jan 2026 13:10:31 -0800 Subject: [PATCH 11/41] Clarify some details --- peps/pep-9999.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index dbc33377f30..765fbbe466e 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -81,7 +81,7 @@ needing to test against multiple python versions. This PEP takes a two-pronged approach to making virtual environments easily discoverable while supporting all aspects mentioned above. First, by default, the virtual environment for the project should be put in the :file:`.venv` -directory of the project (this could be a hardlink, symlink, etc). This name +directory of the project (this can be a hardlink, symlink, etc). This name has been chosen due to preexisting tool support: `Poetry `__ will detect a virtual environment in such a location, @@ -127,13 +127,14 @@ in a :file:`.venv` directory is not possible or desirable, a :file:`.venv` **file** SHOULD be written in the project root instead. The file's contents are to be a single line containing the path to the directory containing the virtual environment (i.e. the directory containing :file:`pyvenv.cfg`). A -trailing newline in the file is acceptable, and so code reading the file +single trailing newline in the file is acceptable, and so code reading the file should strip off any trailing newline. The path in the file is expected to be specific to the machine it's on, so there are no requirements on path -formatting (i.e. a POSIX path is not required). The path MAY be relative to -ease in creating the file by hand. Tools MUST verify the path exists and is a -file before using the path to prevent from being tricked into e.g. blindly -passing the file contents into ``subprocess.run(..., shell=True)``. +formatting (i.e. a POSIX path is not required). The path MAY be relative to the +:file:`.venv` to ease in creating the file by hand. Tools MUST verify the path +exists and is a file before using the path to prevent from being tricked into +e.g. blindly passing the file contents into +``subprocess.run(..., shell=True)``. Tools looking for a virtual environment SHOULD look for the :file:`.venv` directory or file and handle them appropriately. Tools SHOULD NOT prefer one @@ -162,9 +163,11 @@ above recommendations: will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the Python executable for the virtual environment, raising - :exc:`FileNotFoundError` if the path to a virtual environment is not found. - If *traverse* is true, then traversal through the parent directories of - *dir* to look for ``DEFAULT_NAME`` as a file or directory will be done. + an exception if the path to a virtual environment is not found or the + virtual environment is somehow corrupted. If *traverse* is true, then + traversal through the parent directories of *dir* to look for + ``DEFAULT_NAME`` as a file or directory will be done and will stop at the + first ``DEFAULT_NAME`` found closest to *dir*. Backwards Compatibility From bcdb121bb953ec560cd42416c29223244e157590 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 30 Jan 2026 13:20:12 -0800 Subject: [PATCH 12/41] Update CODEOWNERS to fill in gaps --- .github/CODEOWNERS | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 37b4f6a033d..6216d223682 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -617,6 +617,7 @@ peps/pep-0735.rst @brettcannon peps/pep-0736.rst @Rosuav peps/pep-0737.rst @vstinner peps/pep-0738.rst @encukou +# peps/pep-0739.rst peps/pep-0740.rst @dstufft peps/pep-0741.rst @vstinner peps/pep-0742.rst @JelleZijlstra @@ -656,7 +657,6 @@ peps/pep-0775.rst @encukou peps/pep-0776.rst @hoodmane @ambv peps/pep-0777.rst @warsaw @emmatyping peps/pep-0778.rst @warsaw @emmatyping -# ... peps/pep-0779.rst @Yhg1s @colesbury @mpage peps/pep-0780.rst @lysnikolaou peps/pep-0781.rst @methane @@ -664,7 +664,7 @@ peps/pep-0782.rst @vstinner peps/pep-0783.rst @hoodmane @ambv peps/pep-0784.rst @gpshead @emmatyping peps/pep-0785.rst @gpshead -# ... +# peps/pep-0786.rst peps/pep-0787.rst @ncoghlan peps/pep-0788.rst @ZeroIntensity @vstinner peps/pep-0789.rst @njsmith @@ -681,19 +681,21 @@ peps/pep-0801.rst @warsaw peps/pep-0802.rst @AA-Turner peps/pep-0803.rst @encukou peps/pep-0804.rst @pradyunsg -# ... +# peps/pep-0805.rst peps/pep-0806.rst @JelleZijlstra peps/pep-0807.rst @dstufft peps/pep-0808.rst @FFY00 peps/pep-0809.rst @zooba peps/pep-0810.rst @pablogsal @DinoV @Yhg1s peps/pep-0811.rst @sethmlarson @gpshead -# ... +# peps/pep-0812.rst +# peps/pep-0813.rst peps/pep-0814.rst @vstinner @corona10 peps/pep-0815.rst @emmatyping peps/pep-0816.rst @brettcannon peps/pep-0817.rst @warsaw @dstufft peps/pep-0817/ @warsaw @dstufft +# peps/pep-0818.rst # ... peps/pep-0819.rst @emmatyping peps/pep-0820.rst @encukou @@ -781,5 +783,4 @@ peps/pep-8015.rst @vstinner peps/pep-8016.rst @njsmith @dstufft # ... peps/pep-8100.rst @njsmith -# peps/pep-8101.rst -# peps/pep-8102.rst +# 81** PEPs are collectively owned, so no individual assignees. From 5c803546c9d39c8be36562d8d45f2cd14ede5e2e Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 2 Feb 2026 14:11:01 -0800 Subject: [PATCH 13/41] Clarify details --- peps/pep-9999.rst | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 765fbbe466e..8192f6d8238 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -67,7 +67,7 @@ up to remote storage where you pay based on how much storage you use. Another aspect is the directory name used for the virtual environment (although this really only affects local virtual environments). If one views -virtual environments as more of a implementation detail, a directory name +virtual environments as more of an implementation detail, a directory name starting with :file:`.` seemingly makes sense to mark it hidden or de-emphasized in various tools such as shells and code editors. But hiding it can make accessing the directory harder by some tools. @@ -106,9 +106,23 @@ specified above for the :file:`.venv` directory). This file should point to the virtual environment to use by default; there can be other virtual environments for the project, but the :file:`.venv` file should point to the virtual environment to be used if no preference is specified. While a hardlink or -symlink could serve the same purpose, not all file systems support such links. -As well, situations like the automatic backup case mentioned previously -requires a level of indirection that backup tools don't implicitly follow. +symlink for :file:`.venv` could serve the same purpose, not all file systems +support such links. As well, situations like the automatic backup case +mentioned previously require a level of indirection that backup tools don't +implicitly follow. + +The :file:`.venv` file is meant to represent the virtual environment a workflow +tool that is external to the one that wrote the :file:`.venv` file is expected +to use (e.g. Hatch wrote the file and VS Code is going to read it). This means +that a workflow tool shouldn't update the :file:`.venv` file as it runs a test +suite through multiple versions of Python. But if the workflow tool has a +command to control what virtual environment is used when typing ``python`` in +the shell or an equivalent command by default, then the file should be updated +as necessary to match what environment the workflow tool would use +(e.g. :file:`.venv` should always match what virtual environment +` ``hatch run`` `__ +would use). This is not expected to cause a "noisy neighbour" problem as it's +not expected to change that rapidly. Specification @@ -131,9 +145,9 @@ single trailing newline in the file is acceptable, and so code reading the file should strip off any trailing newline. The path in the file is expected to be specific to the machine it's on, so there are no requirements on path formatting (i.e. a POSIX path is not required). The path MAY be relative to the -:file:`.venv` to ease in creating the file by hand. Tools MUST verify the path -exists and is a file before using the path to prevent from being tricked into -e.g. blindly passing the file contents into +:file:`.venv` to ease in creating the file by hand. Tools MUST verify the +directory the file points to exists before using it to prevent tools from being +tricked into e.g. blindly passing the file contents into ``subprocess.run(..., shell=True)``. Tools looking for a virtual environment SHOULD look for the :file:`.venv` @@ -159,7 +173,7 @@ above recommendations: new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. 5. A function named - ``executable(dir: os.PathLike, *, traverse: bool = False)) -> pathlib.Path`` + ``executable(dir: os.PathLike, *, traverse: bool = False) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the Python executable for the virtual environment, raising @@ -265,7 +279,8 @@ Acknowledgements ================ Thanks to everyone who participated in an earlier discussion on this topic at -https://discuss.python.org/t/22922/ . +https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch and +Randy Döring of Poetry for feedback on the initial draft of this PEP. Copyright From 8f4f41abe8995f95ec35e652f8ced1a8796b9a13 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 3 Feb 2026 16:19:49 -0800 Subject: [PATCH 14/41] Add more names to ACKS --- peps/pep-9999.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 8192f6d8238..2769e875832 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -279,8 +279,9 @@ Acknowledgements ================ Thanks to everyone who participated in an earlier discussion on this topic at -https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch and -Randy Döring of Poetry for feedback on the initial draft of this PEP. +https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch, +Randy Döring of Poetry, and Frost Ming of PDM for feedback on the initial draft +of this PEP. Copyright From 364cd0a785f1607c98bc8b598e7972a7632dd3ed Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 6 Feb 2026 13:09:09 -0800 Subject: [PATCH 15/41] Add guidance about `.venv` and version control --- peps/pep-9999.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 2769e875832..66366f94299 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -183,6 +183,16 @@ above recommendations: ``DEFAULT_NAME`` as a file or directory will be done and will stop at the first ``DEFAULT_NAME`` found closest to *dir*. +In regards to committing a :file:`.venv` file to version control, it MAY be +done when the location of the virtual environment is considered static to a +project once it is set up. For instance, some projects that use tox_ have a +"dev" environment defined in their configuration that ends up at `.tox/dev`. +Setting a :file:`.venv` file to point to that virtual environment and checking +in the file is reasonable. The same goes for a project that is only worked on +within a container where the location of the virtual environment is controlled +and thus static on the file system. The guidance of NOT committing your actual +virtual environment to version control is unchanged by this PEP. + Backwards Compatibility ======================= @@ -289,3 +299,6 @@ Copyright This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive. + + +.. _tox: https://tox.wiki/ From b82cebd9841f16b3d7b22fbc99f47e1b6e77e268 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 6 Feb 2026 13:11:21 -0800 Subject: [PATCH 16/41] =?UTF-8?q?Thank=20Bern=C3=A1t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- peps/pep-9999.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 66366f94299..a3b60d4b079 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -290,8 +290,8 @@ Acknowledgements Thanks to everyone who participated in an earlier discussion on this topic at https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch, -Randy Döring of Poetry, and Frost Ming of PDM for feedback on the initial draft -of this PEP. +Randy Döring of Poetry, Frost Ming of PDM, and Bernát Gábor of virtualenv & tox +for feedback on the initial draft of this PEP. Copyright From 98ade21c39f945cc9cdf45eeb33b8dd7da6cf520 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 11 Feb 2026 16:24:06 -0800 Subject: [PATCH 17/41] Clarify language regarding the use of non-executable paths in the .venv file --- peps/pep-9999.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index a3b60d4b079..f2f523c7d52 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -215,8 +215,8 @@ passing it to a shell process (e.g. ``subprocess.run(..., shell=True)``) would be a serious security concern. This is why this PEP says tools MUST make sure the path is valid before using it. -Setting a :file:`.venv` file to a path that isn't a Python executable is only a -concern if the arguments the user provided to the executable were also a +Setting a :file:`.venv` file to a path that isn't a virtual environment is only +a concern if the arguments the user provided to the executable were also a concern. That then would require the user to then craft appropriate arguments on top of using the malicious :file:`.venv` file. From da7bc6abe7d370aa2edd597b71b87c265e27fb8d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 11 Feb 2026 16:25:02 -0800 Subject: [PATCH 18/41] Add Vinay Sajip to acknowledgements --- peps/pep-9999.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index f2f523c7d52..d5e2bbb96a7 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -290,8 +290,8 @@ Acknowledgements Thanks to everyone who participated in an earlier discussion on this topic at https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch, -Randy Döring of Poetry, Frost Ming of PDM, and Bernát Gábor of virtualenv & tox -for feedback on the initial draft of this PEP. +Randy Döring of Poetry, Frost Ming of PDM, Bernát Gábor of virtualenv & tox, +and Vinay Sajip of venv for feedback on the initial draft of this PEP. Copyright From eb5b6bfce992e52f02ee1de668081c66d996e6c8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 20 Feb 2026 15:50:52 -0800 Subject: [PATCH 19/41] Clarify language regarding access to hidden virtual environment directories and simplify explanations about managing multiple environments --- peps/pep-9999.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index d5e2bbb96a7..019f5c62d20 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -70,13 +70,14 @@ Another aspect is the directory name used for the virtual environment virtual environments as more of an implementation detail, a directory name starting with :file:`.` seemingly makes sense to mark it hidden or de-emphasized in various tools such as shells and code editors. But hiding it can make -accessing the directory harder by some tools. +accessing the directory harder via tools that don't expose paths starting with +a ``.``. Lastly, there's whether you have one virtual environment at a time or many. -Having only one minimizes disk space and keeps it simple by not trying to -manage multiple virtual environments. Having multiple virtual environments, -though, means not having to constantly recreate virtual environments when e.g. -needing to test against multiple python versions. +Having only one can minimize disk space for some tools and keeps it simple by +not trying to manage multiple virtual environments. Having multiple virtual +environments, though, means not having to constantly recreate virtual +environments when e.g. needing to test against multiple python versions. This PEP takes a two-pronged approach to making virtual environments easily discoverable while supporting all aspects mentioned above. First, by default, @@ -105,9 +106,9 @@ should be provided in the project's root directory (i.e. the same location as specified above for the :file:`.venv` directory). This file should point to the virtual environment to use by default; there can be other virtual environments for the project, but the :file:`.venv` file should point to the virtual -environment to be used if no preference is specified. While a hardlink or -symlink for :file:`.venv` could serve the same purpose, not all file systems -support such links. As well, situations like the automatic backup case +environment to be used if no preference is specified. While a hardlink, +symlink, etc. for :file:`.venv` could serve the same purpose, not all file +systems support such links. As well, situations like the automatic backup case mentioned previously require a level of indirection that backup tools don't implicitly follow. @@ -116,10 +117,9 @@ tool that is external to the one that wrote the :file:`.venv` file is expected to use (e.g. Hatch wrote the file and VS Code is going to read it). This means that a workflow tool shouldn't update the :file:`.venv` file as it runs a test suite through multiple versions of Python. But if the workflow tool has a -command to control what virtual environment is used when typing ``python`` in -the shell or an equivalent command by default, then the file should be updated -as necessary to match what environment the workflow tool would use -(e.g. :file:`.venv` should always match what virtual environment +command to control what virtual environment is used when runnig Python, then +the file should be updated as necessary to match what environment the workflow +tool would use (e.g. :file:`.venv` should always match what virtual environment ` ``hatch run`` `__ would use). This is not expected to cause a "noisy neighbour" problem as it's not expected to change that rapidly. From d42ed5e8c9a5eb516b582e1da5b89f66ed9441eb Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 23 Mar 2026 13:40:09 -0700 Subject: [PATCH 20/41] Thank Zanie --- peps/pep-9999.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 019f5c62d20..084ae4bc592 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -291,7 +291,8 @@ Acknowledgements Thanks to everyone who participated in an earlier discussion on this topic at https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch, Randy Döring of Poetry, Frost Ming of PDM, Bernát Gábor of virtualenv & tox, -and Vinay Sajip of venv for feedback on the initial draft of this PEP. +Vinay Sajip of venv, and Zanie Blue of uv for feedback on the initial draft of +this PEP. Copyright From 5521cd1fe7a73fe6df16e40bcd17438a1cff0718 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 23 Mar 2026 13:40:25 -0700 Subject: [PATCH 21/41] List tool support --- peps/pep-9999.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 084ae4bc592..cd680102bae 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -194,6 +194,24 @@ and thus static on the file system. The guidance of NOT committing your actual virtual environment to version control is unchanged by this PEP. +Project Support for this PEP +============================ + +Speaking to various tool maintainers about this PEP: + +- Supports + 1. PDM (Frost Ming) + 2. Poetry (Randy Döring) + 3. venv (Vinay Sajip) + 4. Virtualenv (Bernát Gábor) + 5. Tox (Bernát Gábor) + 6. Hatch (Cary Hawkins) +- Lukewarm + 1. uv (Zanie Blue) +- Opposes + 1. Hatch (Ofek Lev) + + Backwards Compatibility ======================= From bc44d20f729f43be9435591de89fdd80196a3063 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 23 Mar 2026 13:40:47 -0700 Subject: [PATCH 22/41] Cover how tools will likely error out if they don't support `.venv` files --- peps/pep-9999.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index cd680102bae..4dbbb52d198 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -218,7 +218,11 @@ Backwards Compatibility For the virtual environment location aspect of this PEP, the backwards compatibility concern would be over some alternative use of :file:`.venv`. But due to the current usage already in the community, the likelihood of an -alternative usage is probably small. +alternative usage is probably small. This will likely lead to tools showing an +error message when a ``.venv`` file is used, though. While the error message +would like be around ``.venv`` being a file and thus not explaining *why* +there's a file, it just prevent any tool overlooking the ``.venv`` file and +blindly creating another virtual environment. The other possible backwards compatibility concern is the new default value for the ``-m venv`` CLI. But since it's currently an error not to specify the From e0fdf6b92b3110ed101881ce69248c73e120edf8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 23 Mar 2026 13:43:43 -0700 Subject: [PATCH 23/41] Add an open issue about supporting multiple virtual environments via an API --- peps/pep-9999.rst | 76 ++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 4dbbb52d198..f7cda66cd9a 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -278,33 +278,55 @@ PEP, and the author of this PEP prefers the name, ``.venv`` was chosen. Discussing alternative names was viewed as bikeshedding. -Support multiple virtual environments -------------------------------------- - -Some workflow tools like -`Hatch `__, -`PDM `__, -and `Poetry `__ -support having multiple virtual environments for a project. It has been -suggested that any virtual environment location spec try to tackle the problem -of multiple virtual environments and not restrict itself to just one. - -Unfortunately multiple virtual environments actually makes this PEP's goal of -specifying what virtual environment tools should use at any moment even more -important. Having multiple virtual environments means there is ambiguity as to -what virtual environment to use at any one time. Most of these tools do -provide a mechanism to activate a virtual environment, but there is no -guarantee that mechanism exposes the selection in a way that's easy for tools -to introspect. - -By having this PEP propose :file:`.venv` files to direct tools to a specific -virtual environment, it helps alleviate the need for this PEP to get involved -in how workflow tools manage virtual environments. Tools can store virtual -environments however they want while still communicating to other tools which -virtual environment it considered the active one. - -As well, tools like uv have shown that virtual environments are not a -requirement for a workflow tool to work, it's a (valid) design choice. +Open Issues +=========== + +An API for discovering environments +----------------------------------- + +While what the PEP currently proposes is simple, there has been some concern +that it's *too* simple. As such, there's an open concern that an API to allow +for broader environment discovery is necessary. + +A possible way to provide such an API is to introduce a ``[workflow]`` table to +:file:`pyproject.toml`. That could have an ``environments`` key which held a +table specifying how to run a discovery app to get environment details in +JSON. For example: + +.. code-block:: toml + + [workflow] + environments = {tool = "...", command = ["..."]} + +The command could output JSON that lists any and all known environments. For +flexibility the output can could more than just virtual environments, such as +global installs of Python. The output could also specify the environment to use +by default if a tool doesn't have a reason or way to make a choice of which +environment to use. + +.. code-block:: json + + { + "version": "1.0", // ... or whatever to version the JSON schema. + "default": 0, // Optional; index into + "environments": [ + { + "type": "virtual", + "path": ".venv", + "python_version": "...", // Optional + "name": "..." // Optional + }, + ... + ] + } + +The discovery tool could also create a virtual environment as a side-effect +of being called. As well, it could write out a ``.venv`` file or directory if +it makes sense. Having ``.venv`` checked for prior to calling the discovery +tool would help avoid the overhead of calling the discovery tool. + +But this does expand the complexity of this PEP. It also isn't necessary to +be a part of this PEP as it could be added later on. Acknowledgements From 21ceb60c2d88ca5f8c657d8fc139e42f5ff22bcd Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 23 Mar 2026 14:10:16 -0700 Subject: [PATCH 24/41] Minor clarifications --- peps/pep-9999.rst | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index f7cda66cd9a..a1db3c65b57 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -81,7 +81,7 @@ environments when e.g. needing to test against multiple python versions. This PEP takes a two-pronged approach to making virtual environments easily discoverable while supporting all aspects mentioned above. First, by default, -the virtual environment for the project should be put in the :file:`.venv` +the virtual environment for the project could be put in the :file:`.venv` directory of the project (this can be a hardlink, symlink, etc). This name has been chosen due to preexisting tool support: `Poetry `__ @@ -109,18 +109,18 @@ for the project, but the :file:`.venv` file should point to the virtual environment to be used if no preference is specified. While a hardlink, symlink, etc. for :file:`.venv` could serve the same purpose, not all file systems support such links. As well, situations like the automatic backup case -mentioned previously require a level of indirection that backup tools don't -implicitly follow. +mentioned previously require a level of indirection so that backup tools don't +implicitly follow into a virtual environment and back it up. The :file:`.venv` file is meant to represent the virtual environment a workflow -tool that is external to the one that wrote the :file:`.venv` file is expected -to use (e.g. Hatch wrote the file and VS Code is going to read it). This means -that a workflow tool shouldn't update the :file:`.venv` file as it runs a test -suite through multiple versions of Python. But if the workflow tool has a -command to control what virtual environment is used when runnig Python, then -the file should be updated as necessary to match what environment the workflow -tool would use (e.g. :file:`.venv` should always match what virtual environment -` ``hatch run`` `__ +tool is expected to use that is external to the one that wrote the +:file:`.venv` file (e.g. Hatch wrote the file and VS Code is going to read it). +This means that a workflow tool shouldn't update the :file:`.venv` file as it +runs a test suite through multiple versions of Python. But if the workflow tool +has a command to control what virtual environment is used when runnig Python, +then the file should be updated as necessary to match what environment the +workflow tool would use (e.g. :file:`.venv` should always match what virtual +environment ` ``hatch run`` `__ would use). This is not expected to cause a "noisy neighbour" problem as it's not expected to change that rapidly. @@ -145,7 +145,7 @@ single trailing newline in the file is acceptable, and so code reading the file should strip off any trailing newline. The path in the file is expected to be specific to the machine it's on, so there are no requirements on path formatting (i.e. a POSIX path is not required). The path MAY be relative to the -:file:`.venv` to ease in creating the file by hand. Tools MUST verify the +:file:`.venv` file to ease in creating the file by hand. Tools MUST verify the directory the file points to exists before using it to prevent tools from being tricked into e.g. blindly passing the file contents into ``subprocess.run(..., shell=True)``. @@ -329,6 +329,15 @@ But this does expand the complexity of this PEP. It also isn't necessary to be a part of this PEP as it could be added later on. +"MAY" instead of "SHOULD" +------------------------- + +Some have suggested removing the "SHOULD" for ``.venv`` in either the directory +or file case and make it a "MAY". That would weaken the PEP, but that is +what some want in order to not feel like a specific workflow is being forced +upon tool authors. + + Acknowledgements ================ From e5dc86e143b0adc0f28a760332da0dceaf5fa306 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 10 Apr 2026 12:19:08 -0700 Subject: [PATCH 25/41] Introduce new method for creating redirect files --- peps/pep-9999.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index a1db3c65b57..ade90551bf0 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -163,16 +163,22 @@ This PEP proposes some changes to the :mod:`venv` module to go along with the above recommendations: 1. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. -2. :meth:`venv.EnvBuilder.create` gains a keyword-only +2. :cls:`venv.EnvBuilder` gains a method: + ``create_redirect_file(env_dir: os.PathLike, project_root: os.PathLike) -> None``. + The method will create a redirect file at ``project_root / DEFAULT_NAME`` + that points to *env_dir*. +3. :meth:`venv.EnvBuilder.create` gains a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a - :file:`.venv` file to that directory. If the value for *env_dir* and - *project_root* are the same then the file will not be created. -3. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of + :file:`.venv` file to that directory via + ``EnvBuilder.create_redirect_file()``. If the value for *env_dir* ends in + ``DEFAULT_NAME`` and *project_root* points to the parent directory of + *env_dir* then ``create_redirect_file()`` will not be called. +4. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of ``DEFAULT_NAME`` (it's currently an error not to provide the argument). -4. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the +5. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. -5. A function named +6. A function named ``executable(dir: os.PathLike, *, traverse: bool = False) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the From 656d6d806fd1d8a701c9d86285ccba3db451eec8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 10 Apr 2026 12:27:36 -0700 Subject: [PATCH 26/41] Specify `create(env_dir=DEFAULT_NAME)` --- peps/pep-9999.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index ade90551bf0..aeafe4c6921 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -173,12 +173,14 @@ above recommendations: ``EnvBuilder.create_redirect_file()``. If the value for *env_dir* ends in ``DEFAULT_NAME`` and *project_root* points to the parent directory of *env_dir* then ``create_redirect_file()`` will not be called. -4. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of +4. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` gets a default + value of ``DEFAULT_NAME``. +5. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of ``DEFAULT_NAME`` (it's currently an error not to provide the argument). -5. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the +6. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. -6. A function named +7. A function named ``executable(dir: os.PathLike, *, traverse: bool = False) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the From 60717b5ea03bed9668166b0960e4abe0f1f634e1 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 12 Apr 2026 13:20:01 -0700 Subject: [PATCH 27/41] Clarify requirements for .venv file encoding and newline handling --- peps/pep-9999.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index aeafe4c6921..b8cca34cbca 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -140,15 +140,15 @@ In all other situations where placing a virtual environment at the project root in a :file:`.venv` directory is not possible or desirable, a :file:`.venv` **file** SHOULD be written in the project root instead. The file's contents are to be a single line containing the path to the directory containing the -virtual environment (i.e. the directory containing :file:`pyvenv.cfg`). A -single trailing newline in the file is acceptable, and so code reading the file -should strip off any trailing newline. The path in the file is expected to be -specific to the machine it's on, so there are no requirements on path -formatting (i.e. a POSIX path is not required). The path MAY be relative to the -:file:`.venv` file to ease in creating the file by hand. Tools MUST verify the -directory the file points to exists before using it to prevent tools from being -tricked into e.g. blindly passing the file contents into -``subprocess.run(..., shell=True)``. +virtual environment (i.e. the directory containing :file:`pyvenv.cfg`). The +file MUST be encoded at UTF-8. A single trailing newline in the file is +acceptable (either ``\r\n`` or ``\n``), and so code reading the file should +strip off any trailing newline. The path in the file is expected to be specific +to the machine it's on, so there are no requirements on path formatting (i.e. a +POSIX path is not required). The path MAY be relative to the :file:`.venv` file +to ease in creating the file by hand. Tools MUST verify the directory the file +points to exists before using it to prevent tools from being tricked into e.g. +blindly passing the file contents into ``subprocess.run(..., shell=True)``. Tools looking for a virtual environment SHOULD look for the :file:`.venv` directory or file and handle them appropriately. Tools SHOULD NOT prefer one From 4ccc3eceba2b04807556e280b4eb17fcdf2ef104 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 12 Apr 2026 13:20:22 -0700 Subject: [PATCH 28/41] Clarify that `executable()` looks for `python` --- peps/pep-9999.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index b8cca34cbca..8b377f6bba9 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -184,7 +184,7 @@ above recommendations: ``executable(dir: os.PathLike, *, traverse: bool = False) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the - Python executable for the virtual environment, raising + ``python`` executable for the virtual environment, raising an exception if the path to a virtual environment is not found or the virtual environment is somehow corrupted. If *traverse* is true, then traversal through the parent directories of *dir* to look for From d67e8e45b3ae7c9d468b509daecdd52a9a0aad70 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 12 Apr 2026 14:10:36 -0700 Subject: [PATCH 29/41] Clarify that the *env_dir* parameter for both `venv.EnvBuilder.create` and `venv.create` has a default value of ``DEFAULT_NAME`` --- peps/pep-9999.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 8b377f6bba9..f612df851b2 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -173,8 +173,8 @@ above recommendations: ``EnvBuilder.create_redirect_file()``. If the value for *env_dir* ends in ``DEFAULT_NAME`` and *project_root* points to the parent directory of *env_dir* then ``create_redirect_file()`` will not be called. -4. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` gets a default - value of ``DEFAULT_NAME``. +4. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` and + :func:`venv.create` get a default value of ``DEFAULT_NAME``. 5. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of ``DEFAULT_NAME`` (it's currently an error not to provide the argument). 6. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the From 90c56ba58798d4fec3fc9164e8996ba840070b0f Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 12 Apr 2026 14:18:57 -0700 Subject: [PATCH 30/41] Clarify that both `venv.EnvBuilder.create` and `venv.create` gain a keyword-only `project_root` parameter for redirect file creation --- peps/pep-9999.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index f612df851b2..613ad51a7bb 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -167,7 +167,7 @@ above recommendations: ``create_redirect_file(env_dir: os.PathLike, project_root: os.PathLike) -> None``. The method will create a redirect file at ``project_root / DEFAULT_NAME`` that points to *env_dir*. -3. :meth:`venv.EnvBuilder.create` gains a keyword-only +3. :meth:`venv.EnvBuilder.create` and :func:`venv.create` gain a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a :file:`.venv` file to that directory via ``EnvBuilder.create_redirect_file()``. If the value for *env_dir* ends in From 23d49d97a1edb01c481a1a572563e5a8032e9615 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 13 Apr 2026 10:28:48 -0700 Subject: [PATCH 31/41] Add `read_redirect_file()` --- peps/pep-9999.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 613ad51a7bb..596313f6a2f 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -163,16 +163,20 @@ This PEP proposes some changes to the :mod:`venv` module to go along with the above recommendations: 1. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. +2. Create a + ``read_redirect_file(project_root: os.PathLike|str) -> Pathlib.Path[str]`` + function for getting the path from a redirect file in *project_root*. 2. :cls:`venv.EnvBuilder` gains a method: - ``create_redirect_file(env_dir: os.PathLike, project_root: os.PathLike) -> None``. - The method will create a redirect file at ``project_root / DEFAULT_NAME`` - that points to *env_dir*. + ``write_redirect_file(project_root: os.PathLike, env_dir: os.PathLike) -> None`` + and an equivalent function for the module. The function and method will + create a redirect file at ``project_root / DEFAULT_NAME`` that points to + *env_dir*. 3. :meth:`venv.EnvBuilder.create` and :func:`venv.create` gain a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a :file:`.venv` file to that directory via - ``EnvBuilder.create_redirect_file()``. If the value for *env_dir* ends in + ``EnvBuilder.write_redirect_file()``. If the value for *env_dir* ends in ``DEFAULT_NAME`` and *project_root* points to the parent directory of - *env_dir* then ``create_redirect_file()`` will not be called. + *env_dir* then ``write_redirect_file()`` will not be called. 4. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` and :func:`venv.create` get a default value of ``DEFAULT_NAME``. 5. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of From 923c4867ffa9c49ecf22b1ab43299b57d02e4468 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 13 Apr 2026 16:35:09 -0700 Subject: [PATCH 32/41] Clarify the creation of redirect files in `project_root` for `read_redirect_file()` --- peps/pep-9999.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 596313f6a2f..376a3ad1bfb 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -165,12 +165,13 @@ above recommendations: 1. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. 2. Create a ``read_redirect_file(project_root: os.PathLike|str) -> Pathlib.Path[str]`` - function for getting the path from a redirect file in *project_root*. -2. :cls:`venv.EnvBuilder` gains a method: + function for getting the path from a redirect file in + ``project_root / DEFAULT_NAME``. +2. :cls:`venv.EnvBuilder` gains ``write_redirect_file(project_root: os.PathLike, env_dir: os.PathLike) -> None`` - and an equivalent function for the module. The function and method will - create a redirect file at ``project_root / DEFAULT_NAME`` that points to - *env_dir*. + and an equivalent ``write_redirect_file()`` function for the module. The + function and method will create a redirect file at + ``project_root / DEFAULT_NAME`` that points to *env_dir*. 3. :meth:`venv.EnvBuilder.create` and :func:`venv.create` gain a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a :file:`.venv` file to that directory via From 49446f21f71d0b2ca503a6241e499a1df75655fd Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:00:25 -0700 Subject: [PATCH 33/41] Add the reference implementation --- peps/pep-9999.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 376a3ad1bfb..8b6b5deb267 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -272,7 +272,10 @@ will be there to tell them where to find the virtual environment. Reference Implementation ======================== -[Link to any existing implementation and details about its state, e.g. proof-of-concept.] +The proposed code changes to :mod:`venv` can be found at +https://github.com/brettcannon/cpython/tree/venv-location-pep . A diff showing +the changes can be seen at +https://github.com/brettcannon/cpython/compare/main...brettcannon:cpython:venv-location-pep . Rejected Ideas From c28629fabdc2a1e1b32d36849bcd9dd32a903dc8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:09:04 -0700 Subject: [PATCH 34/41] Fix the numbered list --- peps/pep-9999.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/peps/pep-9999.rst b/peps/pep-9999.rst index 8b6b5deb267..4a771fb9cf3 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-9999.rst @@ -162,30 +162,30 @@ directory. This PEP proposes some changes to the :mod:`venv` module to go along with the above recommendations: -1. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. -2. Create a +#. A ``DEFAULT_NAME: str`` global that's set to ``".venv"``. +#. Create a ``read_redirect_file(project_root: os.PathLike|str) -> Pathlib.Path[str]`` function for getting the path from a redirect file in ``project_root / DEFAULT_NAME``. -2. :cls:`venv.EnvBuilder` gains +#. :class:`venv.EnvBuilder` gains ``write_redirect_file(project_root: os.PathLike, env_dir: os.PathLike) -> None`` and an equivalent ``write_redirect_file()`` function for the module. The function and method will create a redirect file at ``project_root / DEFAULT_NAME`` that points to *env_dir*. -3. :meth:`venv.EnvBuilder.create` and :func:`venv.create` gain a keyword-only +#. :meth:`venv.EnvBuilder.create` and :func:`venv.create` gain a keyword-only ``project_root: os.PathLike | None`` parameter that will write out a :file:`.venv` file to that directory via ``EnvBuilder.write_redirect_file()``. If the value for *env_dir* ends in ``DEFAULT_NAME`` and *project_root* points to the parent directory of *env_dir* then ``write_redirect_file()`` will not be called. -4. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` and +#. The *env_dir* parameter for :meth:`venv.EnvBuilder.create` and :func:`venv.create` get a default value of ``DEFAULT_NAME``. -5. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of +#. The ``-m venv`` CLI will gain a default value for its *ENV_DIR* argument of ``DEFAULT_NAME`` (it's currently an error not to provide the argument). -6. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the +#. The ``-m venv`` CLI will gain a ``--project-root`` option that mirrors the new parameter to :meth:`venv.EnvBuilder.create`. It will be an error to use the option when multiple *ENV_DIR* arguments are provided. -7. A function named +#. A function named ``executable(dir: os.PathLike, *, traverse: bool = False) -> pathlib.Path`` will be added; it will look for a virtual environment in *dir* at ``DEFAULT_NAME`` (directory or redirect file) and return the path to the @@ -332,7 +332,6 @@ environment to use. "python_version": "...", // Optional "name": "..." // Optional }, - ... ] } From 3d206b4251a21645600327b87790f38b7d26a6f7 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:09:52 -0700 Subject: [PATCH 35/41] Take 832 --- .github/CODEOWNERS | 1 + peps/{pep-9999.rst => pep-0832.rst} | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename peps/{pep-9999.rst => pep-0832.rst} (99%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2434035af52..e3585e55f60 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -707,6 +707,7 @@ peps/pep-0828.rst @ZeroIntensity peps/pep-0829.rst @warsaw peps/pep-0830.rst @gpshead peps/pep-0831.rst @pablogsal @Fidget-Spinner @savannahostrowski +peps/pep-0832.rst @brettcannon # ... peps/pep-2026.rst @hugovk # ... diff --git a/peps/pep-9999.rst b/peps/pep-0832.rst similarity index 99% rename from peps/pep-9999.rst rename to peps/pep-0832.rst index 4a771fb9cf3..2c522f08b6e 100644 --- a/peps/pep-9999.rst +++ b/peps/pep-0832.rst @@ -1,4 +1,4 @@ -PEP: 9999 +PEP: 832 Title: Virtual environment discovery Author: Brett Cannon Discussions-To: Pending From 066fd61728fd72efad187a5fad01897b41326f6d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:11:23 -0700 Subject: [PATCH 36/41] Fix spelling and grammar --- peps/pep-0832.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index 2c522f08b6e..727fb4e6558 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -117,7 +117,7 @@ tool is expected to use that is external to the one that wrote the :file:`.venv` file (e.g. Hatch wrote the file and VS Code is going to read it). This means that a workflow tool shouldn't update the :file:`.venv` file as it runs a test suite through multiple versions of Python. But if the workflow tool -has a command to control what virtual environment is used when runnig Python, +has a command to control what virtual environment is used when running Python, then the file should be updated as necessary to match what environment the workflow tool would use (e.g. :file:`.venv` should always match what virtual environment ` ``hatch run`` `__ @@ -233,8 +233,8 @@ compatibility concern would be over some alternative use of :file:`.venv`. But due to the current usage already in the community, the likelihood of an alternative usage is probably small. This will likely lead to tools showing an error message when a ``.venv`` file is used, though. While the error message -would like be around ``.venv`` being a file and thus not explaining *why* -there's a file, it just prevent any tool overlooking the ``.venv`` file and +would likely be around ``.venv`` being a file and thus not explaining *why* +there's a file, it just prevents any tool from overlooking the ``.venv`` file and blindly creating another virtual environment. The other possible backwards compatibility concern is the new default value for @@ -315,7 +315,7 @@ JSON. For example: environments = {tool = "...", command = ["..."]} The command could output JSON that lists any and all known environments. For -flexibility the output can could more than just virtual environments, such as +flexibility, the output could include more than just virtual environments, such as global installs of Python. The output could also specify the environment to use by default if a tool doesn't have a reason or way to make a choice of which environment to use. From 11de60c19dae281dd0399c777466915f86d4b04d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:20:18 -0700 Subject: [PATCH 37/41] Style cleanup --- peps/pep-0832.rst | 53 ++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index 727fb4e6558..b4d6fe1d068 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -26,7 +26,7 @@ long-lived virtual environment is desirable (the single file case is covered by :pep:`723` and ephemeral virtual environments). As such, tools working on the user's behalf may want to create and/or use the same virtual environment. These tools could be custom scripts in the project like running the test script or -3rd-party tools like package installers. +third-party tools like package installers. Unfortunately, there's no guidance on where tools should put a virtual environment or how to find where one is ultimately put. There's somewhat of a @@ -35,14 +35,14 @@ the project in a directory named :file:`.venv`, but being a convention means it isn't consistently followed. As well, there is no mechanism to point to a virtual environment regardless of its location. -This lack of knowing where to find a virtual environment for tools causes the -developer experience to not be as smooth as it could be. If you rely on shell +This lack of guidance on where tools can find a virtual environment makes the +developer experience less smooth than it could be. If you rely on shell activation to use the proper virtual environment, then you have to make sure to do that (either manually or by configuring some automatic shell integration) as -well as to not accidentally reuse that activated shell with another project (or +well as not to accidentally reuse that activated shell with another project (or have set up shell automation to handle the deactivation). Otherwise tools need -to guess or have custom logic per tool that creates virtual environments or ask -users to manually specify where the virtual environment is. +to guess or have custom logic per tool that creates virtual environments or to +ask users to manually specify where the virtual environment is. For virtual environment creation, it leads to different instructions per project on what to do. And those instructions can be critical if scripts and @@ -77,12 +77,12 @@ Lastly, there's whether you have one virtual environment at a time or many. Having only one can minimize disk space for some tools and keeps it simple by not trying to manage multiple virtual environments. Having multiple virtual environments, though, means not having to constantly recreate virtual -environments when e.g. needing to test against multiple python versions. +environments when e.g. needing to test against multiple Python versions. This PEP takes a two-pronged approach to making virtual environments easily discoverable while supporting all aspects mentioned above. First, by default, the virtual environment for the project could be put in the :file:`.venv` -directory of the project (this can be a hardlink, symlink, etc). This name +directory of the project (this can be a hardlink, symlink, etc.). This name has been chosen due to preexisting tool support: `Poetry `__ will detect a virtual environment in such a location, @@ -100,7 +100,7 @@ and `Codeberg Pathlib.Path[str]`` + ``read_redirect_file(project_root: os.PathLike|str) -> pathlib.Path[str]`` function for getting the path from a redirect file in ``project_root / DEFAULT_NAME``. #. :class:`venv.EnvBuilder` gains @@ -196,10 +197,10 @@ above recommendations: ``DEFAULT_NAME`` as a file or directory will be done and will stop at the first ``DEFAULT_NAME`` found closest to *dir*. -In regards to committing a :file:`.venv` file to version control, it MAY be +With regard to committing a :file:`.venv` file to version control, it MAY be done when the location of the virtual environment is considered static to a project once it is set up. For instance, some projects that use tox_ have a -"dev" environment defined in their configuration that ends up at `.tox/dev`. +"dev" environment defined in their configuration that ends up at ``.tox/dev``. Setting a :file:`.venv` file to point to that virtual environment and checking in the file is reasonable. The same goes for a project that is only worked on within a container where the location of the virtual environment is controlled @@ -252,7 +253,7 @@ the path is valid before using it. Setting a :file:`.venv` file to a path that isn't a virtual environment is only a concern if the arguments the user provided to the executable were also a -concern. That then would require the user to then craft appropriate arguments +concern. That would require the user to craft appropriate arguments on top of using the malicious :file:`.venv` file. @@ -260,22 +261,22 @@ How to Teach This ================= For new users, they can be told that ``python -m venv`` creates a virtual -environment in :file:`.venv` as should any other tool that creates a virtual +environment in :file:`.venv`, and that any other tool that creates a virtual environment on their behalf. For experienced users, they should be taught the default location for a project's virtual environment is at the root of the project in :file:`.venv`. If the currently active virtual environment lives elsewhere, a :file:`.venv` -will be there to tell them where to find the virtual environment. +file will be there to tell them where to find the virtual environment. Reference Implementation ======================== The proposed code changes to :mod:`venv` can be found at -https://github.com/brettcannon/cpython/tree/venv-location-pep . A diff showing +https://github.com/brettcannon/cpython/tree/venv-location-pep. A diff showing the changes can be seen at -https://github.com/brettcannon/cpython/compare/main...brettcannon:cpython:venv-location-pep . +https://github.com/brettcannon/cpython/compare/main...brettcannon:cpython:venv-location-pep. Rejected Ideas @@ -301,11 +302,11 @@ An API for discovering environments ----------------------------------- While what the PEP currently proposes is simple, there has been some concern -that it's *too* simple. As such, there's an open concern that an API to allow +that it's *too* simple. As such, there's concern that an API to allow for broader environment discovery is necessary. A possible way to provide such an API is to introduce a ``[workflow]`` table to -:file:`pyproject.toml`. That could have an ``environments`` key which held a +:file:`pyproject.toml`. That could have an ``environments`` key that holds a table specifying how to run a discovery app to get environment details in JSON. For example: @@ -340,7 +341,7 @@ of being called. As well, it could write out a ``.venv`` file or directory if it makes sense. Having ``.venv`` checked for prior to calling the discovery tool would help avoid the overhead of calling the discovery tool. -But this does expand the complexity of this PEP. It also isn't necessary to +But this expands the complexity of this PEP. It also isn't necessary to be a part of this PEP as it could be added later on. @@ -357,7 +358,7 @@ Acknowledgements ================ Thanks to everyone who participated in an earlier discussion on this topic at -https://discuss.python.org/t/22922/ . Thanks to Cary Hawkins of Hatch, +https://discuss.python.org/t/22922/. Thanks to Cary Hawkins of Hatch, Randy Döring of Poetry, Frost Ming of PDM, Bernát Gábor of virtualenv & tox, Vinay Sajip of venv, and Zanie Blue of uv for feedback on the initial draft of this PEP. From 58cd792e51ee9ad785037904e019a30bd78db6a5 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:21:31 -0700 Subject: [PATCH 38/41] Say `read_redirect_file()` raises an exception if the location doesn't exist --- peps/pep-0832.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index b4d6fe1d068..f2ef7ab4ab9 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -167,7 +167,8 @@ above recommendations: #. Create a ``read_redirect_file(project_root: os.PathLike|str) -> pathlib.Path[str]`` function for getting the path from a redirect file in - ``project_root / DEFAULT_NAME``. + ``project_root / DEFAULT_NAME``. Raises an exception if the location + recorded in the redirect file does not exist. #. :class:`venv.EnvBuilder` gains ``write_redirect_file(project_root: os.PathLike, env_dir: os.PathLike) -> None`` and an equivalent ``write_redirect_file()`` function for the module. The From 2008b9dd3052ab0f7a683b23f9e76aa7a348d056 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:25:08 -0700 Subject: [PATCH 39/41] Add Change History section --- peps/pep-0832.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index f2ef7ab4ab9..ec75259c57f 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -364,6 +364,11 @@ Randy Döring of Poetry, Frost Ming of PDM, Bernát Gábor of virtualenv & tox, Vinay Sajip of venv, and Zanie Blue of uv for feedback on the initial draft of this PEP. +Change History +============== + +N/A + Copyright ========= From 8c5d738d2f0e14a75f1c2a855f0256504f6071d9 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:29:17 -0700 Subject: [PATCH 40/41] Make linting happy --- peps/pep-0832.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index ec75259c57f..09678e37b58 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -120,7 +120,7 @@ runs a test suite through multiple versions of Python. But if the workflow tool has a command to control what virtual environment is used when running Python, then the file should be updated as necessary to match what environment the workflow tool would use (e.g. :file:`.venv` should always match what virtual -environment ` ``hatch run`` `__ +environment `'hatch run' `__ would use). This is not expected to cause a "noisy neighbour" problem as it's not expected to change that rapidly. From c107f764f2771a76d613fd106bf1d56833cd3861 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:35:15 -0700 Subject: [PATCH 41/41] Try to fix list formatting --- peps/pep-0832.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/peps/pep-0832.rst b/peps/pep-0832.rst index 09678e37b58..cceda0a100e 100644 --- a/peps/pep-0832.rst +++ b/peps/pep-0832.rst @@ -215,15 +215,20 @@ Project Support for this PEP Speaking to various tool maintainers about this PEP: - Supports + 1. PDM (Frost Ming) 2. Poetry (Randy Döring) 3. venv (Vinay Sajip) 4. Virtualenv (Bernát Gábor) 5. Tox (Bernát Gábor) 6. Hatch (Cary Hawkins) + - Lukewarm + 1. uv (Zanie Blue) + - Opposes + 1. Hatch (Ofek Lev)