如何让ipythons RichIPythonWidget在pyinstaller环境中使用pyside?

时间:2015-04-14 09:17:00

标签: python ipython pyside pyinstaller

我有一个使用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挂钩导入机制的方式不适用于ipythons qt_loaders。我该如何解决这个问题? 我在Windows 7上使用pyinstaller 2.1,ipython 3.0,python 2.7(32位)。

1 个答案:

答案 0 :(得分:5)

您可以通过两种方式解决问题:

1)覆盖 IPython.external.qt_loaders 中包含的 load_qt 功能,例如:

public void getUserInformation (View view)//This is the function used to call getInformation.
{
    USER_EMAIL = (EditText)findViewById(R.id.signin_emailbox);
    USER_PASS = (EditText)findViewById(R.id.signin_passwordbox);
    Toast.makeText(getBaseContext(),"Please wait...",Toast.LENGTH_LONG).show();
    email = USER_EMAIL.getText().toString();
    userpass = USER_PASS.getText().toString();
    if(email != null && userpass != null)
    {
        Toast.makeText(getBaseContext(),"Data collected", Toast.LENGTH_LONG).show();
        DatabaseOperations dop = new DatabaseOperations(CTX);
        Cursor CR = dop.getInformation(dop);

    }

    else
        Toast.makeText(getBaseContext(),"Sorry, no email or password was collected",Toast.LENGTH_LONG).show();

所以,你将强制选择PySide模块。

2)另一个没有覆盖安装的IPython模块的解决方案是在导入IPython小部件之前将该函数作为参考传递,例如。

def load_qt(api_options):
    from PySide import QtCore, QtGui, QtSvg
    return QtCore, QtGui, QtSvg, 'pyside'

现在它应该工作了。

使用 PyInstaller Develop Version

进行测试