diff --git a/IPython/external/qt.py b/IPython/external/qt.py index 75b02cb..44a0d0c 100644 --- a/IPython/external/qt.py +++ b/IPython/external/qt.py @@ -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 diff --git a/IPython/external/qt_for_kernel.py b/IPython/external/qt_for_kernel.py index 573359e..1c399a1 100644 --- a/IPython/external/qt_for_kernel.py +++ b/IPython/external/qt_for_kernel.py @@ -1,12 +1,75 @@ """ Import Qt in a manner suitable for an IPython kernel. + +This is the import used for the `gui=qt` or `pylab=qt` initialization. + +Priority: + +if matplotlib has been imported: + # get here with pylab=qt + if matplotlib doesn't support v2 (<= 1.0.1): + use PyQt4 @v1 + else: + ask matplotlib which Qt it's using + if it said PyQt: + use PyQt4 @v1 + elif it said PySide: + use PySide + +if matplotlib had nothing to say, or matplotlib not imported: + # get here with gui=qt, or if matplotlib didn't tell us anything + ask ETS' QT_API env variable + + if QT_API not set: + # this is the *default* path - no information was given + try: + PyQt @v1 + except: + fallback on PySide + else: + use PyQt @v2 or PySide, depending on QT_API + because ETS doesn't work with 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': +if matplotlib: + # ask matplotlib first (get here with pylab=qt) + if matplotlib.__version__ <= '1.0.1': + # 1.0.1 doesn't support pyside or v2, so force PyQt @v1 + mod = 'PyQt4' + else: + # this rc option has been proposed, but is yet not in matplotlib master + # as of writing. + mod = matplotlib.rcParams.get('backend.qt4', None) +else: + # get here with `gui=qt` + mod = None + +if mod is None: + # matplotlib not imported or had nothing to say. + # ask QT_API ETS variable + QT_API = os.environ.get('QT_API', None) + if QT_API is None: + 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') + else: + # QT_API specified, use PySide or PyQt+v2 API from external.qt + # this means ETS is likely to be used, which requires v2 + from IPython.external.qt import QtCore, QtGui + +elif mod.lower() == 'pyqt4': + # import PyQt4 unconfigured from PyQt4 import QtCore, QtGui +elif mod.lower() == 'pyside': + from PySide import QtCore, QtGui else: - from IPython.external.qt import QtCore, QtGui + raise ImportError("unhandled value for backend.qt4 from matplotlib: %r"%mod) \ No newline at end of file diff --git a/docs/source/interactive/reference.txt b/docs/source/interactive/reference.txt index 4e08d9d..612885f 100644 --- a/docs/source/interactive/reference.txt +++ b/docs/source/interactive/reference.txt @@ -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. + +If you launch IPython in pylab mode with ``ipython pylab=qt``, then IPython +will ask matplotlib which Qt library to use, 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. + +If you just integrate the Qt event loop with ``ipython gui=qt``, then IPython +has a few more possibilities. 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 the 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. + +.. warning:: + + Note that this means for ETS 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