开发者

Determine if Python is running inside virtualenv

Is it possible to 开发者_运维知识库determine if the current script is running inside a virtualenv environment?


The most reliable way to check for this is to check whether sys.prefix == sys.base_prefix. If they are equal, you are not in a virtual environment; if they are unequal, you are. Inside a virtual environment, sys.prefix points to the virtual environment, and sys.base_prefix is the prefix of the system Python the virtualenv was created from.

The above always works for Python 3 stdlib venv and for recent virtualenv (since version 20). Older versions of virtualenv used sys.real_prefix instead of sys.base_prefix (and sys.real_prefix did not exist outside a virtual environment), and in Python 3.3 and earlier sys.base_prefix did not ever exist. So a fully robust check that handles all of these cases could look like this:

import sys

def get_base_prefix_compat():
    """Get base/real prefix, or sys.prefix if there is none."""
    return getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix

def in_virtualenv():
    return get_base_prefix_compat() != sys.prefix

If you only care about supported Python versions and latest virtualenv, you can replace get_base_prefix_compat() with simply sys.base_prefix.

Using the VIRTUAL_ENV environment variable is not reliable. It is set by the virtualenv activate shell script, but a virtualenv can be used without activation by directly running an executable from the virtualenv's bin/ (or Scripts) directory, in which case $VIRTUAL_ENV will not be set. Or a non-virtualenv Python binary can be executed directly while a virtualenv is activated in the shell, in which case $VIRTUAL_ENV may be set in a Python process that is not actually running in that virtualenv.


Try using pip -V (notice capital V)

If you are running the virtual env. it'll show the path to the env.'s location.


This is an improvement of the accepted answer by Carl Meyer. It works with virtualenv for Python 3 and 2 and also for the venv module in Python 3:

import sys


def is_venv():
    return (hasattr(sys, 'real_prefix') or
            (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))

The check for sys.real_prefix covers virtualenv, the equality of non-empty sys.base_prefix with sys.prefix covers venv.

Consider a script that uses the function like this:

if is_venv():
    print('inside virtualenv or venv')
else:
    print('outside virtualenv or venv')

And the following invocation:

$ python2 test.py 
outside virtualenv or venv

$ python3 test.py 
outside virtualenv or venv

$ python2 -m virtualenv virtualenv2
...
$ . virtualenv2/bin/activate
(virtualenv2) $ python test.py 
inside virtualenv or venv
(virtualenv2) $ deactivate

$ python3 -m virtualenv virtualenv3
...
$ . virtualenv3/bin/activate
(virtualenv3) $ python test.py 
inside virtualenv or venv
(virtualenv3) $ deactivate 

$ python3 -m venv venv3
$ . venv3/bin/activate
(venv3) $ python test.py 
inside virtualenv or venv
(venv3) $ deactivate 


Check the $VIRTUAL_ENV environment variable.

The $VIRTUAL_ENV environment variable contains the virtual environment's directory when in an active virtual environment.

>>> import os
>>> os.environ['VIRTUAL_ENV']
'/some/path/project/venv'

Once you run deactivate / leave the virtual environment, the $VIRTUAL_ENV variable will be cleared/empty. Python will raise a KeyError because the environment variable was unset.

>>> import os
>>> os.environ['VIRTUAL_ENV']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/os.py", line 678, in __getitem__
    raise KeyError(key) from None
KeyError: 'VIRTUAL_ENV'

These same environment variable checks can of course also be done outside of the Python script, in the shell.


There are multiple good answers here, and some less robust ones. Here's an overview.

How not to do it

Do not rely on on the location of Python or the site-packages folder.

If these are set to non-standard locations, that does not mean you're actually in a virtual environment. Users can have more than one Python version installed, and those are not always where you expect them to be.

Avoid looking at:

  • sys.executable
  • sys.prefix
  • pip -V
  • which python

Also, do not check for the presence of venv, .venv or envs in any of these paths. This will break for environments with a more unique location. For example, Pipenv uses hash values as the name for its environments.

VIRTUAL_ENV environment variable

Both virtualenv and venv set the environment variable $VIRTUAL_ENV when activating an environment. See PEP 405.

You can read out this variable in shell scripts, or use this Python code to determine if it's set.

import os
running_in_virtualenv = "VIRTUAL_ENV" in os.environ

# alternative ways to write this, also supporting the case where
# the variable is set but contains an empty string to indicate
# 'not in a virtual environment':
running_in_virtualenv = bool(os.environ.get("VIRTUAL_ENV"))
running_in_virtualenv = bool(os.getenv("VIRTUAL_ENV"))

The problem is, this only works when the environment is activated by the activate shell script.

You can start the environment's scripts without activating the environment, so if that is a concern, you have to use a different method.

sys.base_prefix

virtualenv, venv and pyvenv point sys.prefix to the Python installed inside of the virtualenv as you would expect.

At the same time, the original value of sys.prefix is also made available as sys.base_prefix.

We can use that to detect if we're in a virtualenv.

import sys
# note: Python versions before 3.3 don't have sys.base_prefix
# if you're not in virtual environment
running_in_virtualenv = sys.prefix != sys.base_prefix

Fallback: sys.real_prefix

Now watch out, virtualenv before version 20 did not set sys.base_prefix but it set sys.real_prefix instead.

So to be safe, check both as suggested in hroncok's answer:

import sys

real_prefix = getattr(sys, "real_prefix", None)
base_prefix = getattr(sys, "base_prefix", sys.prefix)

running_in_virtualenv = (base_prefix or real_prefix) != sys.prefix

Anaconda

If you're using Anaconda virtual environments, check Victoria Stuart's answer.


According to the virtualenv pep at http://www.python.org/dev/peps/pep-0405/#specification you can just use sys.prefix instead os.environ['VIRTUAL_ENV'].

the sys.real_prefix does not exist in my virtualenv and same with sys.base_prefix.


To check whether your inside Virtualenv:

import os

if os.getenv('VIRTUAL_ENV'):
    print('Using Virtualenv')
else:
    print('Not using Virtualenv')

You can also get more data on your environment:

import sys
import os

print(f'Python Executable: {sys.executable}')
print(f'Python Version: {sys.version}')
print(f'Virtualenv: {os.getenv("VIRTUAL_ENV")}')


You can do which python and see if its pointing to the one in virtual env.


  • Updated Nov 2019 (appended).

I routinely use several Anaconda-installed virtual environments (venv). This code snippet/examples enables you to determine whether or not you are in a venv (or your system environment), and to also require a specific venv for your script.

Add to Python script (code snippet):

# ----------------------------------------------------------------------------
# Want script to run in Python 3.5 (has required installed OpenCV, imutils, ... packages):
import os

# First, see if we are in a conda venv { py27: Python 2.7 | py35: Python 3.5 | tf: TensorFlow | thee : Theano }
try:
   os.environ["CONDA_DEFAULT_ENV"]
except KeyError:
   print("\tPlease set the py35 { p3 | Python 3.5 } environment!\n")
   exit()

# If we are in a conda venv, require the p3 venv:
if os.environ['CONDA_DEFAULT_ENV'] != "py35":
    print("\tPlease set the py35 { p3 | Python 3.5 } environment!\n")
    exit()

# See also:
# Python: Determine if running inside virtualenv
# http://stackoverflow.com/questions/1871549/python-determine-if-running-inside-virtualenv  
# [ ... SNIP! ... ]

Example:

$ p2
  [Anaconda Python 2.7 venv (source activate py27)]

(py27) $ python  webcam_.py
    Please set the py35 { p3 | Python 3.5 } environment!

(py27) $ p3
  [Anaconda Python 3.5 venv (source activate py35)]

(py35) $ python  webcam.py -n50

    current env: py35
    processing (live): found 2 faces and 4 eyes in this frame
    threaded OpenCV implementation
    num_frames: 50
    webcam -- approx. FPS: 18.59
    Found 2 faces and 4 eyes!
(py35) $

Update 1 -- use in bash scripts:

You can also use this approach in bash scripts (e.g., those that must run in a specific virtual environment). Example (added to bash script):

if [ $CONDA_DEFAULT_ENV ]        ## << note the spaces (important in BASH)!
    then
        printf 'venv: operating in tf-env, proceed ...'
    else
        printf 'Note: must run this script in tf-env venv'
        exit
fi

Update 2 [Nov 2019]

  • For simplicity, I like Matt's answer (https://stackoverflow.com/a/51245168/1904943).

Since my original post I've moved on from Anaconda venv (and Python itself has evolved viz-a-viz virtual environments).

Reexamining this issue, here is some updated Python code that you can insert to test that you are operating in a specific Python virtual environment (venv).

import os, re
try:
    if re.search('py37', os.environ['VIRTUAL_ENV']):
        pass
except KeyError:
    print("\n\tPlease set the Python3 venv [alias: p3]!\n")
    exit()

Here is some explanatory code.

[victoria@victoria ~]$ date; python --version
  Thu 14 Nov 2019 11:27:02 AM PST
  Python 3.8.0

[victoria@victoria ~]$ python
  Python 3.8.0 (default, Oct 23 2019, 18:51:26) 
  [GCC 9.2.0] on linux
  Type "help", "copyright", "credits" or "license" for more information.

>>> import os, re

>>> re.search('py37', os.environ['VIRTUAL_ENV'])
<re.Match object; span=(20, 24), match='py37'>

>>> try:
...     if re.search('py37', os.environ['VIRTUAL_ENV']):
...       print('\n\tOperating in Python3 venv, please proceed!  :-)')
... except KeyError:
...     print("\n\tPlease set the Python3 venv [alias: p3]!\n")
... 

    Please set the Python3 venv [alias: p3]!

>>> [Ctrl-d]
  now exiting EditableBufferInteractiveConsole...

[victoria@victoria ~]$ p3
  [Python 3.7 venv (source activate py37)]

(py37) [victoria@victoria ~]$ python --version
  Python 3.8.0

(py37) [victoria@victoria ~]$ env | grep -i virtual
  VIRTUAL_ENV=/home/victoria/venv/py37

(py37) [victoria@victoria ~]$ python
  Python 3.8.0 (default, Oct 23 2019, 18:51:26) 
  [GCC 9.2.0] on linux
  Type "help", "copyright", "credits" or "license" for more information.

>>> import os, re
>>> try:
...     if re.search('py37', os.environ['VIRTUAL_ENV']):
...       print('\n\tOperating in Python3 venv, please proceed!  :-)')
... except KeyError:
...     print("\n\tPlease set the Python3 venv [alias: p3]!\n")
... 

    Operating in Python3 venv, please proceed!  :-)
>>> 


Easiest way is to just run: which python, if you are in a virtualenv it will point to its python instead of the global one


(edited) I found that way, what do you think of it ? (it also returns the venv base path and works even for readthedocs where checking the env variable does not):

import os
import sys
from distutils.sysconfig import get_config_vars


def get_venv_basedir():
    """Returns the base directory of the virtualenv, useful to read configuration and plugins"""

    exec_prefix = get_config_vars()['exec_prefix']

    if hasattr(sys, 'real_prefix') is False or exec_prefix.startswith(sys.real_prefix):
        raise EnvironmentError('You must be in a virtual environment')

    return os.path.abspath(get_config_vars()['exec_prefix'] + '/../')


In windows OS you see something like this:

C:\Users\yourusername\virtualEnvName\Scripts>activate
(virtualEnvName) C:\Users\yourusername\virtualEnvName\Scripts>

Parentheses mean that you are actually in the virtual environment called "virtualEnvName".


There are a lot of great methods posted here already, but just adding one more:

import site
site.getsitepackages()

tells you where pip installed the packages.


It's not bullet-proof but for UNIX environments simple test like

if run("which python3").find("venv") == -1:
    # something when not executed from venv

works great for me. It's simpler then testing existing of some attribute and, anyway, you should name your venv directory venv.


A potential solution is:

os.access(sys.executable, os.W_OK)

In my case I really just wanted to detect if I could install items with pip as is. While it might not be the right solution for all cases, consider simply checking if you have write permissions for the location of the Python executable.

Note: this works in all versions of Python, but also returns True if you run the system Python with sudo. Here's a potential use case:

import os, sys
can_install_pip_packages = os.access(sys.executable, os.W_OK)

if can_install_pip_packages:
    import pip
    pip.main(['install', 'mypackage'])
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜