Skip to main content
 首页 » 编程设计

python之如何让 ipython RichIPythonWidget 在 pyinstaller 环境中使用 pyside

2025年05月04日59daizhj

我有一个使用 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 开发版测试的