如何使用 subprocess.check_call() 在 vi​​rtualenv 中 运行 `pip`?

How to run `pip` in a virtualenv with subprocess.check_call()?

我正在尝试使用 subprocess.check_call() 在不同的 Python virtualenvs 中启​​动命令。

要激活 virtualenv(以 Python 2/3 不可知的方式),我只需将路径附加到我的 virtualenv bin(或 Scripts under Windows ) 到 PATH,然后使用此修改后的环境调用 subprocess.check_call()。像这样:

environment = os.environ.copy()
environment['PATH'] = os.pathsep.join([bin_path, environment['PATH']])

subprocess.check_call("pip install -r dev_requirements.txt", env=environment)

但是,我注意到 pip 安装系统 Python 站点包中的所有内容。如果我将 check_call() 更改为:

subprocess.check_call("pip install -r dev_requirements.txt", env=environment, shell=True)

然后突然 pip 在 vi​​rtualenv 中按预期运行。

令我困扰的是,在两种情况下 运行 where pip 首先给了我通往virtualenv pip 的路径。

如何解释这种奇怪的行为?

PATH 不是 Popen() 在 Windows 上使用的 CreateProcess() 查找可执行文件的第一个位置。它可以使用与父 python.exe 进程相同的目录中的 pip.exe。 shell (cmd.exe) 使用不同的规则。参见 Popen with conflicting executable/path

避免依赖;使用 pip 的显式完整路径。在这种情况下您不需要更改环境:

import os
from subprocess import check_call

check_call([os.path.join(bin_path, 'pip.exe')] + 
           'install -r dev_requirements.txt'.split())