在我开始之前,关于我的环境的一些说明:通过 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 上找不到与此问题完全匹配的任何内容。我看过的东西:
- 从来没有成功回答过。
使用“pythonw”(而不是“python”)运行应用程序时找不到模块
- 问题不在于我使用的是哪个 python/pythonw,两者都来自 miniconda。
- 这与我的问题完全相反,所以用处不大。
https://github.com/ContinuumIO/anaconda-issues/issues/199
- 这表明 miniconda pythonw 有点像 hack,可能会导致各种问题,但不能直接提供解决方案(可以说强烈建议不要使用其他版本的 python)。
Python 脚本未在 crontab 中运行调用 pysaunter
- 这些导致我尝试修改环境变量。
最后说明
- 更改正在使用的 python 发行版是可能的,但非常不是理想的解决方案。我正在写一些可以在几个不同的环境(包括我还没有测试过的 Linux 和 Windows)中运行的东西,并且由不是我的人运行,所以我需要一个更安全的解决方案。
非常感谢人们可以提供的任何帮助。