确定 Python 是不是在 virtualenv 中运行

Posted

技术标签:

【中文标题】确定 Python 是不是在 virtualenv 中运行【英文标题】:Determine if Python is running inside virtualenv确定 Python 是否在 virtualenv 中运行 【发布时间】:2010-12-24 16:48:28 【问题描述】:

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

【问题讨论】:

出于好奇,您为什么想知道? 即能够编写为您的 shell 生成提示的自定义脚本,并且您希望该提示指示您是否在 venv 中,因此您希望能够从该代码中检测到它,最好不调用外部工具。 接受的答案对我不起作用(2020,Ubuntu 18.04 上的 python3.6.9)这个答案有效:***.com/a/42580137/1296044 保持简单:(在 Windows 10 上的 Jupyter Notebook 或 Python 3.7.1 终端中)import sys print(sys.executable) # 示例输出:>> C:\Anaconda3\envs\quantecon\python.exe OR sys.base_prefix # 示例输出:>> 'C :\\Anaconda3\\envs\\quantecon' 一个潜在的节省时间的人会问为什么你需要了解python是如何运行的。与其在事后试图弄清楚 python 是如何运行的,不如通过了解 如何 python 将在它发生之前被调用来解决你的问题,那么解决方案就会变得简单且更加通用。在这种情况下,它就变成了 MrHetii 的简单答案:***.com/a/28388115/881411。即,如果您控制调用 python,并且您可以在调用之前通过 shell 检查$VIRTUAL_ENV 的存在,那么您将知道 python 是否会在 venv 中运行。 【参考方案1】:

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

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

【讨论】:

virtualenv 是适用于任何 Python 版本 (github.com/pypa/virtualenv) 的独立项目。您链接到的 PEP 用于 pyvenv,它基于 virtualenv,但实现方式不同(更好)并且内置于 Python 3.3+。这个问题是关于 virtualenv,而不是 pyvenv。你是对的,在 pyvenv 中没有 sys.real_prefix 使用此答案从 bash 中检测的一种好方法是运行:env |grep VIRTUAL_ENV |wc -l 如果在 venv 中则返回 1,否则返回 0。 如果您在 shell 中,您可以根据需要简单地使用 [[ -n $VIRTUAL_ENV ]] && echo virtualenv[[ -z $VIRTUAL_ENV ]] && echo not virtualenv【参考方案2】:

最可靠的检查方法是检查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,您可以将get_base_prefix_compat() 替换为简单的sys.base_prefix

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

【讨论】:

如果您使用的是 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。 我已经在 Windows 8/8.1 版本中成功使用它来辨别程序是否在 virtualenv 中运行,但在 Windows Server 2012 R2 上,无论程序是否在 virtualenv 中运行,它都会返回 False 或不是! :( @Kounavi 我认为 Windows 版本可能不会产生任何影响。这个答案是 virtualenv 如何在任何平台上工作的核心部分。您是否有可能在 Windows 2012 机器上使用 Python 3 pyvenv,而不是 virtualenv?或者当你认为你在虚拟环境中运行时,PATH 发生了一些事情,而你实际上并没有在 virtualenv 中运行? 单行 bash 脚本 PYTHON_ENV=$(python -c "import sys; sys.stdout.write('1') if hasattr(sys, 'real_prefix') else sys.stdout.write('0')") 这个答案已经过时了,不足为奇。具体来说,此答案会返回常见用例的误报。那很糟。相反,请参阅:hroncok 的 authoritative update correctly detecting all non-Anaconda venvs 或 Victoria Stuart 的 authoritative answer correctly detecting all Anaconda venvs。 (我对结合这两个答案的人表示赞同。【参考方案3】:

这里有多个好的答案,还有一些不太可靠的答案。 这是一个概述。

如何不这样做

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

如果这些设置为非标准位置,那 不是 的意思 你实际上是在一个虚拟环境中。用户可以拥有多个 已安装 Python 版本,但并不总是在您期望的位置。

避免看:

sys.executable sys.prefix pip -V which python

另外,不要检查任何这些路径中是否存在venv.venvenvs。 对于具有更独特位置的环境,这将中断。例如, 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"))

问题是,这仅在环境被activate shell 脚本激活时才有效。

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

sys.base_prefix

virtualenvvenvpyvenv 指向安装在 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

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

为了安全起见,请按照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 虚拟环境,请检查 Victoria Stuart's answer.

【讨论】:

OP 是在问“我该怎么做?”,而不是“如何不做?”这个答案太过分了。它超出了问题的精神,并以太多的变化混淆了答案。请让您的答案尽可能简单,直接回答问题。 我在这里总结了多个答案,并就特定情况下可能适合的答案提供建议。最初的问题没有提供足够的上下文来选择这些技术中的一种作为“最佳”技术——它并不是那么简单。 在 sys.base_prefix 部分,测试不应该是:running_in_virtualenv = sys.*base_*prefix != sys.prefix 谢谢你,@florisia!我正在从 virtualenvwrapper 过渡到内置 venv 以进行应用程序部署,您的解释为我提供了如何执行此操作的模板。我一直只依赖if hasattr(sys, 'real_prefix'): 测试,它不再起作用了。 我理解关于“不”做什么的反对意见。一个简单的编辑是从最佳答案开始,然后说明为什么其他方法不可接受。然而,最后,这为我提供了最好、正确的细节。【参考方案4】: 2019 年 11 月更新(附加)。

我经常使用几个安装 Anaconda 的虚拟环境 (venv)。此代码 sn-p/examples 使您能够确定您是否处于 venv(或您的系统环境)中,并且还需要为您的脚本提供特定的 venv。

添加到 Python 脚本(代码 sn-p):

# ----------------------------------------------------------------------------
# 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://***.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 月]

为简单起见,我喜欢马特的回答 (https://***.com/a/51245168/1904943)。

自从我发表最初的帖子以来,我已经从 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!  :-)
>>> 

【讨论】:

【参考方案5】:

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

import site
site.getsitepackages()

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

【讨论】:

这并不能说明 Python 是否在虚拟环境中运行。 @florisla 你能详细说明一下吗?如果site.getsitepackages() 输出的目录不是系统目录,那么您可以推断您处于虚拟环境中。 您可以在多个位置安装 Python。例如,在 Windows 上,您可以安装“系统”Python 和 WinPython 发行版以及基于 Conda 的 Python。这些都有不同的站点包文件夹,但不一定由virtualenv 创建(或用于)。 @florisla 好点——我刚刚看到这个(venv 与否)是问题所要问的(我为另一个问题写了一个类似的答案)。我同意这可能无法确定您是否在 venv 中,但可以帮助您告诉您正在使用哪个 Python 或哪个 venv【参考方案6】:

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

【讨论】:

我认为这实际上并不能回答问题(这是关于“当前脚本”的问题)。然而,这回答了我的特定问题,“我如何从命令行确定我是否处于虚拟环境中。”【参考方案7】:

检查$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 中完成。

【讨论】:

这适用于virtualenv virtualenv 和venv virtualenv。 @verboze:正如它应该做的那样,对吧?停用的 virtualenv 意味着用户脚本没有在其中运行。 这会检查 virtualenv 是否被激活,但这并不一定意味着运行的 Python 进程来自该 virtualenv。 这个答案可能在两个方向上都是错误的。 Python 进程可以通过直接执行 virtualenv 的 Python 二进制文件(或以该二进制文件作为 shebang 的脚本)在虚拟环境中运行,而无需使用 shell “激活” virtualenv。在这种情况下,这个答案将给出假阴性。或者,即使在 shell 中激活了 virtualenv,也可以直接执行 non-virtualenv Python 二进制文件或脚本,而这个答案会给出误报。 它对于边缘用例可能很有用,例如,如果您想在从另一种语言运行 Python 代码之前测试 virtualenv 是否已激活。在我的例子中,我的 Node 服务器在这里和那里产生 Python 服务,我想在运行 Jest 测试之前检查虚拟环境是否被激活。【参考方案8】:

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

【讨论】:

which 在 Windows 上默认不可用。您可以在 Windows 上使用where,或者使用whichcraft。或查看sys.executable。但是,仍然有更好的方法。【参考方案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")')

【讨论】:

这是最好的跨平台(Windows/Unix)方法。 到目前为止,这只是跨平台,python 2和python 3兼容的方式。谢谢。【参考方案10】:

一个潜在的解决方案是:

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

【讨论】:

【参考方案11】:

这是对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_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 

【讨论】:

由于大多数 Python 3 框架和应用程序不再维护或支持 Python 3.3,这个函数现在简化为一个简单的单行:def is_venv(): return hasattr(sys, 'real_prefix') or sys.base_prefix != sys.prefix只是说说而已。 遗憾的是,这似乎不适用于 pipenv 创建的虚拟环境。【参考方案12】:

(已编辑)我是这样发现的,你怎么看? (它还返回 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'] + '/../')

【讨论】:

【参考方案13】:

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

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

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

【讨论】:

你和我可以很好地阅读“virtualEnvName”。但问题是,Python 模块如何读取这个。【参考方案14】:

这不是万无一失的,但对于 UNIX 环境来说是简单的测试,例如

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

非常适合我。它比测试某些属性的存在更简单,无论如何,您应该将您的 venv 目录命名为venv

【讨论】:

【参考方案15】:

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

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

【讨论】:

如果您经常移动您的virtualenv,这可能会失败或欺骗您。如果是在撒谎,你可以find /path/to/venv/ -type f -exec sed -ie "s:/old/path/to/venv:/path/to/venv:g" \+。如果它失败了(我得到了“错误的编组数据”),你需要用 find /path/to/venv -type f -name "*.pyc" -exec rm \+ 擦除 .pyc 文件(别担心,它们会自动重建)。 我刚刚在 Windows 10 上使用 Python 3.7 进行了测试。它从%PATH% 中的默认安装...\lib\site-packages 打印pip 的位置。所以在这种情况下它会返回一个误报。 在带有 pip 21.0.1 的 Ubuntu 18 上,pip -V 如果不在 venv 中,则返回用户安装 pip 的路径。因此,这并不能告诉您是否激活了 venv。 如果您使用的是 ZSH 并且您将提示配置为显示其他内容,这可能不起作用 如果您在环境中,则可以在 Windows 10 上运行。

以上是关于确定 Python 是不是在 virtualenv 中运行的主要内容,如果未能解决你的问题,请参考以下文章

Julia 中是不是存在类似 Python 的 virtualenv?

知识分享 Python三大神器之Virtualenv

php 是不是有相当于 python 的 virtualenv 或 ruby​​ 的沙箱?

在vim中设置python virtualenv

python virtualenv,包括所有全部 python 模块

20200221_python虚拟环境在Windows下安装配置_virtualenv不是内部或外部命令也不是可运行的程序或批处理文件