Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

reorder qt support in kernel #560

wants to merge 2 commits into
Jump to file or symbol
Failed to load files and symbols.
+120 −3
@@ -1,4 +1,9 @@
""" A Qt API selector that can be used to switch between PyQt and PySide.
+This uses the ETS 4.0 selection pattern of:
+PySide first, PyQt with API v2. second.
+Do not use this if you need PyQt with the old QString/QVariant API.
import os
@@ -1,12 +1,84 @@
""" Import Qt in a manner suitable for an IPython kernel.
+This is the import used for the `gui=qt` or `pylab=qt` initialization.
+Import Priority:
+if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
+ use PyQt4 @v1
+Next, ask ETS' QT_API env variable
+if QT_API not set:
+ ask matplotlib via rcParams['backend.qt4']
+ if it said PyQt:
+ use PyQt4 @v1
+ elif it said PySide:
+ use PySide
+ else: (matplotlib said nothing)
+ # this is the default path - nobody told us anything
+ try:
+ PyQt @v1
+ except:
+ fallback on PySide
+ use PyQt @v2 or PySide, depending on QT_API
+ because ETS doesn't work with PyQt @v1.
+import os
import sys
-# Older versions of matplotlib do not support PyQt4 v2 APIs or PySide, so we
-# cannot go through the preferred mechanism.
matplotlib = sys.modules.get('matplotlib')
if matplotlib and matplotlib.__version__ <= '1.0.1':
+ # 1.0.1 doesn't support pyside or v2, so stick with PyQt @v1,
+ # and ignore everything else
from PyQt4 import QtCore, QtGui
- from IPython.external.qt import QtCore, QtGui
+ # ask QT_API ETS variable *first*
+ QT_API = os.environ.get('QT_API', None)
+ if QT_API is None:
+ # QT_API not set, ask matplotlib if it was imported (e.g. `pylab=qt`)
+ if matplotlib:
+ # this rc option has been proposed, but is not yet in matplotlib master
+ # as of writing.
+ mpqt = matplotlib.rcParams.get('backend.qt4', None)
+ else:
+ mpqt = None
+ if mpqt is None:
+ # matplotlib not imported or had nothing to say.
+ try:
+ # default to unconfigured PyQt4
+ from PyQt4 import QtCore, QtGui
+ except ImportError:
+ # fallback on PySide
+ try:
+ from PySide import QtCore, QtGui
+ except ImportError:
+ raise ImportError('Cannot import PySide or PyQt4')
+ elif mpqt.lower() == 'pyqt4':
+ # import PyQt4 unconfigured
+ from PyQt4 import QtCore, QtGui
+ elif mpqt.lower() == 'pyside':
+ from PySide import QtCore, QtGui
+ else:
+ raise ImportError("unhandled value for backend.qt4 from matplotlib: %r"%mpqt)
+ else:
+ # QT_API specified, use PySide or PyQt+v2 API from external.qt
+ # this means ETS is likely to be used, which requires v2
+ try:
+ from IPython.external.qt import QtCore, QtGui
+ except ValueError as e:
+ if 'API' in str(e):
+ # API mismatch, give more meaningful message
+ raise ImportError("""
+ Assinging the ETS variable `QT_API=pyqt` implies PyQt's v2 API for
+ QString and QVariant, but PyQt has already been imported
+ with v1 APIs. You must unset QT_API to work with PyQt4
+ in its default mode.
+ else:
+ raise
@@ -1256,6 +1256,46 @@ process pending events at critical points.
Finally, we also have a number of examples in our source directory
:file:`docs/examples/lib` that demonstrate these capabilities.
+PyQt and PySide
+.. attempt at explanation of the complete mess that is Qt support
+When you use ``gui=qt`` or ``pylab=qt``, IPython can work with either
+PyQt4 or PySide. There are three options for configuration here, because
+PyQt4 has two APIs for QString and QVariant - v1, which is the default on
+Python 2, and the more natural v2, which is the only API supported by PySide.
+v2 is also the default for PyQt4 on Python 3. IPython's code for the QtConsole
+uses v2, but you can still use any interface in your code, since the
+Qt frontend is in a different process.
+The default will be to import PyQt4 without configuration of the APIs, thus
+matching what most applications would expect. It will fall back of PySide if
+PyQt4 is unavailable.
+If specified, IPython will respect the environment variable ``QT_API`` used
+by ETS. ETS 4.0 also works with both PyQt4 and PySide, but it requires
+PyQt4 to use its v2 API. So if ``QT_API=pyside`` PySide will be used,
+and if ``QT_API=pyqt`` then PyQt4 will be used *with the v2 API* for
+QString and QVariant, so ETS codes like MayaVi will also work with IPython.
+If you launch IPython in pylab mode with ``ipython pylab=qt``, then IPython
+will ask matplotlib which Qt library to use (only if QT_API is *not set*),
+via the 'backend.qt4' rcParam.
+If matplotlib is version 1.0.1 or older, then IPython will always use PyQt4
+without setting the v2 APIs, since neither v2 PyQt nor PySide work.
+.. warning::
+ Note that this means for ETS 4 to work with PyQt4, ``QT_API`` *must* be set to
+ work with IPython's qt integration, because otherwise PyQt4 will be loaded in
+ an incompatible mode.
+ It also means that you must *not* have ``QT_API`` set if you want to
+ use ``gui=qt`` with code that requires PyQt4 API v1.
.. _matplotlib_support:
Plotting with matplotlib