不需要虚拟环境的Python调用子进程

时间:2019-04-18 05:00:36

标签: python subprocess virtual environment

我有一个Python 3.6脚本,该脚本使用子过程调出第三方工具。

main_script.py:

#!/usr/bin/env python
import subprocess
result = subprocess.run(['third-party-tool', '-arg1'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

问题在于,main_script.py必须在虚拟环境中运行,third-party-tool必须不在任何虚拟环境中运行。

我对third-party-tool知之甚少,除了它在我的路上。当我在虚拟环境中处于活动状态时调用它会导致它阻塞并随后引发异常。我不知道它是否使用默认的python二进制文件,或者它启动了自己的虚拟环境并在其中进行了处理。它不是Python脚本,但显然以某种方式调用了它。

如何告诉子进程退出虚拟环境并在默认的shell环境中运行命令?

我已经研究了几个类似的问题:

2 个答案:

答案 0 :(得分:1)

来自子流程的文档:

https://docs.python.org/3/library/subprocess.html

可接受的参数是

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
    capture_output=False, shell=False, cwd=None, timeout=None, check=False,
    encoding=None, errors=None, text=None, env=None, universal_newlines=None)

尤其是

  

如果env不为None,则它必须是为新进程定义环境变量的映射。这些是用来代替继承当前流程环境的默认行为的。它直接传递给Popen。

因此,传递空字典env={}(从空环境开始)并使用bash --login(作为登录shell运行,读取环境默认值)应该可以解决问题。

subprocess.run(['bash', '--login', '-c', '/full/path/to/third-party-tool', '-arg1'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={})

答案 1 :(得分:0)

感谢您的帮助,nullUser;您的解决方案是对我的问题的简洁而正确的答案。

但是,当我尝试使用该工具时,我的第三方工具现在由于其他(未知)原因而失败。可能还有其他我不知道的其他环境变量,因为新的shell会使其丢失。幸运的是,我找到了一个替代解决方案,可以与其他苦苦挣扎的人分享。

我的解决方案

据我所知,进入虚拟环境与环境的唯一区别是在PATH变量中添加了新路径,并添加了VIRTUAL_ENV变量。

我可以通过创建以下环境的副本来复制外部虚拟环境的行为:

  • 删除该VIRTUAL_ENV环境变量,然后
  • 从PATH中删除python前缀。

示例

my_script.py

my_script.py实施我的解决方案:

#!/usr/bin/env python
import subprocess, os, sys

env = os.environ.copy()
if hasattr(sys,'real_prefix'):
    # If in virtual environment, gotta forge a copy of the environment, where we:
    # Delete the VIRTUAL_ENV variable.
    del(env['VIRTUAL_ENV'])

    # Delete the "/home/me/.python_venv/main/bin:" from the front of my PATH variable.
    orig_path = env['PATH']
    virtual_env_prefix = sys.prefix + '/bin:'
    env['PATH'] = orig_path.replace(virtual_env_prefix, '')

# Pass the environment into the third party tool, modified if and when required.
subprocess.run(['./third-party-tool'], shell=False, env=env)

第三方工具

third-party-tool被模拟为脚本,可以告诉您它是否在虚拟环境中并打印出环境变量。在此示例中,third-party-tool是Python脚本,但通常可能不是。

#!/usr/bin/env python
# third-party-tool
import sys, os
in_venv = hasattr(sys, 'real_prefix')
print('This is third-party Tool and you {} in a virtual environment.'.format("ARE" if in_venv else "ARE NOT"))
os.system('env')

测试

现在,我尝试从外部虚拟环境,内部虚拟环境以及虚拟环境中的python脚本调用第三方工具,以捕获输出。

[me@host ~]$ ./third-party-tool > without_venv.txt
# Now I activate virtual environment
(main) [me@host ~]$ ./third-party-tool > within_venv.txt
(main) [me@host ~]$ ./my_script.py > within_venv_from_python.txt

注意:输出看起来像这样:     这是第三方工具,您不在虚拟环境中。     (继续列出KEY = VALUE环境变量的列表)

我使用我最喜欢的差异工具并比较输出。 within_venv_from_python.txtwithout_venv.txt相同,这是一个好兆头(在两种情况下,third-party-tool都使用相同的环境变量运行,并指示它不在矩阵中)。实施此解决方案后,我实际的第三方工具似乎正在工作。