我有一个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环境中运行该命令?
我检查了几个类似的问题:
third-party-tool
不是Python脚本(我相信它是bash)。从子进程的文档:
https://docs.python.org/3/library/subprocess.html
接受的args是
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运行,它读取env默认值)应该可以做到这一点。
subprocess.run(['bash', '--login', '-c', '/full/path/to/third-party-tool', '-arg1'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={})
感谢您的帮助,nullUser;您的解决方案是对我的问题的简明而正确的答案。
但是,当我试用它时,我的第三方工具现在因其他一些(未知)原因而失败。可能还有一些其他的环境变量,我不知道它会因为新shell而迷失。幸运的是,我找到了一个替代解决方案,我将与其他任何人共同努力。
据我所知,进入虚拟环境对环境的唯一区别是为PATH变量添加一个新路径,并添加变量VIRTUAL_ENV。
我可以通过创建环境的副本来复制外部 - 虚拟环境行为,其中我:
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环境变量列表)
我使用我最喜欢的diff工具并比较输出。 within_venv_from_python.txt
与without_venv.txt
相同,这是一个好兆头(在这两种情况下,third-party-tool
运行相同的环境变量,并表明它不在矩阵中)。实施此解决方案后,我的实际第三方工具似乎正在运行。