运行脚本时自动加载虚拟环境
我有一个Python脚本,它需要从一个虚拟环境中获取一些依赖。 我在想有没有办法把这个虚拟环境添加到我的路径中,让它自动启动虚拟环境,然后运行脚本,最后再返回到系统的Python。
我尝试过使用autoenv和.env
,但似乎并不能完全满足我的需求。我还考虑过改变脚本的开头部分,让它指向虚拟环境的路径,但这样做感觉不太稳妥。
7 个回答
这有帮助吗?
import site
site.addsitedir('/path/to/virtualenv/lib/python2.7/site-packages/')
我觉得这里最好的办法是创建一个简单的脚本,并把它安装到你的虚拟环境里。这样你可以直接使用这个脚本,或者创建一个符号链接,随你喜欢。
这里有个例子:
$ 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 install
或 setup.py develop
来安装你的脚本时,它会把 scripts
的第一行替换成一个指向你虚拟环境中 Python 的“shebang”行(你可以通过 $ head /path/to/my/env/bin/crunchy-frog
来验证)。所以每次你运行这个特定的脚本时,它都会使用那个特定的 Python 虚拟环境。
来自虚拟环境的文档:
如果你直接从虚拟环境的 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
时,自然就不知道虚拟环境里的内容了。
我很惊讶还没有人提到这一点,但这就是为什么在虚拟环境的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')
有两种方法可以做到这一点:
在脚本的第一行写上虚拟环境的Python路径。就像这样:
#!/your/virtual/env/path/bin/python
把虚拟环境的目录添加到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的值复制到上面的代码片段中。