确定 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
、.venv
或envs
。
对于具有更独特位置的环境,这将中断。例如,
Pipenv 使用哈希值作为其环境的名称。
VIRTUAL_ENV
环境变量
virtualenv
和venv
在激活环境时都设置环境变量$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
virtualenv
、venv
和 pyvenv
指向安装在 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_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
【讨论】:
由于大多数 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?
php 是不是有相当于 python 的 virtualenv 或 ruby 的沙箱?
python virtualenv,包括所有全部 python 模块
20200221_python虚拟环境在Windows下安装配置_virtualenv不是内部或外部命令也不是可运行的程序或批处理文件