Skip to content

Commit d5d718b

Browse files
committed
ENH: add support for qt6
1 parent 81a640b commit d5d718b

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

ipykernel/eventloops.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@ def _use_appnope():
2222
return sys.platform == 'darwin' and V(platform.mac_ver()[0]) >= V('10.9')
2323

2424

25-
def _notify_stream_qt(kernel, stream):
26-
25+
def _notify_stream_qt(event_loop, stream):
26+
import operator
27+
from functools import lru_cache
2728
from IPython.external.qt_for_kernel import QtCore
2829

30+
try:
31+
from IPython.external.qt_for_kernel import enum_helper
32+
except ImportError:
33+
@lru_cache(None)
34+
def enum_helper(name):
35+
return operator.attrgetter(
36+
name.rpartition(".")[0]
37+
)(sys.modules[QtCore.__package__])
38+
39+
2940
def process_stream_events():
3041
"""fall back to main loop when there's a socket event"""
3142
# call flush to ensure that the stream doesn't lose events
@@ -34,10 +45,10 @@ def process_stream_events():
3445
# if there were any, wake it up
3546
if stream.flush(limit=1):
3647
notifier.setEnabled(False)
37-
kernel.app.quit()
48+
event_loop.quit()
3849

3950
fd = stream.getsockopt(zmq.FD)
40-
notifier = QtCore.QSocketNotifier(fd, QtCore.QSocketNotifier.Read, kernel.app)
51+
notifier = QtCore.QSocketNotifier(fd, enum_helper('QtCore.QSocketNotifier.Type').Read, event_loop)
4152
notifier.activated.connect(process_stream_events)
4253
# there may already be unprocessed events waiting.
4354
# these events will not wake zmq's edge-triggered FD
@@ -46,7 +57,7 @@ def process_stream_events():
4657
# so we start in a clean state ensuring that any new i/o events will notify.
4758
# schedule first call on the eventloop as soon as it's running,
4859
# so we don't block here processing events
49-
timer = QtCore.QTimer(kernel.app)
60+
timer = QtCore.QTimer(event_loop)
5061
timer.setSingleShot(True)
5162
timer.timeout.connect(process_stream_events)
5263
timer.start(0)
@@ -94,6 +105,11 @@ def exit_decorator(exit_func):
94105
return decorator
95106

96107

108+
def _exec(obj):
109+
# exec on PyQt6, exec_ elsewhere.
110+
obj.exec() if hasattr(obj, "exec") else obj.exec_()
111+
112+
97113
def _loop_qt(app):
98114
"""Inner-loop for running the Qt eventloop
99115
@@ -102,7 +118,7 @@ def _loop_qt(app):
102118
rather than if the eventloop is actually running.
103119
"""
104120
app._in_event_loop = True
105-
app.exec_()
121+
_exec(app)
106122
app._in_event_loop = False
107123

108124

@@ -111,12 +127,14 @@ def loop_qt4(kernel):
111127
"""Start a kernel with PyQt4 event loop integration."""
112128

113129
from IPython.lib.guisupport import get_app_qt4
114-
130+
from IPython.external.qt_for_kernel import QtCore
115131
kernel.app = get_app_qt4([" "])
116132
kernel.app.setQuitOnLastWindowClosed(False)
117-
_notify_stream_qt(kernel, kernel.shell_stream)
133+
event_loop = QtCore.QEventLoop(kernel.app)
134+
135+
_notify_stream_qt(event_loop, kernel.shell_stream)
118136

119-
_loop_qt(kernel.app)
137+
_loop_qt(event_loop)
120138

121139

122140
@register_integration('qt', 'qt5')
@@ -126,9 +144,17 @@ def loop_qt5(kernel):
126144
return loop_qt4(kernel)
127145

128146

129-
# exit and watch are the same for qt 4 and 5
147+
@register_integration('qt6')
148+
def loop_qt6(kernel):
149+
"""Start a kernel with PyQt6 event loop integration."""
150+
os.environ['QT_API'] = 'pyqt6'
151+
return loop_qt4(kernel)
152+
153+
154+
# exit and watch are the same for qt 4, 5, and 6
130155
@loop_qt4.exit
131156
@loop_qt5.exit
157+
@loop_qt6.exit
132158
def loop_qt_exit(kernel):
133159
kernel.app.exit()
134160

0 commit comments

Comments
 (0)