99be accessed directly from the outside
1010"""
1111import sys
12+ import types
1213from functools import partial
1314
1415from IPython .utils .version import check_version
1516
1617# Available APIs.
1718QT_API_PYQT = 'pyqt'
19+ QT_API_PYQT5 = 'pyqt5'
1820QT_API_PYQTv1 = 'pyqtv1'
1921QT_API_PYQT_DEFAULT = 'pyqtdefault' # don't set SIP explicitly
2022QT_API_PYSIDE = 'pyside'
@@ -26,16 +28,16 @@ class ImportDenier(object):
2628 """
2729
2830 def __init__ (self ):
29- self .__forbidden = None
31+ self .__forbidden = set ()
3032
3133 def forbid (self , module_name ):
3234 sys .modules .pop (module_name , None )
33- self .__forbidden = module_name
35+ self .__forbidden . add ( module_name )
3436
3537 def find_module (self , mod_name , pth ):
3638 if pth :
3739 return
38- if mod_name == self .__forbidden :
40+ if mod_name in self .__forbidden :
3941 return self
4042
4143 def load_module (self , mod_name ):
@@ -54,7 +56,12 @@ def commit_api(api):
5456
5557 if api == QT_API_PYSIDE :
5658 ID .forbid ('PyQt4' )
59+ ID .forbid ('PyQt5' )
60+ elif api == QT_API_PYQT :
61+ ID .forbid ('PySide' )
62+ ID .forbid ('PyQt5' )
5763 else :
64+ ID .forbid ('PyQt4' )
5865 ID .forbid ('PySide' )
5966
6067
@@ -75,16 +82,18 @@ def loaded_api():
7582 return QT_API_PYQTv1
7683 elif 'PySide.QtCore' in sys .modules :
7784 return QT_API_PYSIDE
85+ elif 'PyQt5.QtCore' in sys .modules :
86+ return QT_API_PYQT5
7887 return None
7988
8089
8190def has_binding (api ):
82- """Safely check for PyQt4 or PySide, without importing
91+ """Safely check for PyQt4/5 or PySide, without importing
8392 submodules
8493
8594 Parameters
8695 ----------
87- api : str [ 'pyqtv1' | 'pyqt' | 'pyside' | 'pyqtdefault']
96+ api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | ' pyside' | 'pyqtdefault']
8897 Which module to check for
8998
9099 Returns
@@ -97,6 +106,7 @@ def has_binding(api):
97106 module_name = {QT_API_PYSIDE : 'PySide' ,
98107 QT_API_PYQT : 'PyQt4' ,
99108 QT_API_PYQTv1 : 'PyQt4' ,
109+ QT_API_PYQT5 : 'PyQt5' ,
100110 QT_API_PYQT_DEFAULT : 'PyQt4' }
101111 module_name = module_name [api ]
102112
@@ -108,6 +118,9 @@ def has_binding(api):
108118 imp .find_module ('QtCore' , mod .__path__ )
109119 imp .find_module ('QtGui' , mod .__path__ )
110120 imp .find_module ('QtSvg' , mod .__path__ )
121+ if api == QT_API_PYQT5 :
122+ # QT5 requires QtWidgets too
123+ imp .find_module ('QtWidgets' , mod .__path__ )
111124
112125 #we can also safely check PySide version
113126 if api == QT_API_PYSIDE :
@@ -184,6 +197,29 @@ def import_pyqt4(version=2):
184197 return QtCore , QtGui , QtSvg , api
185198
186199
200+ def import_pyqt5 ():
201+ """
202+ Import PyQt5
203+
204+ ImportErrors rasied within this function are non-recoverable
205+ """
206+ import sip
207+
208+ from PyQt5 import QtCore , QtSvg , QtWidgets , QtGui
209+
210+ # Alias PyQt-specific functions for PySide compatibility.
211+ QtCore .Signal = QtCore .pyqtSignal
212+ QtCore .Slot = QtCore .pyqtSlot
213+
214+ # Join QtGui and QtWidgets for Qt4 compatibility.
215+ QtGuiCompat = types .ModuleType ('QtGuiCompat' )
216+ QtGuiCompat .__dict__ .update (QtGui .__dict__ )
217+ QtGuiCompat .__dict__ .update (QtWidgets .__dict__ )
218+
219+ api = QT_API_PYQT5
220+ return QtCore , QtGuiCompat , QtSvg , api
221+
222+
187223def import_pyside ():
188224 """
189225 Import PySide
@@ -205,7 +241,7 @@ def load_qt(api_options):
205241 ----------
206242 api_options: List of strings
207243 The order of APIs to try. Valid items are 'pyside',
208- 'pyqt', and 'pyqtv1'
244+ 'pyqt', 'pyqt5' and 'pyqtv1'
209245
210246 Returns
211247 -------
@@ -222,6 +258,7 @@ def load_qt(api_options):
222258 """
223259 loaders = {QT_API_PYSIDE : import_pyside ,
224260 QT_API_PYQT : import_pyqt4 ,
261+ QT_API_PYQT5 : import_pyqt5 ,
225262 QT_API_PYQTv1 : partial (import_pyqt4 , version = 1 ),
226263 QT_API_PYQT_DEFAULT : partial (import_pyqt4 , version = None )
227264 }
@@ -230,9 +267,8 @@ def load_qt(api_options):
230267
231268 if api not in loaders :
232269 raise RuntimeError (
233- "Invalid Qt API %r, valid values are: %r, %r, %r, %r" %
234- (api , QT_API_PYSIDE , QT_API_PYQT ,
235- QT_API_PYQTv1 , QT_API_PYQT_DEFAULT ))
270+ "Invalid Qt API %r, valid values are: %s" %
271+ (api , ", " .join (["%r" % k for k in loaders .keys ()])))
236272
237273 if not can_import (api ):
238274 continue
@@ -245,14 +281,16 @@ def load_qt(api_options):
245281 else :
246282 raise ImportError ("""
247283 Could not load requested Qt binding. Please ensure that
248- PyQt4 >= 4.7 or PySide >= 1.0.3 is available,
284+ PyQt4 >= 4.7, PyQt5 or PySide >= 1.0.3 is available,
249285 and only one is imported per session.
250286
251287 Currently-imported Qt library: %r
252288 PyQt4 installed: %s
289+ PyQt5 installed: %s
253290 PySide >= 1.0.3 installed: %s
254291 Tried to load: %r
255292 """ % (loaded_api (),
256293 has_binding (QT_API_PYQT ),
294+ has_binding (QT_API_PYQT5 ),
257295 has_binding (QT_API_PYSIDE ),
258296 api_options ))
0 commit comments