@@ -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+
97113def _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
132158def loop_qt_exit (kernel ):
133159 kernel .app .exit ()
134160
0 commit comments