确定Python是否在virtualenv中运行


272

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


2
出于好奇,您为什么想知道?
豪尔赫·雷涛

1
也就是说,能够编写为您的shell生成提示的自定义脚本,并且您希望该提示指示您是否处于venv状态,因此您希望能够从该代码中检测到该提示,最好不要调用外部工具。
Marcin Orlowski

Answers:


227

AFAIK进行检查的最可靠方法(以及在virtualenv和pip内部使用的方法)是检查是否存在sys.real_prefix

import sys

if hasattr(sys, 'real_prefix'):
    #...

在virtualenv内,sys.prefix指向virtualenv目录,并sys.real_prefix指向系统Python的“真实”前缀(通常是/usr/usr/local类似的前缀)。

在virtualenv之外,sys.real_prefix不应该存在。

使用VIRTUAL_ENV环境变量不可靠。它是由virtualenv activateshell脚本设置的,但是可以通过直接从virtualenv bin/(或Scripts)目录运行可执行文件来使用virtualenv而不激活它,在这种情况下$VIRTUAL_ENV将不会设置。


11
这似乎在Python 3中不再有效。
Dan P.

49
如果您正在使用virtualenv(github.com/pypa/virtualenv),则此答案对于Python 2或Python 3同样正确。如果您正在使用pyvenv(legacy.python.org/dev/peps/pep-0405),则为 virtualenv -等效于Python 3.3+(但与virtualenv不同),然后使用sys.base_prefix代替sys.real_prefix,并且sys.base_prefix始终存在;在pyvenv之外它等于sys.prefix。
卡尔·梅耶

2
@Kounavi我认为Windows版本可能不会产生任何影响。这个答案是virtualenv在任何平台上如何工作的核心部分。您是否有可能在Windows 2012计算机上使用Python 3 pyvenv,而不是virtualenv?还是PATH发生了什么事,而您认为自己实际上并没有在virtualenv中运行?
2015年

3
bash脚本的一线工具PYTHON_ENV=$(python -c "import sys; sys.stdout.write('1') if hasattr(sys, 'real_prefix') else sys.stdout.write('0')")
Sam Myers

2
毫无疑问,这个答案已经过时了。具体来说,此答案返回常见用例的假阴性。那很糟。相反,请参阅:hroncok权威性更新正确地检测到所有非Anaconda venvs,或者Victoria Stuart权威性答案正确地检测到所有Anaconda venvs。(我对所有将这两个答案结合在一起的人都表示支持。
Cecil Curry

97

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

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


如果您已virtualenv四处走动,则可能会失败或对您说谎。如果它在说谎,你可以做find /path/to/venv/ -type f -exec sed -ie "s:/old/path/to/venv:/path/to/venv:g" {} \+。如果失败(我收到“不良元帅数据”),则需要擦除.pyc文件find /path/to/venv -type f -name "*.pyc" -exec rm {} \+(不用担心,它们会自动重建)。
jeremysprofile18年

我刚刚在Windows 10上使用Python 3.7进行了测试。它从中的默认安装...\lib\site-packages中打印出pip的位置%PATH%。因此,在这种情况下,它将返回误报。
JamesThomasMoon1979 '19

71

这是对Carl Meyer接受的答案的改进。它与适用于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_prefix与是否sys.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 

4
由于大多数Python 3框架和应用程序不再维护或支持Python 3.3,因此此功能现在简化为简单的一类代码:def is_venv(): return hasattr(sys, 'real_prefix') or sys.base_prefix != sys.prefix只是在说'。
Cecil Curry

遗憾的是,这似乎不适用于pipenv创建的虚拟环境。
dragon788

46

检查$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脚本之外进行。


1
这对于virtualenvvirtualenv和venvvirtualenv均有效。
florisla

@verboze:应该做的对吧?禁用的virtualenv表示用户脚本在其中运行。
MestreLion

这将检查是否激活了virtualenv,但这并不一定意味着正在运行的Python进程来自该virtualenv。
erb

20

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

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


8
virtualenv是可在任何Python版本(github.com/pypa/virtualenv)上运行的独立项目。链接到的PEP用于pyvenv,它基于virtualenv,但实现方式不同(更好),并且内置在Python 3.3+中。这个问题是关于virtualenv,而不是pyvenv。您是正确的,在pyvenv中没有sys.real_prefix
卡尔·梅尔

5
使用此答案从bash进行检测的一种好方法是运行: env |grep VIRTUAL_ENV |wc -l 如果在venv中返回1,否则返回0。
里斯本

3
如果您在外壳中,则可以根据需要使用[[ -n $VIRTUAL_ENV ]] && echo virtualenv或使用[[ -z $VIRTUAL_ENV ]] && echo not virtualenv
2014年

9

要检查您的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")}')

1
这是最好的跨平台(Windows / Unix)方法。
Adi Unnithan

到目前为止,这只是跨平台,python 2和python 3兼容的方式。谢谢。
RJ

9

这里有多个好的答案,而有些则不太健壮。这里是概述。

怎么不做

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

如果将它们设置为非标准位置,则并不意味着您实际上在虚拟环境中。用户可以安装多个Python版本,而这些版本并不总是位于您期望的位置。

避免看:

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

此外,不检查的情况下venv.venv或者envs在任何这些路径。对于位置更独特的环境,这将不起作用。例如, Pipenv使用哈希值作为其环境的名称。

VIRTUAL_ENV 环境变量

两者virtualenvvenv设置环境变量$VIRTUAL_ENV激活一个环境时。参见PEP 405

您可以在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"))

问题是,这仅在环境由Shell脚本激活有效activate

您可以在不激活环境的情况下启动环境的脚本,因此,如果这是一个问题,则必须使用其他方法。

sys.base_prefix

virtualenvvenv然后按预期pyvenv指向sys.prefix安装在virtualenv内部的Python。

同时,的原始sys.prefix也可作为获得sys.base_prefix

我们可以使用它来检测我们是否在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

倒退: sys.real_prefix

现在请注意,virtualenv在未设置版本20之前,而是设置了sys.base_prefixsys.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虚拟环境,请查看 Victoria Stuart的答案


OP正在询问“我如何?”,而不是“如何不?”。这个答案太过分了。它超出了问题的实质,并以太多的变化混淆了答案。请保持您的答案尽可能简单,然后直接回答问题。
Rich Lysakowski PhD

我在这里总结了多个答案,并提供了针对特定情况可能合适的建议。最初的问题没有提供足够的上下文来选择这些技术中的一种作为“最佳”技术-并不是那么简单。
florisla

1
在sys.base_prefix的部分中,测试不应该是:running_in_virtualenv = sys.*base_*prefix != sys.prefix
usonianhorizo​​n

@usonianhorizo​​n是的,谢谢!
florisla

谢谢@florisia!我正在从virtualenvwrapper过渡到用于应用程序部署的内置venv,您的解释给了我有关如何执行此操作的模板。我只依靠if hasattr(sys, 'real_prefix'):测试,该测试不再有效。
usonianhorizo​​n

8

您可以which python查看虚拟环境中是否指向该环境。


1
whichWindows默认情况下不可用。您可以where改为在Windows上使用,也可以使用whichcraft。或看看sys.executable。但是,仍然有更好的方法。
florisla

5
  • 更新于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!  :-)
>>> 

3

最简单的方法是运行:which python,如果您位于virtualenv中,它将指向其python而不是全局的python


1
我认为这实际上不能回答问题(该问题与“当前脚本”有关)。但这回答了我的特定问题:“如何从命令行确定我是否处于虚拟环境中”。
ukrutt

1

(编辑)我发现那条路,您怎么看?(它还会返回venv基本路径,甚至可以在不检查env变量的readthedocs中使用):

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

0

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

import site
site.getsitepackages()

告诉您pip软件包的安装位置。


这不能说明Python是否在虚拟环境中运行。
florisla

@florisla你能详细说明吗?如果site.getsitepackages()输出的目录不是系统目录,则可以推断出您处于虚拟环境中。
flow2k

您可以在多个位置安装Python。例如,在Windows上,您可以安装“系统” Python和WinPython发行版以及基于Conda的Python。这些都有不同的site-packages文件夹,但不一定由a创建(或使用)virtualenv
florisla

@florisla好点-我刚刚看到了这个问题(无论是否是venv)(我为另一个问题写了类似的答案)。我同意这可能无法就您是否处于静脉破裂提供肯定的答案,但可以帮助您告诉您使用的是哪个Python venv
flow2k

-1

它不是防弹的,但对于UNIX环境,简单的测试如

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

对我来说很棒。然后,它比测试某些属性的存在更简单,无论如何,您应该命名venv目录venv


-1

在Windows操作系统中,您会看到以下内容:

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

括号表示您实际上位于称为“ virtualEnvName”的虚拟环境中。


您和我都可以阅读“ virtualEnvName”。但问题是,Python模块如何读取此内容。
florisla

-1

一个可能的解决方案是:

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

就我而言,我真的只是想检测是否可以按原样安装pip物品。尽管这可能不是适用于所有情况的正确解决方案,但请考虑简单地检查一下是否对Python可执行文件的位置具有写权限。

注意:这适用于所有版本的Python,但True如果您使用来运行系统Python,也将返回sudo。这是一个潜在的用例:

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

-1

这是一个古老的问题,但是上面的例子太多了。

保持简单:(在Windows 10的Jupyter Notebook或Python 3.7.1终端中)


import sys
print(sys.executable)```

# example output: >> `C:\Anaconda3\envs\quantecon\python.exe`

OR 
```sys.base_prefix```

# Example output: >> 'C:\\Anaconda3\\envs\\quantecon'

如果您添加逻辑来检查envs该路径中是否存在,当您从anaconda移至virtualenv或时,这将停止工作pipenv
florisla

弗洛里斯拉(Florisla),在我提供在一定范围内对我有用的答案(我不在virtualenv和pipenv之间移动)近三个月后,您提供了“如何做”答案。否决他人的答案以使自己的外观更好是一项不好的运动。
Rich Lysakowski博士

丰富,对您有用的东西可能对其他人不起作用。它甚至可能不适用于原始海报。
florisla
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.