PEP 832 – Virtual environment discovery
- Author:
- Brett Cannon <brett at python.org>
- Discussions-To:
- Discourse thread
- Status:
- Draft
- Type:
- Standards Track
- Created:
- 19-Jan-2026
- Python-Version:
- 3.15
- Post-History:
- 15-Apr-2026 23-Apr-2026 31-Jul-2026
Abstract
This PEP sets out to help make the discovery of a project’s existing environments easier. By providing a default location to look for a virtual environment as already supported by most tools as well as an easy way for workflow tools to list any other environments (virtual or not), tools will have a way to find any and all existing environments for a project.
Motivation
Imagine you are on your Mac laptop and you double-click your desktop shortcut
to launch Emacs (feel free to substitute “Mac” and “Emacs” with your preferred
OS and editor, respectively). You open the directory for your project in Emacs.
Now, how is Emacs (or any other tool for that matter) supposed to know where
the environments for your project are? There’s no possible detection of an
activated virtual environment via the VIRTUAL_ENV environment variable
because you didn’t launch it from a terminal. You potentially could scan all
subdirectories for a pyvenv.cfg file to find a virtual environment, but
that assumes the virtual environments are kept locally with the project and
that there is only one of them, rather than several from which to choose.
As well, not all projects use virtual environments and may use a different
project isolation mechanism like conda environments.
What are tools like code editors, which need access to the environments being used to provide functionality like auto-complete, to do when there is currently no standardized way to tell anyone where any environments are? Currently, tools like editors have to hard-code a search algorithm for every tool that they choose to support. As well, they can document any conventions they support, but that assumes you or the tool you use to manage your environments follow those conventions, which, being conventions, are not written down anywhere.
And this is not a hypothetical issue. The author of this PEP was the dev manager for Python support in VS Code for 7 years and saw firsthand the user struggles and constant feature requests for finding one’s environments for a project.
This issue is also not restricted to code editors. Other tools have a need to access a project’s environment to know what is installed. One example is type checkers which need access to the packages that are installed to appropriately gather type annotations for 3rd-party code in order to type check the user’s code.
The goal of this PEP is to provide a specification for tools which create/manage environments a way to tell other tools where the environments for a project are. And in the case of a project which has multiple environments, this PEP is meant to allow for specifying the default environment to use so users are not forced to make a choice of environment if they do not want to make such a decision (e.g. at first launch of their code editor).
Please note this PEP neither condones nor discourages having multiple environments for a single project; it is neutral as to whether having a single environment or multiple ones is good or bad. It also does not condone one environment type over another.
Specification
This PEP does not define what the “root of a project” means, but the assumption
is that it is the directory one would open in their code editor to work on a
project’s code. This could be the directory where the project’s
pyproject.toml lives, or potentially the top directory of a monorepo.
The virtual environment for a project MAY be a path named .venv
(i.e. .venv/pyvenv.cfg will exist, which can be used to detect the
existence of a virtual environment) in the root of the project. This PEP makes
no judgment whether .venv is a physical or logical path to a directory
containing a virtual environment, nor whether logical paths should be resolved
to their physical equivalent before use.
The root of a project MAY have a .python-envs file. This file acts as a
listing of all known environments for the project (sans .venv; how that
and .python-envs work together will be covered later). The
.python-envs MUST be encoded using UTF-8. Each line of the file
represents an environment that is usable by the project and may be separated by
\n or \r\n. A trailing newline of either \n or \r\n is allowed
and MUST be ignored.
Lines in a .python-envs file MAY be paths to an environment. Paths MAY
be relative, and if they are, they MUST be relative to the
.python-envs file. IF a path is for a virtual environment, THEN the
path MUST be to the directory of the virtual environment (i.e. the directory
containing the pyvenv.cfg file). A line MAY represent any type of an
environment. Tools reading a .python-envs MAY choose what sort of
environments they support and thus MAY ignore any lines they do not
understand (although there is a specific restriction in regards to the default
environment not being supported; covered later). For environments a tool
understands but are somehow malformed (e.g. a virtual environment whose
symlinks no longer resolve), it is up to the tool to decide how to handle such
a situation. There are NO other restrictions on how environments are
represented or what type of environment is in a .python-envs file. An
empty file has NO special meaning other than representing the lack of any
environments.
Duplicate lines MAY be in the file. Listing the same environment multiple times does NOT carry any meaning. Any tool MAY remove duplicates at any point, but it MUST maintain what environment is considered the default during de-duplication.
The last environment listed in a .python-envs file MUST be considered
the default environment when a default environment is desired. IF a tool does
not support the last environment listed THEN the tool MUST either ask the user
which environment to use OR error out.
IF both a virtual environment in a .venv directory path and a
.python-envs file exist side-by-side, THEN the .venv path
MUST be implicitly considered the last line in the .python-envs file.
This also means the .venv virtual environment is considered the default
virtual environment.
With regard to committing a .python-envs file to version control, it
MAY be done when the location of the environment(s) is considered static
for 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 .python-envs 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
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.
Tools MAY use a file system locking mechanism to help guarantee no race conditions when reading or writing to a :.python-envs file.
Rationale
Explicitly supporting .venv is to codify what’s already a convention:
- Poetry will detect a virtual environment in such a location,
- PDM creates virtual environments there already
- uv creates environments there already
- Hatch can support a virtual environment there)
- VS Code
- will select it automatically, while still allowing configuration
- PyCharm
- will use it
- GitHub
has a default
.gitignorewhich ignores.venv - GitLab
has a default
.gitignorewhich ignores.venv - Codeberg
has a default
.gitignorewhich ignores.venv
But not every person or tool wants to keep an environment in the project or
even use the .venv name. In those situations, you need _some_ way
to tell other tools where to find the environments. That’s the purpose of the
.python-envs file. The file itself is hidden as it isn’t a critical
aspect of the project (environments themselves can be viewed as implementation
details). The file name was chosen to make sure it didn’t clash with any other
tool using the same name while still being self-descriptive.
The .python-envs file is specifically agnostic when it comes to what
type of environment can be represented. This helps future-proof the file for
unforeseen, future environments. As well, leaving the representation as loose
as what a single line of a file can represent helps with allowing alternative
environments that a tool may or may not support (which can include alternative
representations for virtual environments, e.g. connecting over SSH). It does
mean, though, that tools SHOULD check the line for appropriate use.
The file format is simple to allow for easy manipulation. Having a
line-delimited file format makes it easy to append a line to a
.python-envs file via the terminal, e.g.:
echo "<path>" >> .python-envsAdd-Content .python-envs "<path>"python3 -c "import sys; p=sys.argv[1]; open('.python-envs', 'a').write(p)" "<path>"
To make appending as simple a process as possible, duplicate lines are
allowed to occur in .python-envs. This alleviates having to check the
file before appending. This is also why a trailing newline is allowed in the
file.
The file format is also simple to avoid duplicating information that the
environment already contains. For instance, it has been suggested to record a
name for environments, but e.g. virtual environments have the prompt recorded
in pyvenv.cfg, so it does not need to be listed separately from the
environment where it may become stale.
This is also why the last line is the default environment: the expectation is people will be adding the environment they want to use and not simply recording an available environment. This all tries to make what is expected to be the most common action the easiest action.
Having .venv represent the last, and thus default, environment in a
.python-envs file is for practical reasons. Tools that predate this
PEP may use the .venv location, and so this is a
backwards-compatibility consideration. And if a user is using such a tool that
uses .venv, then they likely already considered that virtual environment
the default.
Project Support for this PEP
Speaking to various tool maintainers about this PEP:
Note
Any tool without a link to an expression of (no) support gave that information privately, but with permission to state publicly.
- Supports
- VS Code
Backwards Compatibility
For the virtual environment location aspect of this PEP, there is no backwards
compatibility concern as .venv is in this PEP specifically for
backwards compatibility.
As for .python-envs, that file name is not known to be in use. The
biggest backwards compatibility concern is that a tool produces it and it is
not used as expected. After that is the file not being ignored by version
control upfront.
Security Implications
Not checking the contents of a potentially malicious .python-envs file
and passing it to a shell process (e.g. subprocess.run(..., shell=True))
would be a serious security concern.
How to Teach This
For new users, they can be told that python -m venv .venv creates a virtual
environment in .venv, and that any other tool that creates a virtual
environment on their behalf can do the same.
For experienced users, they should be taught that tools may create a virtual
environment at .venv. They should also be told there may be a
.python-envs file which records the location of other environments with
the last environment listed considered the default. As well, they should be
taught that if both .venv and .python-envs exist in the same
directory then .venv is implicitly the last, and thus default,
environment in .python-envs.
Reference Implementation
As this PEP proposes no code changes, there is no reference implementation to speak of.
Rejected Ideas
.venv
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 consensus on an
alternative, a different name doesn’t fundamentally change any semantics,
existing tools seem to already support .venv, and one can still use a
different name for an environment thanks to .python-envs as proposed by
this PEP. Because the author of this PEP prefers the name,
.venv was chosen. Discussing alternative names was viewed as bikeshedding.
.python-envs
A .venv redirect file
An earlier version of this PEP allowed for .venv to act as a redirect
file to where the virtual environment is located. This was found to be too
restrictive compared to .python-envs for a couple of reasons:
- It supported only a single environment
- It was restricted to only a virtual environment
Recording what tool manages an environment
It was suggested to have .python-envs record what tool provided an
environment. The thinking was that there was the potential for orphaned
environments that still existed but were no longer valid for the project after
the user moved away from a tool or changed a configuration that wasn’t obvious
to the user.
The decision was made, though, that this was outside of the scope of this PEP
and not worth complicating .python-envs for. If a tool wanted to keep
track of what environments they created, that would be up to them to do in
their own way. As for orphaned environments that continued to exist, that would
only be a concern for the default environment as the user would need to choose
any other environment.
Using a more structured format
Using a more structured data format such as JSON for .python-envs was
suggested. Typically it was in order to record details about the environment
directly in .python-envs. But since that would be redundant data which
could be gathered from the environment itself, it was deemed not a reason to
make the file format more complicated. And the simplicity of the file format
has helped to keep the goal of the file specific and not have feature creep.
Storing the locations in pyproject.toml
It was suggested to store the locations of the environment in
pyproject.toml, but that was rejected as too rigid. Typically an
environment location is either a personal choice or a tool-specific one, not a
project one. As such, specifying the location statically didn’t seem to make
enough sense to put into the PEP, especially as a project could include its own
.python-envs file.
Using the first entry in .python-envs as the default environment
It’s a subjective choice to have the default environment be at the end of a
.python-envs file instead of at the start. The decision came down to
whether reading or writing should be preferred. The PEP chose the latter,
as its author believes that it is more important to make writing to a
.python-envs file easier, as a person is more likely to do that than
to read it (the corollary is that, since a tool is more likely to read a
.python-envs file via code, reading does not need to be optimized for a
person).
As well, the expectation is that reading even a .python-envs file with
hundreds of locations will not visibly hurt performance in any way.
Leave .python-envs out of the PEP
Some have suggested leaving .python-envs out of the PEP (or not having
this PEP at all). But during discussions around this PEP, the desire to have a
way to list the location of multiple environments no matter where they live
seemed strong enough to keep .python-envs included.
Support a file name suffix for .python-envs
There was a suggestion to allow for multiple .python-envs-like files,
differing by a file suffix. The idea was to organize what an environment was
named/for. The idea could also be extended to have the files only contain a
single environment.
In the end it didn’t seem worth the complexity. Environments would have their own way to name themselves, giving some clue as to their contents. As well, the person choosing which environment to use would not necessarily need such labels. Finally, it could lead to so many files as to be annoying.
Deferred Ideas
During the discussions for this PEP, it was suggested to be more bold and try to come up with a way to standardize how workflow tools could communicate with other tools. This would not only let workflow tools tell other tools where an environment is, but also create environments, run commands in an environment, etc. Conversations went far enough to vote on communication protocols and continue that discussion.
In the end, though, it was decided this PEP could stand on its own without such a tool-to-tool protocol which would be a massive endeavour. But the name of “workflow service protocol” – aka “WSP”, which also means “whitespace” in many parsing grammars – was at least determined and generally liked.
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, Vinay Sajip of venv, and Zanie Blue of uv for feedback on the initial draft of this PEP.
Change History
- 31-Jul-2026
- Changed from
.venvredirect files to.python-envs - Dropped all proposed changes to
venv
- Changed from
- 23-Apr-2026
- Add PyCharm and library-skills support
- Have redirect files read up to the first newline
- Clarify there is no opinion on having multiple virtual environments
- Explicitly use the code editor example for the motivation
- Have
venv.executable()be configurable for the virtual environment name - Clarify symlinks are not to be treated in any special way
- Move the Rationale after the Specification and simplify the latter by moving details to the former
- Loosened things involving “MAY”, “SHOULD”, and “NOT” so tools are not required to do anything beyond how they interpret a redirect file
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.