2

在我开始之前,关于我的环境的一些说明:通过 miniconda 安装的 python 2.7.14、macOS 10.13.3。

问题

我正在尝试analyze.py在 python 中编写一个数据处理管道(调用它),它调用几个不同的程序。其中一个程序,EMAN2使用它自己的 python 环境来运行(例如,位于~/EMAN2/bin/python)。在命令行中,对 eman2 的调用可能如下所示:

~/EMAN2/bin/e2buildstacks.py <args>

wheree2buildstacks.py使用文件顶部的标准类型公式指定它自己的 python 环境#!/Users/<username>/EMAN2/bin/python(注意,有很多这些不同的 .py 文件要运行,我只是使用一个名称作为示例)。

在 python 中,我为这些调用使用了 subprocess.Popen 构造。一个非常简单的例子是:

import subprocess
stacks_cmd = '/Users/<username>/EMAN2/bin/e2buildstacks.py <args>'
process = subprocess.Popen(stacks_cmd, shell=True, stdout=subprocess.PIPE)
stacks_output, stacks_error = process.communicate()

为简单起见,我替换了实际的参数和用户名。

如果这就是我正在做的一切,它工作正常。我可以从命令行运行python analyze.py,它运行 EMAN2 没有问题。

然而,这个管道被包裹在一个 GUI(基于 wxpython)中。所以我必须使用pythonw来运行我的程序。当我尝试这样做时:

pythonw analyze.py

它无法正确运行 EMAN2 脚本,出现错误:

Traceback (most recent call last):
  File "/Users/<username>/EMAN2/bin/e2buildstacks.py", line 34, in <module>
    from EMAN2 import *
ImportError: No module named EMAN2

这向我表明它正在使用我的 miniconda python 而不是~/EMAN2/bin/python运行脚本。

(注意:如果有人使用 EMAN2,我可以为您提供完整的参数列表和输入文件。但请放心,这不是问题,我可以从命令行运行我正在使用的命令)

我试过的

我已经尝试了几种不同的方法来解决这个问题。最简单的是指定要在命令中使用的 python:

import subprocess
stacks_cmd = '/Users/<username>/EMAN2/bin/python /Users/<username>/EMAN2/bin/e2buildstacks.py <args>'
process = subprocess.Popen(stacks_cmd, shell=True, stdout=subprocess.PIPE)
stacks_output, stacks_error = process.communicate()

那没有用,并因同样的错误而失败。

我试过在 shell=False 模式下使用 Popen

import subprocess
stacks_cmd = ['/Users/<username>/EMAN2/bin/python', '/Users/<username>/EMAN2/bin/e2buildstacks.py', <args>]
process = subprocess.Popen(stacks_cmd, shell=False, stdout=subprocess.PIPE)
stacks_output, stacks_error = process.communicate()

或者

import subprocess
stacks_cmd = ['/Users/<username>/EMAN2/bin/e2buildstacks.py', <args>]
process = subprocess.Popen(stacks_cmd, shell=False, stdout=subprocess.PIPE)
stacks_output, stacks_error = process.communicate()

两者都失败并出现相同的错误。

我试过指定可执行文件:

import subprocess
stacks_cmd = ['/Users/<username>/EMAN2/bin/e2buildstacks.py', <args>]
process = subprocess.Popen(stacks_cmd, shell=False, stdout=subprocess.PIPE, executable='/Users/<username>/EMAN2/bin/python')
stacks_output, stacks_error = process.communicate()

这给出了一个不同的错误:

Unknown option: --
usage: /Users/<username>/EMAN2/bin/e2buildstacks.py [option] ... [-c cmd | -m mod | file | -] [arg] ...
Try `python -h' for more information.

这让我认为参数没有正确传递给脚本,而是传递给 python 本身(我可能并不真正理解可执行设置在这里的作用)。

我试过设置环境变量:

import os
my_env = os.environ.copy()
my_env['PATH'] = '/Users/<username>/EMAN2/bin:'+my_env['PATH']
my_env['PYTHONPATH'] = '/Users/<username>/EMAN2/bin'

然后在上述任何命令中将其传递给 subprocess.Popen 作为env=my_env. 这失败并出现相同的错误。

在这一点上,我几乎没有想法,希望有人能提供帮助。同样,这仅发生在pythonw,而不是python

我读过的寻找解决方案的东西

我在 stackoverflow 上找不到与此问题完全匹配的任何内容。我看过的东西:

使用另一个版本的 python 对程序进行子处理

  • 从来没有成功回答过。

使用“pythonw”(而不是“python”)运行应用程序时找不到模块

  • 问题不在于我使用的是哪个 python/pythonw,两者都来自 miniconda。

Python 子进程正在运行不同版本的 Python

  • 这与我的问题完全相反,所以用处不大。

https://github.com/ContinuumIO/anaconda-issues/issues/199

  • 这表明 miniconda pythonw 有点像 hack,可能会导致各种问题,但不能直接提供解决方案(可以说强烈建议不要使用其他版本的 python)。

修改环境的 Python 子进程/Popen

Python 脚本未在 crontab 中运行调用 pysaunter

  • 这些导致我尝试修改环境变量。

最后说明

  • 更改正在使用的 python 发行版是可能的,但非常不是理想的解决方案。我正在写一些可以在几个不同的环境(包括我还没有测试过的 Linux 和 Windows)中运行的东西,并且由不是我的人运行,所以我需要一个更安全的解决方案。

非常感谢人们可以提供的任何帮助。

4

0 回答 0