Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 422c509

Browse files
committed
Add support for PyQt5.
1 parent 347f2de commit 422c509

3 files changed

Lines changed: 57 additions & 19 deletions

File tree

IPython/external/qt.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
""" A Qt API selector that can be used to switch between PyQt and PySide.
1+
""" A Qt API selector that can be used to switch between PyQt4/5 and PySide.
22
33
This uses the ETS 4.0 selection pattern of:
4-
PySide first, PyQt with API v2. second.
4+
PySide first, PyQt4 (API v2.) second, then PyQt5.
55
6-
Do not use this if you need PyQt with the old QString/QVariant API.
6+
Do not use this if you need PyQt4 with the old QString/QVariant API.
77
"""
88

99
import os
1010

1111
from IPython.external.qt_loaders import (load_qt, QT_API_PYSIDE,
12-
QT_API_PYQT)
12+
QT_API_PYQT, QT_API_PYQT5)
1313

1414
QT_API = os.environ.get('QT_API', None)
15-
if QT_API not in [QT_API_PYSIDE, QT_API_PYQT, None]:
16-
raise RuntimeError("Invalid Qt API %r, valid values are: %r, %r" %
17-
(QT_API, QT_API_PYSIDE, QT_API_PYQT))
15+
if QT_API not in [QT_API_PYSIDE, QT_API_PYQT, QT_API_PYQT5, None]:
16+
raise RuntimeError("Invalid Qt API %r, valid values are: %r, %r, %r" %
17+
(QT_API, QT_API_PYSIDE, QT_API_PYQT, QT_API_PYQT5))
1818
if QT_API is None:
19-
api_opts = [QT_API_PYSIDE, QT_API_PYQT]
19+
api_opts = [QT_API_PYSIDE, QT_API_PYQT, QT_API_PYQT5]
2020
else:
2121
api_opts = [QT_API]
2222

IPython/external/qt_loaders.py

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
be accessed directly from the outside
1010
"""
1111
import sys
12+
import types
1213
from functools import partial
1314

1415
from IPython.utils.version import check_version
1516

1617
# Available APIs.
1718
QT_API_PYQT = 'pyqt'
19+
QT_API_PYQT5 = 'pyqt5'
1820
QT_API_PYQTv1 = 'pyqtv1'
1921
QT_API_PYQT_DEFAULT = 'pyqtdefault' # don't set SIP explicitly
2022
QT_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

8190
def 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+
187223
def 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))

IPython/kernel/inprocess/channels.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class InProcessChannel(object):
2828
"""Base class for in-process channels."""
2929
proxy_methods = []
3030

31-
def __init__(self, client):
31+
def __init__(self, client=None):
3232
super(InProcessChannel, self).__init__()
3333
self.client = client
3434
self._is_alive = False

0 commit comments

Comments
 (0)