Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

What happens if I activate a python venv inside another venv?

+2
−1

What happens if I do

python3 -m venv venv1
python3 -m venv venv2
source venv1/bin/activate
source venv2/bin/activate

Which venv(s) am I now in?

History

1 comment thread

downvote reason (4 comments)

1 answer

+2
−0

tl;dr

The second one; and deactivating it does not revert to the first.

Understanding virtual environment activation

Being "in" a virtual environment is just an illusion created by setting a few environment variables. Doing that is platform-specific, and therefore the scripts are as well.

But as a general description, the activation scripts provided by ordinary virtual environments (as created using python -m venv etc.) will:

  1. Ensure that a deactivate command is available (the plain Windows CMD version provides a separate deactivate.bat; others, including Powershell, define a new command)

  2. Remember the "base" settings of the environment variables it changes (this involves deactivating any currently active virtual environment!), so that deactivate can undo changes (it remembers them in additional, undocumented environment variables)

  3. Set VIRTUAL_ENV_PROMPT to be the name of the environment's root folder (this is pre-computed when the environment is created)

  4. Set VIRTUAL_ENV to be the path to the environment's root folder (this is pre-computed when the environment is created)

  5. Add VIRTUAL_ENV to the start of PATH

  6. Unset PYTHONHOME (a mechanism for telling the Python interpreter a different place to look for standard library files; this would prevent the virtual environment's Python from starting up correctly)

  7. Unless disabled (by the user setting VIRTUAL_ENV_DISABLE_PROMPT), modify the prompt (typically by setting PS1)

The scripts are designed so that the activation does not "nest" — activating a second virtual environment implicitly deactivates the first, and so deactivating after that returns to the original situation with no active virtual environment. This is simpler to implement (otherwise the scripts would need to remember a stack of previous environment variable values, and there is often limited space for these) and was apparently considered simpler to understand and just as useful.

Going without

Python itself doesn't actually care about this activation process, and in particular it doesn't check the VIRTUAL_ENV environment variable.

It detects and uses virtual environments by a completely different mechanism:

  1. If PYTHONHOME is set, that overrides everything else — Python will set sys.prefix and sys.base_prefix to that value, and skip the rest of this process.

  2. If there is a config file called pyvenv.cfg either adjacent to the Python executable or in the parent folder, and that file passes some basic validation, it's used to set sys.base_prefix (according to a pre-calculated value stored in the config file when the environment is created) and sys.prefix (to the directory containing the config file).

  3. Otherwise, Python walks the directory tree backwards from its own location, looking for what it expects for the standard library (specifically, a lib folder containing os.py).

Each virtual environment has its own Python executable: on Windows, this is a stub that redirects to the original Python, while Linux can just use a symbolic link (Python will be able to search starting from the link's path rather than the resolved path to the base Python).

Once sys.prefix and sys.base_prefix are determined (by the above process), Python can import the standard library site module and use it to finish configuring sys.path (in particular, adding a site-packages folder either from the virtual environment or from within the Python installation).

As a consequence, in general it is not necessary to activate virtual environments in order to use them[1].

The main idea behind activation is that it modifies your PATH, so that the python command uses the environment's Python, which causes the environment's installed libraries to be used. But you can equally well just specify that Python directly.

For example:

$ python -m venv example-venv
$ # The wrapper inside the virtual environment runs, which will
$ # use the virtual environment's Python, and therefore install
$ # in that environment:
$ example-venv/bin/pip install package-installation-test
$ # Which may also provide more wrappers, accessed similarly:
$ example-venv/bin/demo-example-package
$ # Explicitly running the virtual environment's Python allows
$ # access to what's installed there:
$ example-venv/bin/python -m example_package

(I created the package-installation-test package some time ago, specifically to do these sorts of diagnostics.)


  1. Unless you have, for example, a shell script that cares about the VIRTUAL_ENV value, or a script that does something like subprocess.call(['python', '-c', 'pass']) — which should be using sys.executable instead of relying on path lookup. ↩︎

History

0 comment threads

Sign up to answer this question »