如何告诉POpen使用/设置某些环境变量?

时间:2019-07-09 21:00:19

标签: python django python-3.x environment-variables popen

我正在使用Python 3.7和Django。我使用下面的命令运行通常会在外壳中运行的命令...

out = Popen([settings.SELENIUM_RUNNER_CMD, file_path], stderr=STDOUT, stdout=PIPE)
t = out.communicate()[0], out.returncode

他死于错误

b'env: node: No such file or directory\n'

我要弄清楚的是如何让我的Python环境访问我可以访问的普通环境变量,或者想出一种在运行Python命令之前设置它们的方法。通常,当我自己检查时很容易找到“节点”

davea$ which node
/usr/local/bin/node

但是我不知道如何告诉Python使用我可以访问的相同路径。

2 个答案:

答案 0 :(得分:4)

如果我们引用Popen's documentation,我们可以看到三个相关的参数:

  1. cwd str或类似path的对象,这是当前的工作目录
  2. env映射(比方说dict),这就是传递给被调用程序的环境映射
  3. shell标志,无论是否将程序包装在外壳中

让我们查看每种解决方案。


如果负担得起,只需使用cwd="where is node",例如,如果node位于/usr/local/bin中,则可以使用cwd=/usr/local/bincwd=os.path.join(USR_LOCAL, 'bin')例。但是,所有内容都将在此文件夹中创建,而这可能不是您想要的(日志,当前工作目录上的假设)。


现在,针对环境:

  

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

您可以通过os.environ复制当前环境,并在PATH中添加如下内容:

new_env = os.environ.copy()
new_env['PATH'] = '{}:/usr/local/bin'.format(new_env['PATH'])

然后通过此new_env映射,您就可以了!


如果您真的想依赖shell,可以,但是这里是平台详细信息:

POSIX平台

  

在shell = True的POSIX上,shell默认为/ bin / sh。如果args是字符串,则该字符串指定要通过外壳执行的命令。这意味着字符串的格式必须与在shell提示符下键入时的格式完全相同。例如,这包括在文件名中使用引号或反斜杠转义。如果args是序列,则第一项指定命令字符串,任何其他项都将被视为shell本身的其他参数。也就是说,Popen等效于:Popen(['/bin/sh', '-c', args[0], args[1], ...])

Windows平台

  

在shell = True的Windows上,COMSPEC环境变量指定默认的shell。在Windows上唯一需要指定shell = True的时间是将要执行的命令内置到shell中(例如dir或copy)。您不需要shell = True即可运行批处理文件或基于控制台的可执行文件。

您可以使用PATH=whatever之类的东西并直接使用整个shell,但是要注意的是:安全注意事项


奖金解决方案

只需在调用Python进程之前重新定义PATH。如果您使用的是Django,则可以使用:

  1. 开发服务器
  2. 生产级服务器

在两种情况下,您要做的就是重新定义父进程的环境,对于Gunicorn这样的生产级服务器来说,这是可能的,并且有文档可以做到。对于开发服务器,请在您自己的外壳程序级别上进行操作(但请注意!您可能不得不记录这种行为,或者告诉任何使用您的软件的人,您假设node处于……大多数情况下公平)。

答案 1 :(得分:0)

os.environ.copy()最适合您的需求。

import subprocess, os
my_env = os.environ.copy()
out = Popen([settings.SELENIUM_RUNNER_CMD, file_path], stderr=STDOUT, stdout=PIPE, env=my_env)
t = out.communicate()[0], out.returncode

就应该了!