运行脚本时自动加载虚拟环境

29 投票
7 回答
29885 浏览
提问于 2025-04-18 06:39

我有一个Python脚本,它需要从一个虚拟环境中获取一些依赖。 我在想有没有办法把这个虚拟环境添加到我的路径中,让它自动启动虚拟环境,然后运行脚本,最后再返回到系统的Python。

我尝试过使用autoenv和.env,但似乎并不能完全满足我的需求。我还考虑过改变脚本的开头部分,让它指向虚拟环境的路径,但这样做感觉不太稳妥。

7 个回答

-1

这有帮助吗?

import site
site.addsitedir('/path/to/virtualenv/lib/python2.7/site-packages/')
2

我觉得这里最好的办法是创建一个简单的脚本,并把它安装到你的虚拟环境里。这样你可以直接使用这个脚本,或者创建一个符号链接,随你喜欢。

这里有个例子:

$ mkdir my-tool
$ cd my-tool
$ mkdir scripts
$ touch setup.py
$ mkdir scripts
$ touch scripts/crunchy-frog
$ chmod +x scripts/crunchy-frog

crunchy-frog

#!/usr/bin/env python
print("Constable Parrot ate one of those!")

setup.py

from setuptools import setup

setup(name="my-cool-tool",
      scripts=['scripts/crunchy-frog'],
      )

现在:

$ source /path/to/my/env/bin/activate
(env) $ python setup.py develop 
(env) $ deactivate
$ cd ~
$ ln -s /path/to/my/env/bin/crunchy-frog crunchy-frog
$ ./crunchy-frog
Constable Parrot ate one of those!

当你通过 setup.py installsetup.py develop 来安装你的脚本时,它会把 scripts 的第一行替换成一个指向你虚拟环境中 Python 的“shebang”行(你可以通过 $ head /path/to/my/env/bin/crunchy-frog 来验证)。所以每次你运行这个特定的脚本时,它都会使用那个特定的 Python 虚拟环境。

9

来自虚拟环境的文档

如果你直接从虚拟环境的 bin/ 目录运行一个脚本或者 Python 解释器(比如 path/to/env/bin/pip 或者 /path/to/env/bin/python script.py),就不需要激活虚拟环境。

所以,如果你直接调用虚拟环境里的 Python 可执行文件,你的虚拟环境就会“处于激活状态”。你可以像这样创建一个脚本:

#!/bin/bash

PATH_TO_MY_VENV=/opt/django/ev_scraper/venv/bin

$PATH_TO_MY_VENV/python -c 'import sys; print(sys.version_info)'
python -c 'import sys; print(sys.version_info)'

当我在我的系统上运行这个脚本时,两个调用 Python 的地方会打印出你看到的内容。(Python 3.2.3 在我的虚拟环境里,而 2.7.3 是我系统里的 Python。)

sys.version_info(major=3, minor=2, micro=3, releaselevel='final', serial=0)
sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0)

所以,当你调用 $PATH_TO_MY_VENV/python 时,你在虚拟环境中安装的所有库都会可用。而调用你系统里的普通 python 时,自然就不知道虚拟环境里的内容了。

13

我很惊讶还没有人提到这一点,但这就是为什么在虚拟环境的bin目录下会有一个叫做 activate_this.py 的文件。你可以把它传给 execfile(),这样就可以改变当前运行的解释器的模块搜索路径。

# doing execfile() on this file will alter the current interpreter's
# environment so you can import libraries in the virtualenv
activate_this_file = "/path/to/virtualenv/bin/activate_this.py"

execfile(activate_this_file, dict(__file__=activate_this_file))

你可以把这个文件放在你脚本的最上面,这样就可以强制脚本始终在那个虚拟环境中运行。与修改哈希邦不同,你可以通过使用相对路径来做到这一点:

script_directory = os.path.dirname(os.path.abspath(__file__))
activate_this_file = os.path.join(script_directory, '../../relative/path/to/env/bin/activate_this.py')
25

有两种方法可以做到这一点:

  1. 在脚本的第一行写上虚拟环境的Python路径。就像这样:

    #!/your/virtual/env/path/bin/python

  2. 把虚拟环境的目录添加到sys.path中。注意,你需要先导入sys库。就像这样:

    import sys

    sys.path.append('/path/to/virtual/env/lib')

如果你选择第二种方法,可能需要把多个路径添加到sys.path中(比如site等)。获取这些路径的最好方法是运行你的虚拟环境的Python解释器,然后找出sys.path的值。就像这样:

/your/virtual/env/bin/python

Python blah blah blah

> import sys
> print sys.path
[ 'blah', 'blah' , 'blah' ]

把sys.path的值复制到上面的代码片段中。

撰写回答