Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 832 – Virtual environment discovery

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

Table of Contents

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 .gitignore which ignores .venv
  • GitLab has a default .gitignore which ignores .venv
  • Codeberg has a default .gitignore which 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-envs
  • Add-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
    1. 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 .venv redirect files to .python-envs
    • Dropped all proposed changes to venv
  • 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