确定Python是否在virtualenv中运行

是否有可能确定当前脚本是否在virtualenv环境中运行?

278142 次浏览

最可靠的检查方法是检查sys.prefix == sys.base_prefix是否。如果它们相等,则不是在虚拟环境中;如果它们不相等,你就是。在虚拟环境中,sys.prefix指向虚拟环境,而sys.base_prefix是创建virtualenv的系统Python的前缀。

上述方法对于Python 3 stdlib venv和最近的virtualenv(自版本20起)始终有效。旧版本的virtualenv使用sys.real_prefix而不是sys.base_prefix(并且sys.real_prefix在虚拟环境之外不存在),并且在Python 3.3和更早的版本中,sys.base_prefix从未存在过。所以一个完全健壮的检查可以处理所有这些情况,看起来像这样:

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

如果你只关心支持的Python版本和最新的virtualenv,你可以简单地用sys.base_prefix替换get_base_prefix_compat()

使用VIRTUAL_ENV环境变量不可靠。它是由virtualenv activate shell脚本设置的,但是virtualenv可以在不激活的情况下使用,直接从virtualenv的bin/(或Scripts)目录运行可执行文件,在这种情况下,$VIRTUAL_ENV将不会被设置。或者,当在shell中激活virtualenv时,可以直接执行非virtualenv的Python二进制文件,在这种情况下,$VIRTUAL_ENV可能会在实际上没有在该virtualenv中运行的Python进程中设置。

根据http://www.python.org/dev/peps/pep-0405/#specification的virtualenv pep,你可以直接使用sys.prefix来代替os.environ['VIRTUAL_ENV']

sys.real_prefix在我的virtualenv中不存在,与sys.base_prefix相同。

检查环境变量$VIRTUAL_ENV

在活动的虚拟环境中,$VIRTUAL_ENV环境变量包含虚拟环境的目录。

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

一旦你运行deactivate /离开虚拟环境,$VIRTUAL_ENV变量将被清除/空。Python将引发KeyError,因为环境变量未设置。

>>> 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'

当然,这些相同的环境变量检查也可以在Python脚本之外的shell中完成。

尝试使用pip -V(注意大写V)

如果您正在运行虚拟环境。它会显示通往环境的路径。的位置。

  • 2019年11月更新(附后)。

我经常使用几个安装了anaconda的虚拟环境(venv)。这个代码片段/示例使您能够确定是否处于venv(或您的系统环境)中,并且还为您的脚本需要特定的venv。

添加到Python脚本(代码片段):

# ----------------------------------------------------------------------------
# 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! ... ]

例子:

$ 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) $

更新1——在bash脚本中使用:

您还可以在bash脚本中使用这种方法(例如,必须在特定的虚拟环境中运行的脚本)。示例(添加到bash脚本):

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

更新2[2019年11月]

从我最初的帖子开始,我已经从Anaconda venv (Python本身已经进化了viz-a-viz虚拟环境)转移到其他地方。

重新检查这个问题,这里有一些更新的Python代码,您可以插入它们来测试您是否在特定的Python虚拟环境(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()

下面是一些解释性代码。

[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!  :-)
>>>

它不是万无一失的,但是对于UNIX环境的简单测试,比如

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

对我来说很好。这比测试某些属性的存在要简单得多,无论如何,你应该将你的venv目录命名为venv

这是对卡尔迈耶的公认答案的改进。它适用于Python 3和2中的virtualenv,也适用于Python 3中的venv模块:

import sys




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

sys.real_prefix的检查覆盖了virtualenv,非空的sys.base_prefixsys.prefix的相等性覆盖了venv。

考虑一个像这样使用函数的脚本:

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

以及下面的调用:

$ 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

在windows操作系统中,你会看到这样的东西:

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

括号表示您实际处于名为“virtualEnvName”的虚拟环境中。

(编辑)我是这样发现的,你怎么看?(它还返回venv基本路径,甚至适用于readthedocs,其中检查env变量无效):

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'] + '/../')

潜在的的解决方案是:

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

在我的例子中,我真的只是想检测我是否可以用pip原样安装项目。虽然这可能不是所有情况下的正确解决方案,但请考虑简单地检查您是否具有Python可执行文件位置的写权限。

注意:在所有版本的Python中都有效,但如果使用sudo运行系统Python,也会返回True。下面是一个潜在的用例:

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'])

检查你的Virtualenv内部:

import os


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

您还可以获得有关您的环境的更多数据:

import sys
import os


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

你可以执行which python,看看它是否指向虚拟环境中的那个。

最简单的方法是运行:which python,如果你在一个virtualenv中,它将指向它的python而不是全局的

这里已经发布了很多很棒的方法,但只需要再添加一个:

import site
site.getsitepackages()

告诉你pip安装包的位置。

这里有很多好的答案,也有一些不太可靠的答案。

如何不这样做

不要依赖于Python的位置或site-packages文件夹。

如果这些被设置为非标准位置,则意味着 你实际上是在一个虚拟的环境中。用户可以拥有多个

. Python版本,而这些并不总是在你期望的位置

避免看:

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

同样,不要检查在这些路径中是否存在venv.venvenvs。 这将打破具有更独特位置的环境。例如, Pipenv使用哈希值作为其环境的名称

VIRTUAL_ENV环境变量

virtualenvvenv在激活环境时设置环境变量$VIRTUAL_ENV。 看到PEP 405。< / p >

您可以在shell脚本中读取该变量,或者使用此Python代码来确定是否设置了该变量。

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"))

问题是,这只适用于环境是激活activate shell脚本。

你可以启动环境的脚本没有激活环境,所以如果这是一个问题,你必须使用不同的方法。

sys.base_prefix

virtualenvvenvpyvenvsys.prefix指向安装在virtualenv内部的Python。

同时,sys.prefix原始值也可用作sys.base_prefix

我们可以用它来检测我们是否在虚拟环境中。

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

回退:sys.real_prefix

现在注意,版本20之前的virtualenv没有设置sys.base_prefix,而是设置了sys.real_prefix

所以为了安全起见,请按照hroncok的回答中的建议检查两者:

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虚拟环境,检查 维多利亚·斯图尔特的回答 . < / p >