##// END OF EJS Templates
BUG: QtKernelManagerMixin does not define PyQt4-safe signals.
epatters -
Show More
@@ -1,258 +1,260 b''
1 1 """ Defines a KernelManager that provides signals and slots.
2 2 """
3 3
4 4 # System library imports.
5 5 from IPython.external.qt import QtCore
6 6
7 7 # IPython imports.
8 from IPython.utils.traitlets import Type
9 from util import SuperQObject
8 from IPython.utils.traitlets import HasTraits, Type
9 from util import MetaQObjectHasTraits, SuperQObject
10 10
11 11
12 12 class ChannelQObject(SuperQObject):
13 13
14 14 # Emitted when the channel is started.
15 15 started = QtCore.Signal()
16 16
17 17 # Emitted when the channel is stopped.
18 18 stopped = QtCore.Signal()
19 19
20 20 #---------------------------------------------------------------------------
21 21 # Channel interface
22 22 #---------------------------------------------------------------------------
23 23
24 24 def start(self):
25 25 """ Reimplemented to emit signal.
26 26 """
27 27 super(ChannelQObject, self).start()
28 28 self.started.emit()
29 29
30 30 def stop(self):
31 31 """ Reimplemented to emit signal.
32 32 """
33 33 super(ChannelQObject, self).stop()
34 34 self.stopped.emit()
35 35
36 36 #---------------------------------------------------------------------------
37 37 # EmbeddedChannel interface
38 38 #---------------------------------------------------------------------------
39 39
40 40 def call_handlers_later(self, *args, **kwds):
41 41 """ Call the message handlers later.
42 42 """
43 43 do_later = lambda: self.call_handlers(*args, **kwds)
44 44 QtCore.QTimer.singleShot(0, do_later)
45 45
46 46 def process_events(self):
47 47 """ Process any pending GUI events.
48 48 """
49 49 QtCore.QCoreApplication.instance().processEvents()
50 50
51 51
52 52 class QtShellChannelMixin(ChannelQObject):
53 53
54 54 # Emitted when any message is received.
55 55 message_received = QtCore.Signal(object)
56 56
57 57 # Emitted when a reply has been received for the corresponding request
58 58 # type.
59 59 execute_reply = QtCore.Signal(object)
60 60 complete_reply = QtCore.Signal(object)
61 61 object_info_reply = QtCore.Signal(object)
62 62 history_reply = QtCore.Signal(object)
63 63
64 64 # Emitted when the first reply comes back.
65 65 first_reply = QtCore.Signal()
66 66
67 67 # Used by the first_reply signal logic to determine if a reply is the
68 68 # first.
69 69 _handlers_called = False
70 70
71 71 #---------------------------------------------------------------------------
72 72 # 'ShellSocketChannel' interface
73 73 #---------------------------------------------------------------------------
74 74
75 75 def call_handlers(self, msg):
76 76 """ Reimplemented to emit signals instead of making callbacks.
77 77 """
78 78 # Emit the generic signal.
79 79 self.message_received.emit(msg)
80 80
81 81 # Emit signals for specialized message types.
82 82 msg_type = msg['header']['msg_type']
83 83 signal = getattr(self, msg_type, None)
84 84 if signal:
85 85 signal.emit(msg)
86 86
87 87 if not self._handlers_called:
88 88 self.first_reply.emit()
89 89 self._handlers_called = True
90 90
91 91 #---------------------------------------------------------------------------
92 92 # 'QtShellChannelMixin' interface
93 93 #---------------------------------------------------------------------------
94 94
95 95 def reset_first_reply(self):
96 96 """ Reset the first_reply signal to fire again on the next reply.
97 97 """
98 98 self._handlers_called = False
99 99
100 100
101 101 class QtSubChannelMixin(ChannelQObject):
102 102
103 103 # Emitted when any message is received.
104 104 message_received = QtCore.Signal(object)
105 105
106 106 # Emitted when a message of type 'stream' is received.
107 107 stream_received = QtCore.Signal(object)
108 108
109 109 # Emitted when a message of type 'pyin' is received.
110 110 pyin_received = QtCore.Signal(object)
111 111
112 112 # Emitted when a message of type 'pyout' is received.
113 113 pyout_received = QtCore.Signal(object)
114 114
115 115 # Emitted when a message of type 'pyerr' is received.
116 116 pyerr_received = QtCore.Signal(object)
117 117
118 118 # Emitted when a message of type 'display_data' is received
119 119 display_data_received = QtCore.Signal(object)
120 120
121 121 # Emitted when a crash report message is received from the kernel's
122 122 # last-resort sys.excepthook.
123 123 crash_received = QtCore.Signal(object)
124 124
125 125 # Emitted when a shutdown is noticed.
126 126 shutdown_reply_received = QtCore.Signal(object)
127 127
128 128 #---------------------------------------------------------------------------
129 129 # 'SubSocketChannel' interface
130 130 #---------------------------------------------------------------------------
131 131
132 132 def call_handlers(self, msg):
133 133 """ Reimplemented to emit signals instead of making callbacks.
134 134 """
135 135 # Emit the generic signal.
136 136 self.message_received.emit(msg)
137 137 # Emit signals for specialized message types.
138 138 msg_type = msg['header']['msg_type']
139 139 signal = getattr(self, msg_type + '_received', None)
140 140 if signal:
141 141 signal.emit(msg)
142 142 elif msg_type in ('stdout', 'stderr'):
143 143 self.stream_received.emit(msg)
144 144
145 145 def flush(self):
146 146 """ Reimplemented to ensure that signals are dispatched immediately.
147 147 """
148 148 super(QtSubChannelMixin, self).flush()
149 149 QtCore.QCoreApplication.instance().processEvents()
150 150
151 151
152 152 class QtStdInChannelMixin(ChannelQObject):
153 153
154 154 # Emitted when any message is received.
155 155 message_received = QtCore.Signal(object)
156 156
157 157 # Emitted when an input request is received.
158 158 input_requested = QtCore.Signal(object)
159 159
160 160 #---------------------------------------------------------------------------
161 161 # 'StdInSocketChannel' interface
162 162 #---------------------------------------------------------------------------
163 163
164 164 def call_handlers(self, msg):
165 165 """ Reimplemented to emit signals instead of making callbacks.
166 166 """
167 167 # Emit the generic signal.
168 168 self.message_received.emit(msg)
169 169
170 170 # Emit signals for specialized message types.
171 171 msg_type = msg['header']['msg_type']
172 172 if msg_type == 'input_request':
173 173 self.input_requested.emit(msg)
174 174
175 175
176 176 class QtHBChannelMixin(ChannelQObject):
177 177
178 178 # Emitted when the kernel has died.
179 179 kernel_died = QtCore.Signal(object)
180 180
181 181 #---------------------------------------------------------------------------
182 182 # 'HBSocketChannel' interface
183 183 #---------------------------------------------------------------------------
184 184
185 185 def call_handlers(self, since_last_heartbeat):
186 186 """ Reimplemented to emit signals instead of making callbacks.
187 187 """
188 188 # Emit the generic signal.
189 189 self.kernel_died.emit(since_last_heartbeat)
190 190
191 191
192 class QtKernelManagerMixin(object):
192 class QtKernelManagerMixin(HasTraits, SuperQObject):
193 193 """ A KernelManager that provides signals and slots.
194 194 """
195 195
196 __metaclass__ = MetaQObjectHasTraits
197
196 198 # Emitted when the kernel manager has started listening.
197 199 started_kernel = QtCore.Signal()
198 200
199 201 # Emitted when the kernel manager has started listening.
200 202 started_channels = QtCore.Signal()
201 203
202 204 # Emitted when the kernel manager has stopped listening.
203 205 stopped_channels = QtCore.Signal()
204 206
205 207 # Use Qt-specific channel classes that emit signals.
206 208 sub_channel_class = Type(QtSubChannelMixin)
207 209 shell_channel_class = Type(QtShellChannelMixin)
208 210 stdin_channel_class = Type(QtStdInChannelMixin)
209 211 hb_channel_class = Type(QtHBChannelMixin)
210 212
211 213 #---------------------------------------------------------------------------
212 214 # 'KernelManager' interface
213 215 #---------------------------------------------------------------------------
214 216
215 217 #------ Kernel process management ------------------------------------------
216 218
217 219 def start_kernel(self, *args, **kw):
218 220 """ Reimplemented for proper heartbeat management.
219 221 """
220 222 if self._shell_channel is not None:
221 223 self._shell_channel.reset_first_reply()
222 224 super(QtKernelManagerMixin, self).start_kernel(*args, **kw)
223 225 self.started_kernel.emit()
224 226
225 227 #------ Channel management -------------------------------------------------
226 228
227 229 def start_channels(self, *args, **kw):
228 230 """ Reimplemented to emit signal.
229 231 """
230 232 super(QtKernelManagerMixin, self).start_channels(*args, **kw)
231 233 self.started_channels.emit()
232 234
233 235 def stop_channels(self):
234 236 """ Reimplemented to emit signal.
235 237 """
236 238 super(QtKernelManagerMixin, self).stop_channels()
237 239 self.stopped_channels.emit()
238 240
239 241 @property
240 242 def shell_channel(self):
241 243 """ Reimplemented for proper heartbeat management.
242 244 """
243 245 if self._shell_channel is None:
244 246 self._shell_channel = super(QtKernelManagerMixin,self).shell_channel
245 247 self._shell_channel.first_reply.connect(self._first_reply)
246 248 return self._shell_channel
247 249
248 250 #---------------------------------------------------------------------------
249 251 # Protected interface
250 252 #---------------------------------------------------------------------------
251 253
252 254 def _first_reply(self):
253 255 """ Unpauses the heartbeat channel when the first reply is received on
254 256 the execute channel. Note that this will *not* start the heartbeat
255 257 channel if it is not already running!
256 258 """
257 259 if self._hb_channel is not None:
258 260 self._hb_channel.unpause()
@@ -1,37 +1,33 b''
1 1 """ Defines an embedded KernelManager that provides signals and slots.
2 2 """
3 3
4 4 # Local imports.
5 5 from IPython.embedded.kernelmanager import \
6 6 ShellEmbeddedChannel, SubEmbeddedChannel, StdInEmbeddedChannel, \
7 7 HBEmbeddedChannel, EmbeddedKernelManager
8 8 from IPython.utils.traitlets import Type
9 9 from base_kernelmanager import QtShellChannelMixin, QtSubChannelMixin, \
10 10 QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin
11 from util import MetaQObjectHasTraits, SuperQObject
12 11
13 12
14 13 class QtShellEmbeddedChannel(QtShellChannelMixin, ShellEmbeddedChannel):
15 14 pass
16 15
17 16 class QtSubEmbeddedChannel(QtSubChannelMixin, SubEmbeddedChannel):
18 17 pass
19 18
20 19 class QtStdInEmbeddedChannel(QtStdInChannelMixin, StdInEmbeddedChannel):
21 20 pass
22 21
23 22 class QtHBEmbeddedChannel(QtHBChannelMixin, HBEmbeddedChannel):
24 23 pass
25 24
26 25
27 class QtEmbeddedKernelManager(QtKernelManagerMixin,
28 EmbeddedKernelManager, SuperQObject):
26 class QtEmbeddedKernelManager(QtKernelManagerMixin, EmbeddedKernelManager):
29 27 """ An embedded KernelManager that provides signals and slots.
30 28 """
31 29
32 __metaclass__ = MetaQObjectHasTraits
33
34 30 sub_channel_class = Type(QtSubEmbeddedChannel)
35 31 shell_channel_class = Type(QtShellEmbeddedChannel)
36 32 stdin_channel_class = Type(QtStdInEmbeddedChannel)
37 33 hb_channel_class = Type(QtHBEmbeddedChannel)
@@ -1,35 +1,32 b''
1 1 """ Defines a KernelManager that provides signals and slots.
2 2 """
3 3
4 4 # Local imports.
5 5 from IPython.utils.traitlets import Type
6 6 from IPython.zmq.kernelmanager import ShellSocketChannel, SubSocketChannel, \
7 7 StdInSocketChannel, HBSocketChannel, KernelManager
8 8 from base_kernelmanager import QtShellChannelMixin, QtSubChannelMixin, \
9 9 QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin
10 from util import MetaQObjectHasTraits, SuperQObject
11 10
12 11
13 12 class QtShellSocketChannel(QtShellChannelMixin, ShellSocketChannel):
14 13 pass
15 14
16 15 class QtSubSocketChannel(QtSubChannelMixin, SubSocketChannel):
17 16 pass
18 17
19 18 class QtStdInSocketChannel(QtStdInChannelMixin, StdInSocketChannel):
20 19 pass
21 20
22 21 class QtHBSocketChannel(QtHBChannelMixin, HBSocketChannel):
23 22 pass
24 23
25 24
26 class QtKernelManager(QtKernelManagerMixin, KernelManager, SuperQObject):
25 class QtKernelManager(QtKernelManagerMixin, KernelManager):
27 26 """ A KernelManager that provides signals and slots.
28 27 """
29 28
30 __metaclass__ = MetaQObjectHasTraits
31
32 29 sub_channel_class = Type(QtSubSocketChannel)
33 30 shell_channel_class = Type(QtShellSocketChannel)
34 31 stdin_channel_class = Type(QtStdInSocketChannel)
35 32 hb_channel_class = Type(QtHBSocketChannel)
@@ -1,106 +1,106 b''
1 1 """ Defines miscellaneous Qt-related helper classes and functions.
2 2 """
3 3
4 4 # Standard library imports.
5 5 import inspect
6 6
7 7 # System library imports.
8 8 from IPython.external.qt import QtCore, QtGui
9 9
10 10 # IPython imports.
11 11 from IPython.utils.traitlets import HasTraits, TraitType
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Metaclasses
15 15 #-----------------------------------------------------------------------------
16 16
17 17 MetaHasTraits = type(HasTraits)
18 18 MetaQObject = type(QtCore.QObject)
19 19
20 20 class MetaQObjectHasTraits(MetaQObject, MetaHasTraits):
21 21 """ A metaclass that inherits from the metaclasses of HasTraits and QObject.
22 22
23 23 Using this metaclass allows a class to inherit from both HasTraits and
24 24 QObject. Using SuperQObject instead of QObject is highly recommended. See
25 25 QtKernelManager for an example.
26 26 """
27 27 def __new__(mcls, name, bases, classdict):
28 28 # FIXME: this duplicates the code from MetaHasTraits.
29 29 # I don't think a super() call will help me here.
30 30 for k,v in classdict.iteritems():
31 31 if isinstance(v, TraitType):
32 32 v.name = k
33 33 elif inspect.isclass(v):
34 34 if issubclass(v, TraitType):
35 35 vinst = v()
36 36 vinst.name = k
37 37 classdict[k] = vinst
38 38 cls = MetaQObject.__new__(mcls, name, bases, classdict)
39 39 return cls
40 40
41 41 def __init__(mcls, name, bases, classdict):
42 42 # Note: super() did not work, so we explicitly call these.
43 43 MetaQObject.__init__(mcls, name, bases, classdict)
44 44 MetaHasTraits.__init__(mcls, name, bases, classdict)
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Classes
48 48 #-----------------------------------------------------------------------------
49 49
50 50 class SuperQObject(QtCore.QObject):
51 51 """ Permits the use of super() in class hierarchies that contain QObject.
52 52
53 53 Unlike QObject, SuperQObject does not accept a QObject parent. If it did,
54 54 super could not be emulated properly (all other classes in the heierarchy
55 55 would have to accept the parent argument--they don't, of course, because
56 56 they don't inherit QObject.)
57 57
58 58 This class is primarily useful for attaching signals to existing non-Qt
59 classes. See QtKernelManager for an example.
59 classes. See QtKernelManagerMixin for an example.
60 60 """
61 61
62 62 def __new__(cls, *args, **kw):
63 63 # We initialize QObject as early as possible. Without this, Qt complains
64 64 # if SuperQObject is not the first class in the super class list.
65 65 inst = QtCore.QObject.__new__(cls)
66 66 QtCore.QObject.__init__(inst)
67 67 return inst
68 68
69 69 def __init__(self, *args, **kw):
70 70 # Emulate super by calling the next method in the MRO, if there is one.
71 71 mro = self.__class__.mro()
72 72 for qt_class in QtCore.QObject.mro():
73 73 mro.remove(qt_class)
74 74 next_index = mro.index(SuperQObject) + 1
75 75 if next_index < len(mro):
76 76 mro[next_index].__init__(self, *args, **kw)
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # Functions
80 80 #-----------------------------------------------------------------------------
81 81
82 82 def get_font(family, fallback=None):
83 83 """Return a font of the requested family, using fallback as alternative.
84 84
85 85 If a fallback is provided, it is used in case the requested family isn't
86 86 found. If no fallback is given, no alternative is chosen and Qt's internal
87 87 algorithms may automatically choose a fallback font.
88 88
89 89 Parameters
90 90 ----------
91 91 family : str
92 92 A font name.
93 93 fallback : str
94 94 A font name.
95 95
96 96 Returns
97 97 -------
98 98 font : QFont object
99 99 """
100 100 font = QtGui.QFont(family)
101 101 # Check whether we got what we wanted using QFontInfo, since exactMatch()
102 102 # is overly strict and returns false in too many cases.
103 103 font_info = QtGui.QFontInfo(font)
104 104 if fallback is not None and font_info.family() != family:
105 105 font = QtGui.QFont(fallback)
106 106 return font
General Comments 0
You need to be logged in to leave comments. Login now