使用带有 mayavi 导入的 pyinstaller 创建独立的 exe

creating standalone exe using pyinstaller with mayavi import

我有一个程序可以通过绘制表面和点云来查看它们与表面的关系,从而帮助以 3D 形式可视化某些数据。对于可视化,我使用的是 mayavi,因为它易于设置并且比 3D 中的 matplotlib 做得更好。当我 运行 在我的 python 环境中使用该程序并生成漂亮的可视化效果时,该程序运行良好。但是,我需要将它分发给一些没有 Python 并且不想在每台计算机上安装 python 和所有加载项的人,所以我一直在使用 pyinstaller创建独立的 .exe 文件,在我开发程序后它们可以 运行。

作为参考,这一切都是在 Windows 10、Python 3.6、pyqt 4.11.4、pyface 6.0.0、traits 4.6.0、pyinstaller 3.3.1、mayavi 4.5 上完成的。 0+vtk81。我使用的几乎每个模块都是使用 pip 安装的。

问题是,如果我 use/import mayavi 模块,我似乎无法获得可运行的 exe。我已经阅读了很多关于不同挂钩文件和隐藏导入的 github 文档,每次我修复一个错误时都会弹出另一个错误。这一切都是从 scipy 开始的,但我相信我已经解决了这些问题。所以我有几个问题可以帮助我解决问题:

1) 是否有人使用带有 mayavi 导入的 pyinstaller 成功创建了独立的 exe(特别是 from mayavi import mlab)?你的秘密是什么?!?

这看起来很相似,但我还没弄清楚...SO_link

我已经使用以下链接 (scipy,h5py,pandas,traits/qt4,ETS_TOOLKIT) 添加隐藏的导入或修复其他问题,但在设置 ETS_TOOLKIT=qt4 后我现在卡住了。在设置它之前,我会得到一个 pyface/traits 错误 RuntimeError: No traitsui.toolkits plugin found for toolkit null,但现在它对 qt4 说同样的事情而不是 null。我安装了 qt4,所以我不明白...它在 pyface/base_toolkit.py.

中的 import_toolkit 函数中

2) 在 3D 可视化/exe 创建方面是否有更好的途径?我需要一个 3D 程序,如果点在表面前面或后面,它可以准确渲染,并且能够 rotate/zoom/pan 交互,而且它需要直观。 Mayavi 具有类似于 matplotlib 的非常简单的命令,但围绕 UI 如何与一切交互,其他命令似乎非常复杂。

3) 如何解释我收到的所有这些错误代码?他们通常很含糊地说某一行抛出了一个嵌套在其他 10 个函数调用中的异常,而且似乎很难找出到底哪里出错了,尤其是当 Google 上没有弹出任何似乎相关的内容时。

编辑

虽然我仍然很困惑,但我已经能够更改发生错误的位置。在回溯之后,我在 traitsui/editors/code_editor.py(第 49 行)中注释掉了设置标记颜色的一行,此时异常然后在下次调用 Color 方法时开始......但我仍然得到相同的结果运行时错误。所以这并没有告诉我太多,除了我还在寻找我需要包含什么隐藏的导入来让这个东西工作。

另请注意,我在使用 PyInstaller 和 cx_Freeze 时遇到了完全相同的错误,以防万一...

编辑 2

我现在已经在 python 2.7 中使用 anaconda 进行了尝试,同样的问题......我开始相信宇宙不希望这种情况发生。还有其他地方我应该提出这个问题吗?我已经在 traitsui GitHub 上发帖,但这不是很有帮助。这似乎比 pyinstaller/cx_freeze 大,因为它发生在两个....

我处理了同样的问题,最后切换到 cx_freeze,现在在 linux 和 windows 上工作正常。您正在处理的问题来自您发现的 SE answer 中的语句,即动态导入语句,其中导入的内容仅在运行时确定:

    be = 'pyface.ui.%s.' % tk
    __import__(be + 'init')

我无法在 pyinstaller 中修复该问题,而在 cx_freeze 中,当您在构建文件中明确添加所需的包时,它可以正常工作。这是我使用的包列表:

"packages": ["pyface.ui.qt4", "tvtk.vtk_module", "tvtk.pyface.ui.wx", "matplotlib.backends.backend_qt4",'pkg_resources._vendor','pkg_resources.extern','pygments.lexers',
                              'tvtk.pyface.ui.qt4','pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore','numpy','matplotlib','mayavi']

这是一个完整的构建脚本,适用于 python3.6、cx_freeze 5.0.2、mayavi 4.5.0+vtk71、traits 4.6.0、pyface 5.1.0 和 traitsui 5.1 .0。

import os
from cx_Freeze import setup, Executable
import cx_Freeze.hooks
def hack(finder, module):
    return
cx_Freeze.hooks.load_matplotlib = hack
import scipy
import matplotlib

scipy_path = os.path.dirname(scipy.__file__) #use this if you are also using scipy in your application

build_exe_options = {"packages": ["pyface.ui.qt4", "tvtk.vtk_module", "tvtk.pyface.ui.wx", "matplotlib.backends.backend_qt4",'pygments.lexers',
                                  'tvtk.pyface.ui.qt4','pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore','numpy','matplotlib','mayavi'],
                     "include_files": [(str(scipy_path), "scipy"), #for scipy
                    (matplotlib.get_data_path(), "mpl-data"),],
                     "includes":['PyQt4.QtCore','PyQt4.QtGui','mayavi','PyQt4'],
                     'excludes':'Tkinter',
                    "namespace_packages": ['mayavi']
                    }


executables = [
    Executable('main.py', targetName="main.exe",base = 'Win32GUI',)
]

setup(name='main',
      version='1.0',
      description='',
      options = {"build_exe": build_exe_options},
      executables=executables,
      )

我是这样导入pyface的:

os.environ['ETS_TOOLKIT'] = 'qt4'

import imp
try:
    imp.find_module('PySide') # test if PySide if available
except ImportError:
    os.environ['QT_API'] = 'pyqt' # signal to pyface that PyQt4 should be used

from pyface.qt import QtGui, QtCore

导入 mayavi 之前