我有一个使用 pyinstaller 构建的应用程序,它使用 PySide 作为其 Qt Gui。我通过嵌入 ipython qtconsole 包含了一个交互式提示。 这会破坏由 pyinstaller 创建的构建。
这是一个最小的(非)工作示例:
from PySide.QtGui import *
from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.qt.inprocess import QtInProcessKernelManager
from IPython.lib import guisupport
class IPythonWidget(RichIPythonWidget):
def __init__(self, parent=None, **kwargs):
super(self.__class__, self).__init__(parent)
self.app = app = guisupport.get_app_qt4()
self.kernel_manager = kernel_manager = QtInProcessKernelManager()
kernel_manager.start_kernel()
self.kernel = kernel = kernel_manager.kernel
kernel.gui = 'qt4'
self.kernel_client = kernel_client = kernel_manager.client()
kernel_client.start_channels()
if __name__ == '__main__':
app = QApplication([])
i = IPythonWidget()
i.show()
app.exec_()
当直接从源代码(python mwe.py)运行时,它会弹出一个 ipython qt 控制台窗口。 当我将它与 pyinstaller 捆绑在一个目录中并运行 exe 时,我得到了这个:
Traceback (most recent call last):
File "<string>", line 3, in <module>
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyi_importers.py", line 270, in load_module
exec(bytecode, module.__dict__)
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\IPython.qt.console.rich_ipython_widget", line 8, in <module>
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyi_importers.py", line 270, in load_module
exec(bytecode, module.__dict__)
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\IPython.external.qt", line 23, in <module>
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\IPython.external.qt_loaders", line 296, in load_qt
ImportError:
Could not load requested Qt binding. Please ensure that
PyQt4 >= 4.7, PyQt5 or PySide >= 1.0.3 is available,
and only one is imported per session.
Currently-imported Qt library: 'pyqtv1'
PyQt4 installed: False
PyQt5 installed: False
PySide >= 1.0.3 installed: False
Tried to load: ['pyside', 'pyqt', 'pyqt5']
当我构建一个可执行文件 (pyinstaller -F mwe.py) 并运行它时,我得到了这个:
WARNING: file already exists but should not: C:\Users\SARNOW4\AppData\Local\Temp\_MEI62362\Include\pyconfig.h
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyi_importers.py", line 270, in load_module
exec(bytecode, module.__dict__)
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\PySide", line 41, in <module>
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\PySide", line 11, in _setupQtDirectories
File "H:\Home\pydd2swid\build\mwe\out00-PYZ.pyz\PySide._utils", line 93, in get_pyside_dir
File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyi_importers.py", line 409, in load_module
module = imp.load_module(fullname, fp, filename, self._c_ext_tuple)
RuntimeError: the sip module has already registered a module called PyQt4.QtCore
似乎 pyinstaller Hook 导入机制的方式不适用于 ipython qt_loaders。我该如何解决这个问题?
我在 Windows 7 上使用 pyinstaller 2.1、ipython 3.0、python 2.7(32 位)。
请您参考如下方法:
您可以通过两种方式修复它:
1) 覆盖IPython.external.qt_loaders中包含的函数load_qt,例如:
def load_qt(api_options):
from PySide import QtCore, QtGui, QtSvg
return QtCore, QtGui, QtSvg, 'pyside'
因此,您将强制选择 PySide 模块。
2) 另一种不覆盖已安装的 IPython 模块的解决方案是在导入 IPython 小部件之前将函数作为引用传递,例如
def new_load_qt(api_options):
from PySide import QtCore, QtGui, QtSvg
return QtCore, QtGui, QtSvg, 'pyside'
from IPython.external import qt_loaders
qt_loaders.load_qt = new_load_qt
from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
现在它应该可以工作了。
它是使用 PyInstaller 开发版测试的
