如何在virtualenv中设置环境变量

19

如果我有一个激活虚拟环境的 Python 脚本,就像这样:

#!/path/to/venv/bin/python
如何在不修改此脚本的情况下设置变量?
我希望这个环境变量对使用这个虚拟环境的所有脚本都有效。
这意味着修改此脚本不是解决方案,因为有二十个脚本,我不想修改二十个脚本。
编写一个围绕Python脚本的shell包装器脚本可以解决问题,但我想避免这样做。
过去,我认为可以使用自定义sitecustomize.py作为启动代码。但Ubuntu(据我所知是唯一这样做的发行版)附带了其自己的sitecustomize.py文件,结果我的sitecustomize.py不会被调用。参见https://bugs.launchpad.net/ubuntu/+source/python2.5/+bug/197219 以下是我想使用虚拟环境的一些方式:
- 通过Unix cron执行的脚本。 - systemd服务中的虚拟环境。请参阅:如何在systemd服务单元中启用虚拟环境? - 通过mod_wsgi(Apache):https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html#daemon-mode-single-application (我再次考虑了一下。我想设置变量不是Python或虚拟环境的工作。我需要一种统一的方法来设置环境变量。在我的情况下,我希望这样做而不使用shell包装器)。

2
这个有关吗?:https://dev59.com/eGkw5IYBdhLWcg3w8O6o - OliverRadini
1
激活脚本(在虚拟环境的bin目录中)用于激活虚拟环境,可能是设置环境变量的一个可能位置。所有Python脚本都应该继承这些变量,但从维护的角度来看,这可能不是一个很好的选择,因为如果您设置了一个新的虚拟环境,您将不得不记住再次修改激活脚本。 - Abhinav Upadhyay
1
@OliverRadini,你提到的问题不适用。据我所知,这些问题通过在执行Python解释器之前设置环境变量的(shell)脚本来解决。在我的问题中,解释器是这样调用的:“#!/path/to/venv/bin/python”,我无法编写包装的shell脚本。 - guettli
啊,我明白了,谢谢;对于混淆感到抱歉。我会暂时保留我的评论,以防有人想要更多关于什么不会解决问题的信息。 - OliverRadini
如果我有一个像这样激活虚拟环境的Python脚本:只是选择Python二进制文件,那么venv并没有被“激活”。激活venv主要是通过bin/activate shell脚本更新您的PATH变量,但这不是使用Python二进制文件的必要条件。 - Martijn Pieters
显示剩余2条评论
5个回答

38

在编写sitecustomize.py文件并更改bin/python都是可行的解决方法,但我建议另一种不需要直接更改虚拟环境中内容的方法,只需安装一个.pth文件:

./venv/lib/python2.7/site-packages/_set_envs.pth

带有内容:

import os; os.environ['FOO'] = 'bar'

测试:

$ ./venv/bin/python -c "import os; print os.getenv('FOO')"
bar

“诀窍是,Python会在启动时加载每个.pth文件(链接1),如果有一行以import开头,这行代码将被执行,从而允许注入任意代码。”
“优点是,您可以编写一个Python包,使用setuptools 安装此.pth文件,并将其安装到您想要更改的虚拟环境中。”

1
这种方法在Ubuntu中也不起作用。此外,Python 2.x已经过时。您可以使用导入site模块site.USER_SITE获得此路径。 - Rutrus

4
从我试过的情况来看,如果在虚拟环境中创建一个sitecustomize.py文件,它将优先于全局/usr/lib/python2.7目录下安装的sitecustomize.py文件。以下是我的操作步骤:
在虚拟环境中创建一个sitecustomize.py文件。
$ echo "import os; os.environ['FOO'] = 'BAR'" > ~/venvs/env_test/lib/python2.7/sitecustomize.py

确保在从虚拟环境运行Python二进制文件时,它被导入和执行。

$ ~/venvs/env_test/bin/python
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sitecustomize
>>> sitecustomize.__file__
'/home/abhinav/venvs/env_test/lib/python2.7/sitecustomize.py'
>>> import os
>>> os.environ['FOO']
'BAR'
>>>

只需验证即使没有显式导入 sitecustomize ,也已设置 FOO

$ ~/venvs/env_test/bin/python
Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ['FOO']
'BAR'
>>>

这在我的Ubuntu 20.04.2 LTS上使用Python 3.8.5无法工作,因为ENABLE_USER_SITE被设置为False。 - Rutrus

3

在尝试了dotenv包和.pth方法后,我发现它们对我不起作用。因此,我只需修改venv/bin/activate脚本,并在那里导出变量。

这是我的想法。

$ cat venv/bin/activate

deactivate () {
    unset FOO
    unset BAR
    ...
}

...

export FOO='xxx'
export BAR='xxx'

1

有点hackish,但应该可行。

  1. 将虚拟环境bin中的python链接重命名为python.lnk之类的名称
  2. bin文件夹中创建一个看起来像这样的文件python

    #!/bin/sh
    export TEST='It works!'
    "$0.lnk" "$@"
  3. 使其可执行

    chmod +x python

然后,如果您运行以下脚本:

#!/work/venv/bin/python
import os

print 'Virtualenv variable TEST="{}"'.format(os.environ['TEST'])

如下所示:

./myscript.py

它将打印:

Virtualenv variable TEST="It works!"


这是正确的答案。只有这种方式可以调整他的Python shebang,这才是他问题的真正原因。 - Rutrus

0

如何在Ubuntu上操作

Ubuntu的问题似乎是Python包带有PYTHONNOUSERSITE作为cPython编译标志。您可以在site module中找到它,并查看site.ENABLE_USER_SITE是否设置为False。

问题的具体情况

简而言之#!/path/to/venv/bin/python不足以执行您的虚拟环境。

尽管其他答案在某些情况下似乎是正确的,但问题在于他强制使用#!/path/to/venv/bin/python进行执行,但他在问题中没有提供任何上下文虚拟环境,因此我认为他在运行脚本之前没有激活他的虚拟环境。

这是无用的,因为该命令通常链接到您的系统Python可执行文件[^1]并不做任何更多的事情。此外,默认情况下,如果您没有使用source /path/to/venv/bin/activate激活虚拟环境或配置Apache或Nginx来管理您的venv,则将使用系统环境变量。

解决方案:在venv中设置环境变量

然后,可以在您的venv/bin/activate脚本中添加一行特定的代码,以Bash语言添加环境值:

export FOO=BAR

然后使用source命令激活它。


[^1]: 可能你会更喜欢一个通用的 #!/usr/bin/env python3 (python2 已经被弃用)。这个环境将会正确地处理你的可执行文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接