I have an application that i build using pyinstaller, and it uses PySide for its Qt Gui. I included an interactive prompt by embedding an ipython qtconsole. This breaks the builds created by pyinstaller.
Here is a minimal (non-)working example:
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_()
When run directly from source (python mwe.py), it pops up an ipython qt console window. When i bundle this with pyinstaller in one directory and run the exe, i get this:
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']
and when i build a single executable (pyinstaller -F mwe.py) and run it, i get this:
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
It seems that the way pyinstaller hooks the import mechanism does not work with ipythons qt_loaders. How can i fix this?
I am using pyinstaller 2.1, ipython 3.0, python 2.7 (32-bit) on Windows 7.
You can fix it in two ways:
1) Overwrite the function load_qt included in IPython.external.qt_loaders, e.g.:
so, you will force to choose the PySide Module.
2) Another solution without overwriting the IPython Module installed, would be passing the function as reference before importing the IPython widget, e.g.
Now it should work.
It was tested using the PyInstaller Develop Version