Calling `sip.setapi` does not work if app has already imported from PyQt4 #276

Closed
Sharpie opened this Issue Feb 20, 2011 · 4 comments

4 participants

@Sharpie

Take the following example for a minimal Qt shell:

#!/usr/bin/env python
import sys

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QMainWindow, QApplication

from IPython.frontend.qt.kernelmanager import QtKernelManager
from IPython.frontend.qt.console.ipython_widget import IPythonWidget


class MainWin(QMainWindow):
  def __init__(self):
    QMainWindow.__init__(self)
    self.resize(1000,1000)

    self.kernel = QtKernelManager()
    self.kernel.start_kernel()
    self.kernel.start_channels()

    self.console = IPythonWidget()
    self.console.kernel_manager = self.kernel

    self.setCentralWidget(self.console)

def main():
    app = QApplication(sys.argv)

    main_win = MainWin()
    main_win.show()
    main_win.activateWindow()

    app.exec_()

if __name__ == '__main__':
    main()

Trying to run this fails with the following error:

Traceback (most recent call last):
  File "./console_test.py", line 7, in <module>
    from IPython.frontend.qt.kernelmanager import QtKernelManager
  File "/usr/local/lib/python2.7/site-packages/IPython/frontend/qt/kernelmanager.py", line 5, in <module>
    from IPython.external.qt import QtCore
  File "/usr/local/lib/python2.7/site-packages/IPython/external/qt.py", line 17, in <module>
    sip.setapi('QString', 2)
 ValueError: API 'QString' has already been set to version 1

Rearranging the imports in the following order allows it to succeed:

from IPython.frontend.qt.kernelmanager import QtKernelManager
from IPython.frontend.qt.console.ipython_widget import IPythonWidget

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QMainWindow, QApplication

Apparently, in order for the sip.setapi to be valid, a PyQt application can't have made any PyQt4 imports before importing from the IPython interface. For a simple one-file script like this there is no problem. However, adding an IPython widget into a large project would be difficult.

Is there any alternative to using sip.setapi?

@epatters

Unfortunately, there is not a good alternative. IPython is now using the v2 string API for both PySide and Python 3 compatibility reasons. This means that any Qt code using IPython must also use the v2 API.

To avoid having to order your imports in a silly way, you should make a call to sip.setapi before any Qt imports in the main script of your application. (You do not, of course, need to put a setapi call anywhere else.)

@Sharpie

Any workarounds for projects where I don't have commit access to the main script? Or that contain significant amounts of Python code that use QString?

@takluyver
IPython member

As far as I know, you have to pick one version of the API per project. So if IPython stuck with the v1 API, it couldn't be integrated with projects using the v2 API. No solution springs to mind, unfortunately. For an idea of how much code is affected in IPython, see the diff at #259.

@fperez
IPython member

I guess we'll need to close this one, since there isn't really anything we can do on our side. If anyone ever comes around with a better solution (doubtful) we can reopen and apply it.

@vidartf vidartf referenced this issue in hyperspy/hyperspy Nov 24, 2015
Merged

Fix windows traitui5 #767

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment