##// END OF EJS Templates
set busy/idle around every message...
MinRK -
Show More
@@ -1,669 +1,677 b''
1 """Base class for a kernel that talks to frontends over 0MQ."""
1 """Base class for a kernel that talks to frontends over 0MQ."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import sys
8 import sys
9 import time
9 import time
10 import logging
10 import logging
11 import uuid
11 import uuid
12
12
13 from datetime import datetime
13 from datetime import datetime
14 from signal import (
14 from signal import (
15 signal, default_int_handler, SIGINT
15 signal, default_int_handler, SIGINT
16 )
16 )
17
17
18 import zmq
18 import zmq
19 from zmq.eventloop import ioloop
19 from zmq.eventloop import ioloop
20 from zmq.eventloop.zmqstream import ZMQStream
20 from zmq.eventloop.zmqstream import ZMQStream
21
21
22 from IPython.config.configurable import Configurable
22 from IPython.config.configurable import Configurable
23 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.error import StdinNotImplementedError
24 from IPython.core import release
24 from IPython.core import release
25 from IPython.utils import py3compat
25 from IPython.utils import py3compat
26 from IPython.utils.py3compat import unicode_type, string_types
26 from IPython.utils.py3compat import unicode_type, string_types
27 from IPython.utils.jsonutil import json_clean
27 from IPython.utils.jsonutil import json_clean
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Any, Instance, Float, Dict, List, Set, Integer, Unicode, Bool,
29 Any, Instance, Float, Dict, List, Set, Integer, Unicode, Bool,
30 )
30 )
31
31
32 from .session import Session
32 from .session import Session
33
33
34
34
35 class Kernel(Configurable):
35 class Kernel(Configurable):
36
36
37 #---------------------------------------------------------------------------
37 #---------------------------------------------------------------------------
38 # Kernel interface
38 # Kernel interface
39 #---------------------------------------------------------------------------
39 #---------------------------------------------------------------------------
40
40
41 # attribute to override with a GUI
41 # attribute to override with a GUI
42 eventloop = Any(None)
42 eventloop = Any(None)
43 def _eventloop_changed(self, name, old, new):
43 def _eventloop_changed(self, name, old, new):
44 """schedule call to eventloop from IOLoop"""
44 """schedule call to eventloop from IOLoop"""
45 loop = ioloop.IOLoop.instance()
45 loop = ioloop.IOLoop.instance()
46 loop.add_callback(self.enter_eventloop)
46 loop.add_callback(self.enter_eventloop)
47
47
48 session = Instance(Session)
48 session = Instance(Session)
49 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
49 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
50 shell_streams = List()
50 shell_streams = List()
51 control_stream = Instance(ZMQStream)
51 control_stream = Instance(ZMQStream)
52 iopub_socket = Instance(zmq.Socket)
52 iopub_socket = Instance(zmq.Socket)
53 stdin_socket = Instance(zmq.Socket)
53 stdin_socket = Instance(zmq.Socket)
54 log = Instance(logging.Logger)
54 log = Instance(logging.Logger)
55
55
56 # identities:
56 # identities:
57 int_id = Integer(-1)
57 int_id = Integer(-1)
58 ident = Unicode()
58 ident = Unicode()
59
59
60 def _ident_default(self):
60 def _ident_default(self):
61 return unicode_type(uuid.uuid4())
61 return unicode_type(uuid.uuid4())
62
62
63 # Private interface
63 # Private interface
64
64
65 _darwin_app_nap = Bool(True, config=True,
65 _darwin_app_nap = Bool(True, config=True,
66 help="""Whether to use appnope for compatiblity with OS X App Nap.
66 help="""Whether to use appnope for compatiblity with OS X App Nap.
67
67
68 Only affects OS X >= 10.9.
68 Only affects OS X >= 10.9.
69 """
69 """
70 )
70 )
71
71
72 # track associations with current request
72 # track associations with current request
73 _allow_stdin = Bool(False)
73 _allow_stdin = Bool(False)
74 _parent_header = Dict()
74 _parent_header = Dict()
75 _parent_ident = Any(b'')
75 _parent_ident = Any(b'')
76 # Time to sleep after flushing the stdout/err buffers in each execute
76 # Time to sleep after flushing the stdout/err buffers in each execute
77 # cycle. While this introduces a hard limit on the minimal latency of the
77 # cycle. While this introduces a hard limit on the minimal latency of the
78 # execute cycle, it helps prevent output synchronization problems for
78 # execute cycle, it helps prevent output synchronization problems for
79 # clients.
79 # clients.
80 # Units are in seconds. The minimum zmq latency on local host is probably
80 # Units are in seconds. The minimum zmq latency on local host is probably
81 # ~150 microseconds, set this to 500us for now. We may need to increase it
81 # ~150 microseconds, set this to 500us for now. We may need to increase it
82 # a little if it's not enough after more interactive testing.
82 # a little if it's not enough after more interactive testing.
83 _execute_sleep = Float(0.0005, config=True)
83 _execute_sleep = Float(0.0005, config=True)
84
84
85 # Frequency of the kernel's event loop.
85 # Frequency of the kernel's event loop.
86 # Units are in seconds, kernel subclasses for GUI toolkits may need to
86 # Units are in seconds, kernel subclasses for GUI toolkits may need to
87 # adapt to milliseconds.
87 # adapt to milliseconds.
88 _poll_interval = Float(0.05, config=True)
88 _poll_interval = Float(0.05, config=True)
89
89
90 # If the shutdown was requested over the network, we leave here the
90 # If the shutdown was requested over the network, we leave here the
91 # necessary reply message so it can be sent by our registered atexit
91 # necessary reply message so it can be sent by our registered atexit
92 # handler. This ensures that the reply is only sent to clients truly at
92 # handler. This ensures that the reply is only sent to clients truly at
93 # the end of our shutdown process (which happens after the underlying
93 # the end of our shutdown process (which happens after the underlying
94 # IPython shell's own shutdown).
94 # IPython shell's own shutdown).
95 _shutdown_message = None
95 _shutdown_message = None
96
96
97 # This is a dict of port number that the kernel is listening on. It is set
97 # This is a dict of port number that the kernel is listening on. It is set
98 # by record_ports and used by connect_request.
98 # by record_ports and used by connect_request.
99 _recorded_ports = Dict()
99 _recorded_ports = Dict()
100
100
101 # set of aborted msg_ids
101 # set of aborted msg_ids
102 aborted = Set()
102 aborted = Set()
103
103
104 # Track execution count here. For IPython, we override this to use the
104 # Track execution count here. For IPython, we override this to use the
105 # execution count we store in the shell.
105 # execution count we store in the shell.
106 execution_count = 0
106 execution_count = 0
107
107
108
108
109 def __init__(self, **kwargs):
109 def __init__(self, **kwargs):
110 super(Kernel, self).__init__(**kwargs)
110 super(Kernel, self).__init__(**kwargs)
111
111
112 # Build dict of handlers for message types
112 # Build dict of handlers for message types
113 msg_types = [ 'execute_request', 'complete_request',
113 msg_types = [ 'execute_request', 'complete_request',
114 'inspect_request', 'history_request',
114 'inspect_request', 'history_request',
115 'kernel_info_request',
115 'kernel_info_request',
116 'connect_request', 'shutdown_request',
116 'connect_request', 'shutdown_request',
117 'apply_request',
117 'apply_request',
118 ]
118 ]
119 self.shell_handlers = {}
119 self.shell_handlers = {}
120 for msg_type in msg_types:
120 for msg_type in msg_types:
121 self.shell_handlers[msg_type] = getattr(self, msg_type)
121 self.shell_handlers[msg_type] = getattr(self, msg_type)
122
122
123 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
123 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
124 self.control_handlers = {}
124 self.control_handlers = {}
125 for msg_type in control_msg_types:
125 for msg_type in control_msg_types:
126 self.control_handlers[msg_type] = getattr(self, msg_type)
126 self.control_handlers[msg_type] = getattr(self, msg_type)
127
127
128
128
129 def dispatch_control(self, msg):
129 def dispatch_control(self, msg):
130 """dispatch control requests"""
130 """dispatch control requests"""
131 idents,msg = self.session.feed_identities(msg, copy=False)
131 idents,msg = self.session.feed_identities(msg, copy=False)
132 try:
132 try:
133 msg = self.session.unserialize(msg, content=True, copy=False)
133 msg = self.session.unserialize(msg, content=True, copy=False)
134 except:
134 except:
135 self.log.error("Invalid Control Message", exc_info=True)
135 self.log.error("Invalid Control Message", exc_info=True)
136 return
136 return
137
137
138 self.log.debug("Control received: %s", msg)
138 self.log.debug("Control received: %s", msg)
139
139
140 # Set the parent message for side effects.
141 self.set_parent(idents, msg)
142 self._publish_status(u'busy')
143
140 header = msg['header']
144 header = msg['header']
141 msg_type = header['msg_type']
145 msg_type = header['msg_type']
142
146
143 handler = self.control_handlers.get(msg_type, None)
147 handler = self.control_handlers.get(msg_type, None)
144 if handler is None:
148 if handler is None:
145 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
149 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
146 else:
150 else:
147 try:
151 try:
148 handler(self.control_stream, idents, msg)
152 handler(self.control_stream, idents, msg)
149 except Exception:
153 except Exception:
150 self.log.error("Exception in control handler:", exc_info=True)
154 self.log.error("Exception in control handler:", exc_info=True)
151
155
156 sys.stdout.flush()
157 sys.stderr.flush()
158 self._publish_status(u'idle')
159
152 def dispatch_shell(self, stream, msg):
160 def dispatch_shell(self, stream, msg):
153 """dispatch shell requests"""
161 """dispatch shell requests"""
154 # flush control requests first
162 # flush control requests first
155 if self.control_stream:
163 if self.control_stream:
156 self.control_stream.flush()
164 self.control_stream.flush()
157
165
158 idents,msg = self.session.feed_identities(msg, copy=False)
166 idents,msg = self.session.feed_identities(msg, copy=False)
159 try:
167 try:
160 msg = self.session.unserialize(msg, content=True, copy=False)
168 msg = self.session.unserialize(msg, content=True, copy=False)
161 except:
169 except:
162 self.log.error("Invalid Message", exc_info=True)
170 self.log.error("Invalid Message", exc_info=True)
163 return
171 return
164
172
165 # Set the parent message for side effects.
173 # Set the parent message for side effects.
166 self.set_parent(idents, msg)
174 self.set_parent(idents, msg)
167 self._publish_status(u'busy')
175 self._publish_status(u'busy')
168
176
169 header = msg['header']
177 header = msg['header']
170 msg_id = header['msg_id']
178 msg_id = header['msg_id']
171 msg_type = msg['header']['msg_type']
179 msg_type = msg['header']['msg_type']
172
180
173 # Print some info about this message and leave a '--->' marker, so it's
181 # Print some info about this message and leave a '--->' marker, so it's
174 # easier to trace visually the message chain when debugging. Each
182 # easier to trace visually the message chain when debugging. Each
175 # handler prints its message at the end.
183 # handler prints its message at the end.
176 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
184 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
177 self.log.debug(' Content: %s\n --->\n ', msg['content'])
185 self.log.debug(' Content: %s\n --->\n ', msg['content'])
178
186
179 if msg_id in self.aborted:
187 if msg_id in self.aborted:
180 self.aborted.remove(msg_id)
188 self.aborted.remove(msg_id)
181 # is it safe to assume a msg_id will not be resubmitted?
189 # is it safe to assume a msg_id will not be resubmitted?
182 reply_type = msg_type.split('_')[0] + '_reply'
190 reply_type = msg_type.split('_')[0] + '_reply'
183 status = {'status' : 'aborted'}
191 status = {'status' : 'aborted'}
184 md = {'engine' : self.ident}
192 md = {'engine' : self.ident}
185 md.update(status)
193 md.update(status)
186 self.session.send(stream, reply_type, metadata=md,
194 self.session.send(stream, reply_type, metadata=md,
187 content=status, parent=msg, ident=idents)
195 content=status, parent=msg, ident=idents)
188 return
196 return
189
197
190 handler = self.shell_handlers.get(msg_type, None)
198 handler = self.shell_handlers.get(msg_type, None)
191 if handler is None:
199 if handler is None:
192 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
200 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
193 else:
201 else:
194 # ensure default_int_handler during handler call
202 # ensure default_int_handler during handler call
195 sig = signal(SIGINT, default_int_handler)
203 sig = signal(SIGINT, default_int_handler)
196 self.log.debug("%s: %s", msg_type, msg)
204 self.log.debug("%s: %s", msg_type, msg)
197 try:
205 try:
198 handler(stream, idents, msg)
206 handler(stream, idents, msg)
199 except Exception:
207 except Exception:
200 self.log.error("Exception in message handler:", exc_info=True)
208 self.log.error("Exception in message handler:", exc_info=True)
201 finally:
209 finally:
202 signal(SIGINT, sig)
210 signal(SIGINT, sig)
203
211
204 sys.stdout.flush()
212 sys.stdout.flush()
205 sys.stderr.flush()
213 sys.stderr.flush()
206 self._publish_status(u'idle')
214 self._publish_status(u'idle')
207
215
208 def enter_eventloop(self):
216 def enter_eventloop(self):
209 """enter eventloop"""
217 """enter eventloop"""
210 self.log.info("entering eventloop %s", self.eventloop)
218 self.log.info("entering eventloop %s", self.eventloop)
211 for stream in self.shell_streams:
219 for stream in self.shell_streams:
212 # flush any pending replies,
220 # flush any pending replies,
213 # which may be skipped by entering the eventloop
221 # which may be skipped by entering the eventloop
214 stream.flush(zmq.POLLOUT)
222 stream.flush(zmq.POLLOUT)
215 # restore default_int_handler
223 # restore default_int_handler
216 signal(SIGINT, default_int_handler)
224 signal(SIGINT, default_int_handler)
217 while self.eventloop is not None:
225 while self.eventloop is not None:
218 try:
226 try:
219 self.eventloop(self)
227 self.eventloop(self)
220 except KeyboardInterrupt:
228 except KeyboardInterrupt:
221 # Ctrl-C shouldn't crash the kernel
229 # Ctrl-C shouldn't crash the kernel
222 self.log.error("KeyboardInterrupt caught in kernel")
230 self.log.error("KeyboardInterrupt caught in kernel")
223 continue
231 continue
224 else:
232 else:
225 # eventloop exited cleanly, this means we should stop (right?)
233 # eventloop exited cleanly, this means we should stop (right?)
226 self.eventloop = None
234 self.eventloop = None
227 break
235 break
228 self.log.info("exiting eventloop")
236 self.log.info("exiting eventloop")
229
237
230 def start(self):
238 def start(self):
231 """register dispatchers for streams"""
239 """register dispatchers for streams"""
232 if self.control_stream:
240 if self.control_stream:
233 self.control_stream.on_recv(self.dispatch_control, copy=False)
241 self.control_stream.on_recv(self.dispatch_control, copy=False)
234
242
235 def make_dispatcher(stream):
243 def make_dispatcher(stream):
236 def dispatcher(msg):
244 def dispatcher(msg):
237 return self.dispatch_shell(stream, msg)
245 return self.dispatch_shell(stream, msg)
238 return dispatcher
246 return dispatcher
239
247
240 for s in self.shell_streams:
248 for s in self.shell_streams:
241 s.on_recv(make_dispatcher(s), copy=False)
249 s.on_recv(make_dispatcher(s), copy=False)
242
250
243 # publish idle status
251 # publish idle status
244 self._publish_status('starting')
252 self._publish_status('starting')
245
253
246 def do_one_iteration(self):
254 def do_one_iteration(self):
247 """step eventloop just once"""
255 """step eventloop just once"""
248 if self.control_stream:
256 if self.control_stream:
249 self.control_stream.flush()
257 self.control_stream.flush()
250 for stream in self.shell_streams:
258 for stream in self.shell_streams:
251 # handle at most one request per iteration
259 # handle at most one request per iteration
252 stream.flush(zmq.POLLIN, 1)
260 stream.flush(zmq.POLLIN, 1)
253 stream.flush(zmq.POLLOUT)
261 stream.flush(zmq.POLLOUT)
254
262
255
263
256 def record_ports(self, ports):
264 def record_ports(self, ports):
257 """Record the ports that this kernel is using.
265 """Record the ports that this kernel is using.
258
266
259 The creator of the Kernel instance must call this methods if they
267 The creator of the Kernel instance must call this methods if they
260 want the :meth:`connect_request` method to return the port numbers.
268 want the :meth:`connect_request` method to return the port numbers.
261 """
269 """
262 self._recorded_ports = ports
270 self._recorded_ports = ports
263
271
264 #---------------------------------------------------------------------------
272 #---------------------------------------------------------------------------
265 # Kernel request handlers
273 # Kernel request handlers
266 #---------------------------------------------------------------------------
274 #---------------------------------------------------------------------------
267
275
268 def _make_metadata(self, other=None):
276 def _make_metadata(self, other=None):
269 """init metadata dict, for execute/apply_reply"""
277 """init metadata dict, for execute/apply_reply"""
270 new_md = {
278 new_md = {
271 'dependencies_met' : True,
279 'dependencies_met' : True,
272 'engine' : self.ident,
280 'engine' : self.ident,
273 'started': datetime.now(),
281 'started': datetime.now(),
274 }
282 }
275 if other:
283 if other:
276 new_md.update(other)
284 new_md.update(other)
277 return new_md
285 return new_md
278
286
279 def _publish_execute_input(self, code, parent, execution_count):
287 def _publish_execute_input(self, code, parent, execution_count):
280 """Publish the code request on the iopub stream."""
288 """Publish the code request on the iopub stream."""
281
289
282 self.session.send(self.iopub_socket, u'execute_input',
290 self.session.send(self.iopub_socket, u'execute_input',
283 {u'code':code, u'execution_count': execution_count},
291 {u'code':code, u'execution_count': execution_count},
284 parent=parent, ident=self._topic('execute_input')
292 parent=parent, ident=self._topic('execute_input')
285 )
293 )
286
294
287 def _publish_status(self, status, parent=None):
295 def _publish_status(self, status, parent=None):
288 """send status (busy/idle) on IOPub"""
296 """send status (busy/idle) on IOPub"""
289 self.session.send(self.iopub_socket,
297 self.session.send(self.iopub_socket,
290 u'status',
298 u'status',
291 {u'execution_state': status},
299 {u'execution_state': status},
292 parent=parent or self._parent_header,
300 parent=parent or self._parent_header,
293 ident=self._topic('status'),
301 ident=self._topic('status'),
294 )
302 )
295
303
296 def set_parent(self, ident, parent):
304 def set_parent(self, ident, parent):
297 """Set the current parent_header
305 """Set the current parent_header
298
306
299 Side effects (IOPub messages) and replies are associated with
307 Side effects (IOPub messages) and replies are associated with
300 the request that caused them via the parent_header.
308 the request that caused them via the parent_header.
301
309
302 The parent identity is used to route input_request messages
310 The parent identity is used to route input_request messages
303 on the stdin channel.
311 on the stdin channel.
304 """
312 """
305 self._parent_ident = ident
313 self._parent_ident = ident
306 self._parent_header = parent
314 self._parent_header = parent
307
315
308 def send_response(self, stream, msg_or_type, content=None, ident=None,
316 def send_response(self, stream, msg_or_type, content=None, ident=None,
309 buffers=None, track=False, header=None, metadata=None):
317 buffers=None, track=False, header=None, metadata=None):
310 """Send a response to the message we're currently processing.
318 """Send a response to the message we're currently processing.
311
319
312 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
320 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
313 except ``parent``.
321 except ``parent``.
314
322
315 This relies on :meth:`set_parent` having been called for the current
323 This relies on :meth:`set_parent` having been called for the current
316 message.
324 message.
317 """
325 """
318 return self.session.send(stream, msg_or_type, content, self._parent_header,
326 return self.session.send(stream, msg_or_type, content, self._parent_header,
319 ident, buffers, track, header, metadata)
327 ident, buffers, track, header, metadata)
320
328
321 def execute_request(self, stream, ident, parent):
329 def execute_request(self, stream, ident, parent):
322 """handle an execute_request"""
330 """handle an execute_request"""
323
331
324 try:
332 try:
325 content = parent[u'content']
333 content = parent[u'content']
326 code = py3compat.cast_unicode_py2(content[u'code'])
334 code = py3compat.cast_unicode_py2(content[u'code'])
327 silent = content[u'silent']
335 silent = content[u'silent']
328 store_history = content.get(u'store_history', not silent)
336 store_history = content.get(u'store_history', not silent)
329 user_expressions = content.get('user_expressions', {})
337 user_expressions = content.get('user_expressions', {})
330 allow_stdin = content.get('allow_stdin', False)
338 allow_stdin = content.get('allow_stdin', False)
331 except:
339 except:
332 self.log.error("Got bad msg: ")
340 self.log.error("Got bad msg: ")
333 self.log.error("%s", parent)
341 self.log.error("%s", parent)
334 return
342 return
335
343
336 md = self._make_metadata(parent['metadata'])
344 md = self._make_metadata(parent['metadata'])
337
345
338 # Re-broadcast our input for the benefit of listening clients, and
346 # Re-broadcast our input for the benefit of listening clients, and
339 # start computing output
347 # start computing output
340 if not silent:
348 if not silent:
341 self.execution_count += 1
349 self.execution_count += 1
342 self._publish_execute_input(code, parent, self.execution_count)
350 self._publish_execute_input(code, parent, self.execution_count)
343
351
344 reply_content = self.do_execute(code, silent, store_history,
352 reply_content = self.do_execute(code, silent, store_history,
345 user_expressions, allow_stdin)
353 user_expressions, allow_stdin)
346
354
347 # Flush output before sending the reply.
355 # Flush output before sending the reply.
348 sys.stdout.flush()
356 sys.stdout.flush()
349 sys.stderr.flush()
357 sys.stderr.flush()
350 # FIXME: on rare occasions, the flush doesn't seem to make it to the
358 # FIXME: on rare occasions, the flush doesn't seem to make it to the
351 # clients... This seems to mitigate the problem, but we definitely need
359 # clients... This seems to mitigate the problem, but we definitely need
352 # to better understand what's going on.
360 # to better understand what's going on.
353 if self._execute_sleep:
361 if self._execute_sleep:
354 time.sleep(self._execute_sleep)
362 time.sleep(self._execute_sleep)
355
363
356 # Send the reply.
364 # Send the reply.
357 reply_content = json_clean(reply_content)
365 reply_content = json_clean(reply_content)
358
366
359 md['status'] = reply_content['status']
367 md['status'] = reply_content['status']
360 if reply_content['status'] == 'error' and \
368 if reply_content['status'] == 'error' and \
361 reply_content['ename'] == 'UnmetDependency':
369 reply_content['ename'] == 'UnmetDependency':
362 md['dependencies_met'] = False
370 md['dependencies_met'] = False
363
371
364 reply_msg = self.session.send(stream, u'execute_reply',
372 reply_msg = self.session.send(stream, u'execute_reply',
365 reply_content, parent, metadata=md,
373 reply_content, parent, metadata=md,
366 ident=ident)
374 ident=ident)
367
375
368 self.log.debug("%s", reply_msg)
376 self.log.debug("%s", reply_msg)
369
377
370 if not silent and reply_msg['content']['status'] == u'error':
378 if not silent and reply_msg['content']['status'] == u'error':
371 self._abort_queues()
379 self._abort_queues()
372
380
373 def do_execute(self, code, silent, store_history=True,
381 def do_execute(self, code, silent, store_history=True,
374 user_experssions=None, allow_stdin=False):
382 user_experssions=None, allow_stdin=False):
375 """Execute user code. Must be overridden by subclasses.
383 """Execute user code. Must be overridden by subclasses.
376 """
384 """
377 raise NotImplementedError
385 raise NotImplementedError
378
386
379 def complete_request(self, stream, ident, parent):
387 def complete_request(self, stream, ident, parent):
380 content = parent['content']
388 content = parent['content']
381 code = content['code']
389 code = content['code']
382 cursor_pos = content['cursor_pos']
390 cursor_pos = content['cursor_pos']
383
391
384 matches = self.do_complete(code, cursor_pos)
392 matches = self.do_complete(code, cursor_pos)
385 matches = json_clean(matches)
393 matches = json_clean(matches)
386 completion_msg = self.session.send(stream, 'complete_reply',
394 completion_msg = self.session.send(stream, 'complete_reply',
387 matches, parent, ident)
395 matches, parent, ident)
388 self.log.debug("%s", completion_msg)
396 self.log.debug("%s", completion_msg)
389
397
390 def do_complete(self, code, cursor_pos):
398 def do_complete(self, code, cursor_pos):
391 """Override in subclasses to find completions.
399 """Override in subclasses to find completions.
392 """
400 """
393 return {'matches' : [],
401 return {'matches' : [],
394 'cursor_end' : cursor_pos,
402 'cursor_end' : cursor_pos,
395 'cursor_start' : cursor_pos,
403 'cursor_start' : cursor_pos,
396 'metadata' : {},
404 'metadata' : {},
397 'status' : 'ok'}
405 'status' : 'ok'}
398
406
399 def inspect_request(self, stream, ident, parent):
407 def inspect_request(self, stream, ident, parent):
400 content = parent['content']
408 content = parent['content']
401
409
402 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
410 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
403 content.get('detail_level', 0))
411 content.get('detail_level', 0))
404 # Before we send this object over, we scrub it for JSON usage
412 # Before we send this object over, we scrub it for JSON usage
405 reply_content = json_clean(reply_content)
413 reply_content = json_clean(reply_content)
406 msg = self.session.send(stream, 'inspect_reply',
414 msg = self.session.send(stream, 'inspect_reply',
407 reply_content, parent, ident)
415 reply_content, parent, ident)
408 self.log.debug("%s", msg)
416 self.log.debug("%s", msg)
409
417
410 def do_inspect(self, code, cursor_pos, detail_level=0):
418 def do_inspect(self, code, cursor_pos, detail_level=0):
411 """Override in subclasses to allow introspection.
419 """Override in subclasses to allow introspection.
412 """
420 """
413 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
421 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
414
422
415 def history_request(self, stream, ident, parent):
423 def history_request(self, stream, ident, parent):
416 content = parent['content']
424 content = parent['content']
417
425
418 reply_content = self.do_history(**content)
426 reply_content = self.do_history(**content)
419
427
420 reply_content = json_clean(reply_content)
428 reply_content = json_clean(reply_content)
421 msg = self.session.send(stream, 'history_reply',
429 msg = self.session.send(stream, 'history_reply',
422 reply_content, parent, ident)
430 reply_content, parent, ident)
423 self.log.debug("%s", msg)
431 self.log.debug("%s", msg)
424
432
425 def do_history(self, hist_access_type, output, raw, session=None, start=None,
433 def do_history(self, hist_access_type, output, raw, session=None, start=None,
426 stop=None, n=None, pattern=None, unique=False):
434 stop=None, n=None, pattern=None, unique=False):
427 """Override in subclasses to access history.
435 """Override in subclasses to access history.
428 """
436 """
429 return {'history': []}
437 return {'history': []}
430
438
431 def connect_request(self, stream, ident, parent):
439 def connect_request(self, stream, ident, parent):
432 if self._recorded_ports is not None:
440 if self._recorded_ports is not None:
433 content = self._recorded_ports.copy()
441 content = self._recorded_ports.copy()
434 else:
442 else:
435 content = {}
443 content = {}
436 msg = self.session.send(stream, 'connect_reply',
444 msg = self.session.send(stream, 'connect_reply',
437 content, parent, ident)
445 content, parent, ident)
438 self.log.debug("%s", msg)
446 self.log.debug("%s", msg)
439
447
440 @property
448 @property
441 def kernel_info(self):
449 def kernel_info(self):
442 return {
450 return {
443 'protocol_version': release.kernel_protocol_version,
451 'protocol_version': release.kernel_protocol_version,
444 'implementation': self.implementation,
452 'implementation': self.implementation,
445 'implementation_version': self.implementation_version,
453 'implementation_version': self.implementation_version,
446 'language': self.language,
454 'language': self.language,
447 'language_version': self.language_version,
455 'language_version': self.language_version,
448 'banner': self.banner,
456 'banner': self.banner,
449 }
457 }
450
458
451 def kernel_info_request(self, stream, ident, parent):
459 def kernel_info_request(self, stream, ident, parent):
452 msg = self.session.send(stream, 'kernel_info_reply',
460 msg = self.session.send(stream, 'kernel_info_reply',
453 self.kernel_info, parent, ident)
461 self.kernel_info, parent, ident)
454 self.log.debug("%s", msg)
462 self.log.debug("%s", msg)
455
463
456 def shutdown_request(self, stream, ident, parent):
464 def shutdown_request(self, stream, ident, parent):
457 content = self.do_shutdown(parent['content']['restart'])
465 content = self.do_shutdown(parent['content']['restart'])
458 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
466 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
459 # same content, but different msg_id for broadcasting on IOPub
467 # same content, but different msg_id for broadcasting on IOPub
460 self._shutdown_message = self.session.msg(u'shutdown_reply',
468 self._shutdown_message = self.session.msg(u'shutdown_reply',
461 content, parent
469 content, parent
462 )
470 )
463
471
464 self._at_shutdown()
472 self._at_shutdown()
465 # call sys.exit after a short delay
473 # call sys.exit after a short delay
466 loop = ioloop.IOLoop.instance()
474 loop = ioloop.IOLoop.instance()
467 loop.add_timeout(time.time()+0.1, loop.stop)
475 loop.add_timeout(time.time()+0.1, loop.stop)
468
476
469 def do_shutdown(self, restart):
477 def do_shutdown(self, restart):
470 """Override in subclasses to do things when the frontend shuts down the
478 """Override in subclasses to do things when the frontend shuts down the
471 kernel.
479 kernel.
472 """
480 """
473 return {'status': 'ok', 'restart': restart}
481 return {'status': 'ok', 'restart': restart}
474
482
475 #---------------------------------------------------------------------------
483 #---------------------------------------------------------------------------
476 # Engine methods
484 # Engine methods
477 #---------------------------------------------------------------------------
485 #---------------------------------------------------------------------------
478
486
479 def apply_request(self, stream, ident, parent):
487 def apply_request(self, stream, ident, parent):
480 try:
488 try:
481 content = parent[u'content']
489 content = parent[u'content']
482 bufs = parent[u'buffers']
490 bufs = parent[u'buffers']
483 msg_id = parent['header']['msg_id']
491 msg_id = parent['header']['msg_id']
484 except:
492 except:
485 self.log.error("Got bad msg: %s", parent, exc_info=True)
493 self.log.error("Got bad msg: %s", parent, exc_info=True)
486 return
494 return
487
495
488 md = self._make_metadata(parent['metadata'])
496 md = self._make_metadata(parent['metadata'])
489
497
490 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
498 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
491
499
492 # put 'ok'/'error' status in header, for scheduler introspection:
500 # put 'ok'/'error' status in header, for scheduler introspection:
493 md['status'] = reply_content['status']
501 md['status'] = reply_content['status']
494
502
495 # flush i/o
503 # flush i/o
496 sys.stdout.flush()
504 sys.stdout.flush()
497 sys.stderr.flush()
505 sys.stderr.flush()
498
506
499 self.session.send(stream, u'apply_reply', reply_content,
507 self.session.send(stream, u'apply_reply', reply_content,
500 parent=parent, ident=ident,buffers=result_buf, metadata=md)
508 parent=parent, ident=ident,buffers=result_buf, metadata=md)
501
509
502 def do_apply(self, content, bufs, msg_id, reply_metadata):
510 def do_apply(self, content, bufs, msg_id, reply_metadata):
503 """Override in subclasses to support the IPython parallel framework.
511 """Override in subclasses to support the IPython parallel framework.
504 """
512 """
505 raise NotImplementedError
513 raise NotImplementedError
506
514
507 #---------------------------------------------------------------------------
515 #---------------------------------------------------------------------------
508 # Control messages
516 # Control messages
509 #---------------------------------------------------------------------------
517 #---------------------------------------------------------------------------
510
518
511 def abort_request(self, stream, ident, parent):
519 def abort_request(self, stream, ident, parent):
512 """abort a specifig msg by id"""
520 """abort a specifig msg by id"""
513 msg_ids = parent['content'].get('msg_ids', None)
521 msg_ids = parent['content'].get('msg_ids', None)
514 if isinstance(msg_ids, string_types):
522 if isinstance(msg_ids, string_types):
515 msg_ids = [msg_ids]
523 msg_ids = [msg_ids]
516 if not msg_ids:
524 if not msg_ids:
517 self.abort_queues()
525 self.abort_queues()
518 for mid in msg_ids:
526 for mid in msg_ids:
519 self.aborted.add(str(mid))
527 self.aborted.add(str(mid))
520
528
521 content = dict(status='ok')
529 content = dict(status='ok')
522 reply_msg = self.session.send(stream, 'abort_reply', content=content,
530 reply_msg = self.session.send(stream, 'abort_reply', content=content,
523 parent=parent, ident=ident)
531 parent=parent, ident=ident)
524 self.log.debug("%s", reply_msg)
532 self.log.debug("%s", reply_msg)
525
533
526 def clear_request(self, stream, idents, parent):
534 def clear_request(self, stream, idents, parent):
527 """Clear our namespace."""
535 """Clear our namespace."""
528 content = self.do_clear()
536 content = self.do_clear()
529 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
537 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
530 content = content)
538 content = content)
531
539
532 def do_clear(self):
540 def do_clear(self):
533 """Override in subclasses to clear the namespace
541 """Override in subclasses to clear the namespace
534
542
535 This is only required for IPython.parallel.
543 This is only required for IPython.parallel.
536 """
544 """
537 raise NotImplementedError
545 raise NotImplementedError
538
546
539 #---------------------------------------------------------------------------
547 #---------------------------------------------------------------------------
540 # Protected interface
548 # Protected interface
541 #---------------------------------------------------------------------------
549 #---------------------------------------------------------------------------
542
550
543 def _topic(self, topic):
551 def _topic(self, topic):
544 """prefixed topic for IOPub messages"""
552 """prefixed topic for IOPub messages"""
545 if self.int_id >= 0:
553 if self.int_id >= 0:
546 base = "engine.%i" % self.int_id
554 base = "engine.%i" % self.int_id
547 else:
555 else:
548 base = "kernel.%s" % self.ident
556 base = "kernel.%s" % self.ident
549
557
550 return py3compat.cast_bytes("%s.%s" % (base, topic))
558 return py3compat.cast_bytes("%s.%s" % (base, topic))
551
559
552 def _abort_queues(self):
560 def _abort_queues(self):
553 for stream in self.shell_streams:
561 for stream in self.shell_streams:
554 if stream:
562 if stream:
555 self._abort_queue(stream)
563 self._abort_queue(stream)
556
564
557 def _abort_queue(self, stream):
565 def _abort_queue(self, stream):
558 poller = zmq.Poller()
566 poller = zmq.Poller()
559 poller.register(stream.socket, zmq.POLLIN)
567 poller.register(stream.socket, zmq.POLLIN)
560 while True:
568 while True:
561 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
569 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
562 if msg is None:
570 if msg is None:
563 return
571 return
564
572
565 self.log.info("Aborting:")
573 self.log.info("Aborting:")
566 self.log.info("%s", msg)
574 self.log.info("%s", msg)
567 msg_type = msg['header']['msg_type']
575 msg_type = msg['header']['msg_type']
568 reply_type = msg_type.split('_')[0] + '_reply'
576 reply_type = msg_type.split('_')[0] + '_reply'
569
577
570 status = {'status' : 'aborted'}
578 status = {'status' : 'aborted'}
571 md = {'engine' : self.ident}
579 md = {'engine' : self.ident}
572 md.update(status)
580 md.update(status)
573 reply_msg = self.session.send(stream, reply_type, metadata=md,
581 reply_msg = self.session.send(stream, reply_type, metadata=md,
574 content=status, parent=msg, ident=idents)
582 content=status, parent=msg, ident=idents)
575 self.log.debug("%s", reply_msg)
583 self.log.debug("%s", reply_msg)
576 # We need to wait a bit for requests to come in. This can probably
584 # We need to wait a bit for requests to come in. This can probably
577 # be set shorter for true asynchronous clients.
585 # be set shorter for true asynchronous clients.
578 poller.poll(50)
586 poller.poll(50)
579
587
580
588
581 def _no_raw_input(self):
589 def _no_raw_input(self):
582 """Raise StdinNotImplentedError if active frontend doesn't support
590 """Raise StdinNotImplentedError if active frontend doesn't support
583 stdin."""
591 stdin."""
584 raise StdinNotImplementedError("raw_input was called, but this "
592 raise StdinNotImplementedError("raw_input was called, but this "
585 "frontend does not support stdin.")
593 "frontend does not support stdin.")
586
594
587 def getpass(self, prompt=''):
595 def getpass(self, prompt=''):
588 """Forward getpass to frontends
596 """Forward getpass to frontends
589
597
590 Raises
598 Raises
591 ------
599 ------
592 StdinNotImplentedError if active frontend doesn't support stdin.
600 StdinNotImplentedError if active frontend doesn't support stdin.
593 """
601 """
594 if not self._allow_stdin:
602 if not self._allow_stdin:
595 raise StdinNotImplementedError(
603 raise StdinNotImplementedError(
596 "getpass was called, but this frontend does not support input requests."
604 "getpass was called, but this frontend does not support input requests."
597 )
605 )
598 return self._input_request(prompt,
606 return self._input_request(prompt,
599 self._parent_ident,
607 self._parent_ident,
600 self._parent_header,
608 self._parent_header,
601 password=True,
609 password=True,
602 )
610 )
603
611
604 def raw_input(self, prompt=''):
612 def raw_input(self, prompt=''):
605 """Forward raw_input to frontends
613 """Forward raw_input to frontends
606
614
607 Raises
615 Raises
608 ------
616 ------
609 StdinNotImplentedError if active frontend doesn't support stdin.
617 StdinNotImplentedError if active frontend doesn't support stdin.
610 """
618 """
611 if not self._allow_stdin:
619 if not self._allow_stdin:
612 raise StdinNotImplementedError(
620 raise StdinNotImplementedError(
613 "raw_input was called, but this frontend does not support input requests."
621 "raw_input was called, but this frontend does not support input requests."
614 )
622 )
615 return self._input_request(prompt,
623 return self._input_request(prompt,
616 self._parent_ident,
624 self._parent_ident,
617 self._parent_header,
625 self._parent_header,
618 password=False,
626 password=False,
619 )
627 )
620
628
621 def _input_request(self, prompt, ident, parent, password=False):
629 def _input_request(self, prompt, ident, parent, password=False):
622 # Flush output before making the request.
630 # Flush output before making the request.
623 sys.stderr.flush()
631 sys.stderr.flush()
624 sys.stdout.flush()
632 sys.stdout.flush()
625 # flush the stdin socket, to purge stale replies
633 # flush the stdin socket, to purge stale replies
626 while True:
634 while True:
627 try:
635 try:
628 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
636 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
629 except zmq.ZMQError as e:
637 except zmq.ZMQError as e:
630 if e.errno == zmq.EAGAIN:
638 if e.errno == zmq.EAGAIN:
631 break
639 break
632 else:
640 else:
633 raise
641 raise
634
642
635 # Send the input request.
643 # Send the input request.
636 content = json_clean(dict(prompt=prompt, password=password))
644 content = json_clean(dict(prompt=prompt, password=password))
637 self.session.send(self.stdin_socket, u'input_request', content, parent,
645 self.session.send(self.stdin_socket, u'input_request', content, parent,
638 ident=ident)
646 ident=ident)
639
647
640 # Await a response.
648 # Await a response.
641 while True:
649 while True:
642 try:
650 try:
643 ident, reply = self.session.recv(self.stdin_socket, 0)
651 ident, reply = self.session.recv(self.stdin_socket, 0)
644 except Exception:
652 except Exception:
645 self.log.warn("Invalid Message:", exc_info=True)
653 self.log.warn("Invalid Message:", exc_info=True)
646 except KeyboardInterrupt:
654 except KeyboardInterrupt:
647 # re-raise KeyboardInterrupt, to truncate traceback
655 # re-raise KeyboardInterrupt, to truncate traceback
648 raise KeyboardInterrupt
656 raise KeyboardInterrupt
649 else:
657 else:
650 break
658 break
651 try:
659 try:
652 value = py3compat.unicode_to_str(reply['content']['value'])
660 value = py3compat.unicode_to_str(reply['content']['value'])
653 except:
661 except:
654 self.log.error("Bad input_reply: %s", parent)
662 self.log.error("Bad input_reply: %s", parent)
655 value = ''
663 value = ''
656 if value == '\x04':
664 if value == '\x04':
657 # EOF
665 # EOF
658 raise EOFError
666 raise EOFError
659 return value
667 return value
660
668
661 def _at_shutdown(self):
669 def _at_shutdown(self):
662 """Actions taken at shutdown by the kernel, called by python's atexit.
670 """Actions taken at shutdown by the kernel, called by python's atexit.
663 """
671 """
664 # io.rprint("Kernel at_shutdown") # dbg
672 # io.rprint("Kernel at_shutdown") # dbg
665 if self._shutdown_message is not None:
673 if self._shutdown_message is not None:
666 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
674 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
667 self.log.debug("%s", self._shutdown_message)
675 self.log.debug("%s", self._shutdown_message)
668 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
676 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
669
677
@@ -1,1063 +1,1063 b''
1 .. _messaging:
1 .. _messaging:
2
2
3 ======================
3 ======================
4 Messaging in IPython
4 Messaging in IPython
5 ======================
5 ======================
6
6
7
7
8 Versioning
8 Versioning
9 ==========
9 ==========
10
10
11 The IPython message specification is versioned independently of IPython.
11 The IPython message specification is versioned independently of IPython.
12 The current version of the specification is 5.0.
12 The current version of the specification is 5.0.
13
13
14
14
15 Introduction
15 Introduction
16 ============
16 ============
17
17
18 This document explains the basic communications design and messaging
18 This document explains the basic communications design and messaging
19 specification for how the various IPython objects interact over a network
19 specification for how the various IPython objects interact over a network
20 transport. The current implementation uses the ZeroMQ_ library for messaging
20 transport. The current implementation uses the ZeroMQ_ library for messaging
21 within and between hosts.
21 within and between hosts.
22
22
23 .. Note::
23 .. Note::
24
24
25 This document should be considered the authoritative description of the
25 This document should be considered the authoritative description of the
26 IPython messaging protocol, and all developers are strongly encouraged to
26 IPython messaging protocol, and all developers are strongly encouraged to
27 keep it updated as the implementation evolves, so that we have a single
27 keep it updated as the implementation evolves, so that we have a single
28 common reference for all protocol details.
28 common reference for all protocol details.
29
29
30 The basic design is explained in the following diagram:
30 The basic design is explained in the following diagram:
31
31
32 .. image:: figs/frontend-kernel.png
32 .. image:: figs/frontend-kernel.png
33 :width: 450px
33 :width: 450px
34 :alt: IPython kernel/frontend messaging architecture.
34 :alt: IPython kernel/frontend messaging architecture.
35 :align: center
35 :align: center
36 :target: ../_images/frontend-kernel.png
36 :target: ../_images/frontend-kernel.png
37
37
38 A single kernel can be simultaneously connected to one or more frontends. The
38 A single kernel can be simultaneously connected to one or more frontends. The
39 kernel has three sockets that serve the following functions:
39 kernel has three sockets that serve the following functions:
40
40
41 1. Shell: this single ROUTER socket allows multiple incoming connections from
41 1. Shell: this single ROUTER socket allows multiple incoming connections from
42 frontends, and this is the socket where requests for code execution, object
42 frontends, and this is the socket where requests for code execution, object
43 information, prompts, etc. are made to the kernel by any frontend. The
43 information, prompts, etc. are made to the kernel by any frontend. The
44 communication on this socket is a sequence of request/reply actions from
44 communication on this socket is a sequence of request/reply actions from
45 each frontend and the kernel.
45 each frontend and the kernel.
46
46
47 2. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
47 2. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
48 side effects (stdout, stderr, etc.) as well as the requests coming from any
48 side effects (stdout, stderr, etc.) as well as the requests coming from any
49 client over the shell socket and its own requests on the stdin socket. There
49 client over the shell socket and its own requests on the stdin socket. There
50 are a number of actions in Python which generate side effects: :func:`print`
50 are a number of actions in Python which generate side effects: :func:`print`
51 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
51 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
52 a multi-client scenario, we want all frontends to be able to know what each
52 a multi-client scenario, we want all frontends to be able to know what each
53 other has sent to the kernel (this can be useful in collaborative scenarios,
53 other has sent to the kernel (this can be useful in collaborative scenarios,
54 for example). This socket allows both side effects and the information
54 for example). This socket allows both side effects and the information
55 about communications taking place with one client over the shell channel
55 about communications taking place with one client over the shell channel
56 to be made available to all clients in a uniform manner.
56 to be made available to all clients in a uniform manner.
57
57
58 3. stdin: this ROUTER socket is connected to all frontends, and it allows
58 3. stdin: this ROUTER socket is connected to all frontends, and it allows
59 the kernel to request input from the active frontend when :func:`raw_input` is called.
59 the kernel to request input from the active frontend when :func:`raw_input` is called.
60 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
60 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
61 for the kernel while this communication is happening (illustrated in the
61 for the kernel while this communication is happening (illustrated in the
62 figure by the black outline around the central keyboard). In practice,
62 figure by the black outline around the central keyboard). In practice,
63 frontends may display such kernel requests using a special input widget or
63 frontends may display such kernel requests using a special input widget or
64 otherwise indicating that the user is to type input for the kernel instead
64 otherwise indicating that the user is to type input for the kernel instead
65 of normal commands in the frontend.
65 of normal commands in the frontend.
66
66
67 All messages are tagged with enough information (details below) for clients
67 All messages are tagged with enough information (details below) for clients
68 to know which messages come from their own interaction with the kernel and
68 to know which messages come from their own interaction with the kernel and
69 which ones are from other clients, so they can display each type
69 which ones are from other clients, so they can display each type
70 appropriately.
70 appropriately.
71
71
72 4. Control: This channel is identical to Shell, but operates on a separate socket,
72 4. Control: This channel is identical to Shell, but operates on a separate socket,
73 to allow important messages to avoid queueing behind execution requests (e.g. shutdown or abort).
73 to allow important messages to avoid queueing behind execution requests (e.g. shutdown or abort).
74
74
75 The actual format of the messages allowed on each of these channels is
75 The actual format of the messages allowed on each of these channels is
76 specified below. Messages are dicts of dicts with string keys and values that
76 specified below. Messages are dicts of dicts with string keys and values that
77 are reasonably representable in JSON. Our current implementation uses JSON
77 are reasonably representable in JSON. Our current implementation uses JSON
78 explicitly as its message format, but this shouldn't be considered a permanent
78 explicitly as its message format, but this shouldn't be considered a permanent
79 feature. As we've discovered that JSON has non-trivial performance issues due
79 feature. As we've discovered that JSON has non-trivial performance issues due
80 to excessive copying, we may in the future move to a pure pickle-based raw
80 to excessive copying, we may in the future move to a pure pickle-based raw
81 message format. However, it should be possible to easily convert from the raw
81 message format. However, it should be possible to easily convert from the raw
82 objects to JSON, since we may have non-python clients (e.g. a web frontend).
82 objects to JSON, since we may have non-python clients (e.g. a web frontend).
83 As long as it's easy to make a JSON version of the objects that is a faithful
83 As long as it's easy to make a JSON version of the objects that is a faithful
84 representation of all the data, we can communicate with such clients.
84 representation of all the data, we can communicate with such clients.
85
85
86 .. Note::
86 .. Note::
87
87
88 Not all of these have yet been fully fleshed out, but the key ones are, see
88 Not all of these have yet been fully fleshed out, but the key ones are, see
89 kernel and frontend files for actual implementation details.
89 kernel and frontend files for actual implementation details.
90
90
91 General Message Format
91 General Message Format
92 ======================
92 ======================
93
93
94 A message is defined by the following four-dictionary structure::
94 A message is defined by the following four-dictionary structure::
95
95
96 {
96 {
97 # The message header contains a pair of unique identifiers for the
97 # The message header contains a pair of unique identifiers for the
98 # originating session and the actual message id, in addition to the
98 # originating session and the actual message id, in addition to the
99 # username for the process that generated the message. This is useful in
99 # username for the process that generated the message. This is useful in
100 # collaborative settings where multiple users may be interacting with the
100 # collaborative settings where multiple users may be interacting with the
101 # same kernel simultaneously, so that frontends can label the various
101 # same kernel simultaneously, so that frontends can label the various
102 # messages in a meaningful way.
102 # messages in a meaningful way.
103 'header' : {
103 'header' : {
104 'msg_id' : uuid,
104 'msg_id' : uuid,
105 'username' : str,
105 'username' : str,
106 'session' : uuid,
106 'session' : uuid,
107 # All recognized message type strings are listed below.
107 # All recognized message type strings are listed below.
108 'msg_type' : str,
108 'msg_type' : str,
109 # the message protocol version
109 # the message protocol version
110 'version' : '5.0',
110 'version' : '5.0',
111 },
111 },
112
112
113 # In a chain of messages, the header from the parent is copied so that
113 # In a chain of messages, the header from the parent is copied so that
114 # clients can track where messages come from.
114 # clients can track where messages come from.
115 'parent_header' : dict,
115 'parent_header' : dict,
116
116
117 # Any metadata associated with the message.
117 # Any metadata associated with the message.
118 'metadata' : dict,
118 'metadata' : dict,
119
119
120 # The actual content of the message must be a dict, whose structure
120 # The actual content of the message must be a dict, whose structure
121 # depends on the message type.
121 # depends on the message type.
122 'content' : dict,
122 'content' : dict,
123 }
123 }
124
124
125 .. versionchanged:: 5.0
125 .. versionchanged:: 5.0
126
126
127 ``version`` key added to the header.
127 ``version`` key added to the header.
128
128
129 The Wire Protocol
129 The Wire Protocol
130 =================
130 =================
131
131
132
132
133 This message format exists at a high level,
133 This message format exists at a high level,
134 but does not describe the actual *implementation* at the wire level in zeromq.
134 but does not describe the actual *implementation* at the wire level in zeromq.
135 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
135 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
136
136
137 .. note::
137 .. note::
138
138
139 This section should only be relevant to non-Python consumers of the protocol.
139 This section should only be relevant to non-Python consumers of the protocol.
140 Python consumers should simply import and use IPython's own implementation of the wire protocol
140 Python consumers should simply import and use IPython's own implementation of the wire protocol
141 in the :class:`IPython.kernel.zmq.session.Session` object.
141 in the :class:`IPython.kernel.zmq.session.Session` object.
142
142
143 Every message is serialized to a sequence of at least six blobs of bytes:
143 Every message is serialized to a sequence of at least six blobs of bytes:
144
144
145 .. sourcecode:: python
145 .. sourcecode:: python
146
146
147 [
147 [
148 b'u-u-i-d', # zmq identity(ies)
148 b'u-u-i-d', # zmq identity(ies)
149 b'<IDS|MSG>', # delimiter
149 b'<IDS|MSG>', # delimiter
150 b'baddad42', # HMAC signature
150 b'baddad42', # HMAC signature
151 b'{header}', # serialized header dict
151 b'{header}', # serialized header dict
152 b'{parent_header}', # serialized parent header dict
152 b'{parent_header}', # serialized parent header dict
153 b'{metadata}', # serialized metadata dict
153 b'{metadata}', # serialized metadata dict
154 b'{content}, # serialized content dict
154 b'{content}, # serialized content dict
155 b'blob', # extra raw data buffer(s)
155 b'blob', # extra raw data buffer(s)
156 ...
156 ...
157 ]
157 ]
158
158
159 The front of the message is the ZeroMQ routing prefix,
159 The front of the message is the ZeroMQ routing prefix,
160 which can be zero or more socket identities.
160 which can be zero or more socket identities.
161 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
161 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
162 In the case of IOPub, there should be just one prefix component,
162 In the case of IOPub, there should be just one prefix component,
163 which is the topic for IOPub subscribers, e.g. ``execute_result``, ``display_data``.
163 which is the topic for IOPub subscribers, e.g. ``execute_result``, ``display_data``.
164
164
165 .. note::
165 .. note::
166
166
167 In most cases, the IOPub topics are irrelevant and completely ignored,
167 In most cases, the IOPub topics are irrelevant and completely ignored,
168 because frontends just subscribe to all topics.
168 because frontends just subscribe to all topics.
169 The convention used in the IPython kernel is to use the msg_type as the topic,
169 The convention used in the IPython kernel is to use the msg_type as the topic,
170 and possibly extra information about the message, e.g. ``execute_result`` or ``stream.stdout``
170 and possibly extra information about the message, e.g. ``execute_result`` or ``stream.stdout``
171
171
172 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
172 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
173 If authentication is disabled, this should be an empty string.
173 If authentication is disabled, this should be an empty string.
174 By default, the hashing function used for computing these signatures is sha256.
174 By default, the hashing function used for computing these signatures is sha256.
175
175
176 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
176 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
177
177
178 .. note::
178 .. note::
179
179
180 To disable authentication and signature checking,
180 To disable authentication and signature checking,
181 set the `key` field of a connection file to an empty string.
181 set the `key` field of a connection file to an empty string.
182
182
183 The signature is the HMAC hex digest of the concatenation of:
183 The signature is the HMAC hex digest of the concatenation of:
184
184
185 - A shared key (typically the ``key`` field of a connection file)
185 - A shared key (typically the ``key`` field of a connection file)
186 - The serialized header dict
186 - The serialized header dict
187 - The serialized parent header dict
187 - The serialized parent header dict
188 - The serialized metadata dict
188 - The serialized metadata dict
189 - The serialized content dict
189 - The serialized content dict
190
190
191 In Python, this is implemented via:
191 In Python, this is implemented via:
192
192
193 .. sourcecode:: python
193 .. sourcecode:: python
194
194
195 # once:
195 # once:
196 digester = HMAC(key, digestmod=hashlib.sha256)
196 digester = HMAC(key, digestmod=hashlib.sha256)
197
197
198 # for each message
198 # for each message
199 d = digester.copy()
199 d = digester.copy()
200 for serialized_dict in (header, parent, metadata, content):
200 for serialized_dict in (header, parent, metadata, content):
201 d.update(serialized_dict)
201 d.update(serialized_dict)
202 signature = d.hexdigest()
202 signature = d.hexdigest()
203
203
204 After the signature is the actual message, always in four frames of bytes.
204 After the signature is the actual message, always in four frames of bytes.
205 The four dictionaries that compose a message are serialized separately,
205 The four dictionaries that compose a message are serialized separately,
206 in the order of header, parent header, metadata, and content.
206 in the order of header, parent header, metadata, and content.
207 These can be serialized by any function that turns a dict into bytes.
207 These can be serialized by any function that turns a dict into bytes.
208 The default and most common serialization is JSON, but msgpack and pickle
208 The default and most common serialization is JSON, but msgpack and pickle
209 are common alternatives.
209 are common alternatives.
210
210
211 After the serialized dicts are zero to many raw data buffers,
211 After the serialized dicts are zero to many raw data buffers,
212 which can be used by message types that support binary data (mainly apply and data_pub).
212 which can be used by message types that support binary data (mainly apply and data_pub).
213
213
214
214
215 Python functional API
215 Python functional API
216 =====================
216 =====================
217
217
218 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
218 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
219 should develop, at a few key points, functional forms of all the requests that
219 should develop, at a few key points, functional forms of all the requests that
220 take arguments in this manner and automatically construct the necessary dict
220 take arguments in this manner and automatically construct the necessary dict
221 for sending.
221 for sending.
222
222
223 In addition, the Python implementation of the message specification extends
223 In addition, the Python implementation of the message specification extends
224 messages upon deserialization to the following form for convenience::
224 messages upon deserialization to the following form for convenience::
225
225
226 {
226 {
227 'header' : dict,
227 'header' : dict,
228 # The msg's unique identifier and type are always stored in the header,
228 # The msg's unique identifier and type are always stored in the header,
229 # but the Python implementation copies them to the top level.
229 # but the Python implementation copies them to the top level.
230 'msg_id' : uuid,
230 'msg_id' : uuid,
231 'msg_type' : str,
231 'msg_type' : str,
232 'parent_header' : dict,
232 'parent_header' : dict,
233 'content' : dict,
233 'content' : dict,
234 'metadata' : dict,
234 'metadata' : dict,
235 }
235 }
236
236
237 All messages sent to or received by any IPython process should have this
237 All messages sent to or received by any IPython process should have this
238 extended structure.
238 extended structure.
239
239
240
240
241 Messages on the shell ROUTER/DEALER sockets
241 Messages on the shell ROUTER/DEALER sockets
242 ===========================================
242 ===========================================
243
243
244 .. _execute:
244 .. _execute:
245
245
246 Execute
246 Execute
247 -------
247 -------
248
248
249 This message type is used by frontends to ask the kernel to execute code on
249 This message type is used by frontends to ask the kernel to execute code on
250 behalf of the user, in a namespace reserved to the user's variables (and thus
250 behalf of the user, in a namespace reserved to the user's variables (and thus
251 separate from the kernel's own internal code and variables).
251 separate from the kernel's own internal code and variables).
252
252
253 Message type: ``execute_request``::
253 Message type: ``execute_request``::
254
254
255 content = {
255 content = {
256 # Source code to be executed by the kernel, one or more lines.
256 # Source code to be executed by the kernel, one or more lines.
257 'code' : str,
257 'code' : str,
258
258
259 # A boolean flag which, if True, signals the kernel to execute
259 # A boolean flag which, if True, signals the kernel to execute
260 # this code as quietly as possible.
260 # this code as quietly as possible.
261 # silent=True forces store_history to be False,
261 # silent=True forces store_history to be False,
262 # and will *not*:
262 # and will *not*:
263 # - broadcast output on the IOPUB channel
263 # - broadcast output on the IOPUB channel
264 # - have an execute_result
264 # - have an execute_result
265 # The default is False.
265 # The default is False.
266 'silent' : bool,
266 'silent' : bool,
267
267
268 # A boolean flag which, if True, signals the kernel to populate history
268 # A boolean flag which, if True, signals the kernel to populate history
269 # The default is True if silent is False. If silent is True, store_history
269 # The default is True if silent is False. If silent is True, store_history
270 # is forced to be False.
270 # is forced to be False.
271 'store_history' : bool,
271 'store_history' : bool,
272
272
273 # A dict mapping names to expressions to be evaluated in the
273 # A dict mapping names to expressions to be evaluated in the
274 # user's dict. The rich display-data representation of each will be evaluated after execution.
274 # user's dict. The rich display-data representation of each will be evaluated after execution.
275 # See the display_data content for the structure of the representation data.
275 # See the display_data content for the structure of the representation data.
276 'user_expressions' : dict,
276 'user_expressions' : dict,
277
277
278 # Some frontends do not support stdin requests.
278 # Some frontends do not support stdin requests.
279 # If raw_input is called from code executed from such a frontend,
279 # If raw_input is called from code executed from such a frontend,
280 # a StdinNotImplementedError will be raised.
280 # a StdinNotImplementedError will be raised.
281 'allow_stdin' : True,
281 'allow_stdin' : True,
282 }
282 }
283
283
284 .. versionchanged:: 5.0
284 .. versionchanged:: 5.0
285
285
286 ``user_variables`` removed, because it is redundant with user_expressions.
286 ``user_variables`` removed, because it is redundant with user_expressions.
287
287
288 The ``code`` field contains a single string (possibly multiline) to be executed.
288 The ``code`` field contains a single string (possibly multiline) to be executed.
289
289
290 The ``user_expressions`` field deserves a detailed explanation. In the past, IPython had
290 The ``user_expressions`` field deserves a detailed explanation. In the past, IPython had
291 the notion of a prompt string that allowed arbitrary code to be evaluated, and
291 the notion of a prompt string that allowed arbitrary code to be evaluated, and
292 this was put to good use by many in creating prompts that displayed system
292 this was put to good use by many in creating prompts that displayed system
293 status, path information, and even more esoteric uses like remote instrument
293 status, path information, and even more esoteric uses like remote instrument
294 status acquired over the network. But now that IPython has a clean separation
294 status acquired over the network. But now that IPython has a clean separation
295 between the kernel and the clients, the kernel has no prompt knowledge; prompts
295 between the kernel and the clients, the kernel has no prompt knowledge; prompts
296 are a frontend feature, and it should be even possible for different
296 are a frontend feature, and it should be even possible for different
297 frontends to display different prompts while interacting with the same kernel.
297 frontends to display different prompts while interacting with the same kernel.
298 ``user_expressions`` can be used to retrieve this information.
298 ``user_expressions`` can be used to retrieve this information.
299
299
300 Any error in evaluating any expression in ``user_expressions`` will result in
300 Any error in evaluating any expression in ``user_expressions`` will result in
301 only that key containing a standard error message, of the form::
301 only that key containing a standard error message, of the form::
302
302
303 {
303 {
304 'status' : 'error',
304 'status' : 'error',
305 'ename' : 'NameError',
305 'ename' : 'NameError',
306 'evalue' : 'foo',
306 'evalue' : 'foo',
307 'traceback' : ...
307 'traceback' : ...
308 }
308 }
309
309
310 .. Note::
310 .. Note::
311
311
312 In order to obtain the current execution counter for the purposes of
312 In order to obtain the current execution counter for the purposes of
313 displaying input prompts, frontends may make an execution request with an
313 displaying input prompts, frontends may make an execution request with an
314 empty code string and ``silent=True``.
314 empty code string and ``silent=True``.
315
315
316 Upon completion of the execution request, the kernel *always* sends a reply,
316 Upon completion of the execution request, the kernel *always* sends a reply,
317 with a status code indicating what happened and additional data depending on
317 with a status code indicating what happened and additional data depending on
318 the outcome. See :ref:`below <execution_results>` for the possible return
318 the outcome. See :ref:`below <execution_results>` for the possible return
319 codes and associated data.
319 codes and associated data.
320
320
321 .. seealso::
321 .. seealso::
322
322
323 :ref:`execution_semantics`
323 :ref:`execution_semantics`
324
324
325 .. _execution_counter:
325 .. _execution_counter:
326
326
327 Execution counter (prompt number)
327 Execution counter (prompt number)
328 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
329
329
330 The kernel should have a single, monotonically increasing counter of all execution
330 The kernel should have a single, monotonically increasing counter of all execution
331 requests that are made with ``store_history=True``. This counter is used to populate
331 requests that are made with ``store_history=True``. This counter is used to populate
332 the ``In[n]`` and ``Out[n]`` prompts. The value of this counter will be returned as the
332 the ``In[n]`` and ``Out[n]`` prompts. The value of this counter will be returned as the
333 ``execution_count`` field of all ``execute_reply`` and ``execute_input`` messages.
333 ``execution_count`` field of all ``execute_reply`` and ``execute_input`` messages.
334
334
335 .. _execution_results:
335 .. _execution_results:
336
336
337 Execution results
337 Execution results
338 ~~~~~~~~~~~~~~~~~
338 ~~~~~~~~~~~~~~~~~
339
339
340 Message type: ``execute_reply``::
340 Message type: ``execute_reply``::
341
341
342 content = {
342 content = {
343 # One of: 'ok' OR 'error' OR 'abort'
343 # One of: 'ok' OR 'error' OR 'abort'
344 'status' : str,
344 'status' : str,
345
345
346 # The global kernel counter that increases by one with each request that
346 # The global kernel counter that increases by one with each request that
347 # stores history. This will typically be used by clients to display
347 # stores history. This will typically be used by clients to display
348 # prompt numbers to the user. If the request did not store history, this will
348 # prompt numbers to the user. If the request did not store history, this will
349 # be the current value of the counter in the kernel.
349 # be the current value of the counter in the kernel.
350 'execution_count' : int,
350 'execution_count' : int,
351 }
351 }
352
352
353 When status is 'ok', the following extra fields are present::
353 When status is 'ok', the following extra fields are present::
354
354
355 {
355 {
356 # 'payload' will be a list of payload dicts.
356 # 'payload' will be a list of payload dicts.
357 # Each execution payload is a dict with string keys that may have been
357 # Each execution payload is a dict with string keys that may have been
358 # produced by the code being executed. It is retrieved by the kernel at
358 # produced by the code being executed. It is retrieved by the kernel at
359 # the end of the execution and sent back to the front end, which can take
359 # the end of the execution and sent back to the front end, which can take
360 # action on it as needed.
360 # action on it as needed.
361 # The only requirement of each payload dict is that it have a 'source' key,
361 # The only requirement of each payload dict is that it have a 'source' key,
362 # which is a string classifying the payload (e.g. 'pager').
362 # which is a string classifying the payload (e.g. 'pager').
363 'payload' : list(dict),
363 'payload' : list(dict),
364
364
365 # Results for the user_expressions.
365 # Results for the user_expressions.
366 'user_expressions' : dict,
366 'user_expressions' : dict,
367 }
367 }
368
368
369 .. versionchanged:: 5.0
369 .. versionchanged:: 5.0
370
370
371 ``user_variables`` is removed, use user_expressions instead.
371 ``user_variables`` is removed, use user_expressions instead.
372
372
373 .. admonition:: Execution payloads
373 .. admonition:: Execution payloads
374
374
375 The notion of an 'execution payload' is different from a return value of a
375 The notion of an 'execution payload' is different from a return value of a
376 given set of code, which normally is just displayed on the execute_result stream
376 given set of code, which normally is just displayed on the execute_result stream
377 through the PUB socket. The idea of a payload is to allow special types of
377 through the PUB socket. The idea of a payload is to allow special types of
378 code, typically magics, to populate a data container in the IPython kernel
378 code, typically magics, to populate a data container in the IPython kernel
379 that will be shipped back to the caller via this channel. The kernel
379 that will be shipped back to the caller via this channel. The kernel
380 has an API for this in the PayloadManager::
380 has an API for this in the PayloadManager::
381
381
382 ip.payload_manager.write_payload(payload_dict)
382 ip.payload_manager.write_payload(payload_dict)
383
383
384 which appends a dictionary to the list of payloads.
384 which appends a dictionary to the list of payloads.
385
385
386 The payload API is not yet stabilized,
386 The payload API is not yet stabilized,
387 and should probably not be supported by non-Python kernels at this time.
387 and should probably not be supported by non-Python kernels at this time.
388 In such cases, the payload list should always be empty.
388 In such cases, the payload list should always be empty.
389
389
390
390
391 When status is 'error', the following extra fields are present::
391 When status is 'error', the following extra fields are present::
392
392
393 {
393 {
394 'ename' : str, # Exception name, as a string
394 'ename' : str, # Exception name, as a string
395 'evalue' : str, # Exception value, as a string
395 'evalue' : str, # Exception value, as a string
396
396
397 # The traceback will contain a list of frames, represented each as a
397 # The traceback will contain a list of frames, represented each as a
398 # string. For now we'll stick to the existing design of ultraTB, which
398 # string. For now we'll stick to the existing design of ultraTB, which
399 # controls exception level of detail statefully. But eventually we'll
399 # controls exception level of detail statefully. But eventually we'll
400 # want to grow into a model where more information is collected and
400 # want to grow into a model where more information is collected and
401 # packed into the traceback object, with clients deciding how little or
401 # packed into the traceback object, with clients deciding how little or
402 # how much of it to unpack. But for now, let's start with a simple list
402 # how much of it to unpack. But for now, let's start with a simple list
403 # of strings, since that requires only minimal changes to ultratb as
403 # of strings, since that requires only minimal changes to ultratb as
404 # written.
404 # written.
405 'traceback' : list,
405 'traceback' : list,
406 }
406 }
407
407
408
408
409 When status is 'abort', there are for now no additional data fields. This
409 When status is 'abort', there are for now no additional data fields. This
410 happens when the kernel was interrupted by a signal.
410 happens when the kernel was interrupted by a signal.
411
411
412 .. _msging_inspection:
412 .. _msging_inspection:
413
413
414 Introspection
414 Introspection
415 -------------
415 -------------
416
416
417 Code can be inspected to show useful information to the user.
417 Code can be inspected to show useful information to the user.
418 It is up to the Kernel to decide what information should be displayed, and its formatting.
418 It is up to the Kernel to decide what information should be displayed, and its formatting.
419
419
420 Message type: ``inspect_request``::
420 Message type: ``inspect_request``::
421
421
422 content = {
422 content = {
423 # The code context in which introspection is requested
423 # The code context in which introspection is requested
424 # this may be up to an entire multiline cell.
424 # this may be up to an entire multiline cell.
425 'code' : str,
425 'code' : str,
426
426
427 # The cursor position within 'code' (in unicode characters) where inspection is requested
427 # The cursor position within 'code' (in unicode characters) where inspection is requested
428 'cursor_pos' : int,
428 'cursor_pos' : int,
429
429
430 # The level of detail desired. In IPython, the default (0) is equivalent to typing
430 # The level of detail desired. In IPython, the default (0) is equivalent to typing
431 # 'x?' at the prompt, 1 is equivalent to 'x??'.
431 # 'x?' at the prompt, 1 is equivalent to 'x??'.
432 # The difference is up to kernels, but in IPython level 1 includes the source code
432 # The difference is up to kernels, but in IPython level 1 includes the source code
433 # if available.
433 # if available.
434 'detail_level' : 0 or 1,
434 'detail_level' : 0 or 1,
435 }
435 }
436
436
437 .. versionchanged:: 5.0
437 .. versionchanged:: 5.0
438
438
439 ``object_info_request`` renamed to ``inspect_request``.
439 ``object_info_request`` renamed to ``inspect_request``.
440
440
441 .. versionchanged:: 5.0
441 .. versionchanged:: 5.0
442
442
443 ``name`` key replaced with ``code`` and ``cursor_pos``,
443 ``name`` key replaced with ``code`` and ``cursor_pos``,
444 moving the lexing responsibility to the kernel.
444 moving the lexing responsibility to the kernel.
445
445
446 The reply is a mime-bundle, like a `display_data`_ message,
446 The reply is a mime-bundle, like a `display_data`_ message,
447 which should be a formatted representation of information about the context.
447 which should be a formatted representation of information about the context.
448 In the notebook, this is used to show tooltips over function calls, etc.
448 In the notebook, this is used to show tooltips over function calls, etc.
449
449
450 Message type: ``inspect_reply``::
450 Message type: ``inspect_reply``::
451
451
452 content = {
452 content = {
453 # 'ok' if the request succeeded or 'error', with error information as in all other replies.
453 # 'ok' if the request succeeded or 'error', with error information as in all other replies.
454 'status' : 'ok',
454 'status' : 'ok',
455
455
456 # data can be empty if nothing is found
456 # data can be empty if nothing is found
457 'data' : dict,
457 'data' : dict,
458 'metadata' : dict,
458 'metadata' : dict,
459 }
459 }
460
460
461 .. versionchanged:: 5.0
461 .. versionchanged:: 5.0
462
462
463 ``object_info_reply`` renamed to ``inspect_reply``.
463 ``object_info_reply`` renamed to ``inspect_reply``.
464
464
465 .. versionchanged:: 5.0
465 .. versionchanged:: 5.0
466
466
467 Reply is changed from structured data to a mime bundle, allowing formatting decisions to be made by the kernel.
467 Reply is changed from structured data to a mime bundle, allowing formatting decisions to be made by the kernel.
468
468
469 .. _msging_completion:
469 .. _msging_completion:
470
470
471 Completion
471 Completion
472 ----------
472 ----------
473
473
474 Message type: ``complete_request``::
474 Message type: ``complete_request``::
475
475
476 content = {
476 content = {
477 # The code context in which completion is requested
477 # The code context in which completion is requested
478 # this may be up to an entire multiline cell, such as
478 # this may be up to an entire multiline cell, such as
479 # 'foo = a.isal'
479 # 'foo = a.isal'
480 'code' : str,
480 'code' : str,
481
481
482 # The cursor position within 'code' (in unicode characters) where completion is requested
482 # The cursor position within 'code' (in unicode characters) where completion is requested
483 'cursor_pos' : int,
483 'cursor_pos' : int,
484 }
484 }
485
485
486 .. versionchanged:: 5.0
486 .. versionchanged:: 5.0
487
487
488 ``line``, ``block``, and ``text`` keys are removed in favor of a single ``code`` for context.
488 ``line``, ``block``, and ``text`` keys are removed in favor of a single ``code`` for context.
489 Lexing is up to the kernel.
489 Lexing is up to the kernel.
490
490
491
491
492 Message type: ``complete_reply``::
492 Message type: ``complete_reply``::
493
493
494 content = {
494 content = {
495 # The list of all matches to the completion request, such as
495 # The list of all matches to the completion request, such as
496 # ['a.isalnum', 'a.isalpha'] for the above example.
496 # ['a.isalnum', 'a.isalpha'] for the above example.
497 'matches' : list,
497 'matches' : list,
498
498
499 # The range of text that should be replaced by the above matches when a completion is accepted.
499 # The range of text that should be replaced by the above matches when a completion is accepted.
500 # typically cursor_end is the same as cursor_pos in the request.
500 # typically cursor_end is the same as cursor_pos in the request.
501 'cursor_start' : int,
501 'cursor_start' : int,
502 'cursor_end' : int,
502 'cursor_end' : int,
503
503
504 # Information that frontend plugins might use for extra display information about completions.
504 # Information that frontend plugins might use for extra display information about completions.
505 'metadata' : dict,
505 'metadata' : dict,
506
506
507 # status should be 'ok' unless an exception was raised during the request,
507 # status should be 'ok' unless an exception was raised during the request,
508 # in which case it should be 'error', along with the usual error message content
508 # in which case it should be 'error', along with the usual error message content
509 # in other messages.
509 # in other messages.
510 'status' : 'ok'
510 'status' : 'ok'
511 }
511 }
512
512
513 .. versionchanged:: 5.0
513 .. versionchanged:: 5.0
514
514
515 - ``matched_text`` is removed in favor of ``cursor_start`` and ``cursor_end``.
515 - ``matched_text`` is removed in favor of ``cursor_start`` and ``cursor_end``.
516 - ``metadata`` is added for extended information.
516 - ``metadata`` is added for extended information.
517
517
518 .. _msging_history:
518 .. _msging_history:
519
519
520 History
520 History
521 -------
521 -------
522
522
523 For clients to explicitly request history from a kernel. The kernel has all
523 For clients to explicitly request history from a kernel. The kernel has all
524 the actual execution history stored in a single location, so clients can
524 the actual execution history stored in a single location, so clients can
525 request it from the kernel when needed.
525 request it from the kernel when needed.
526
526
527 Message type: ``history_request``::
527 Message type: ``history_request``::
528
528
529 content = {
529 content = {
530
530
531 # If True, also return output history in the resulting dict.
531 # If True, also return output history in the resulting dict.
532 'output' : bool,
532 'output' : bool,
533
533
534 # If True, return the raw input history, else the transformed input.
534 # If True, return the raw input history, else the transformed input.
535 'raw' : bool,
535 'raw' : bool,
536
536
537 # So far, this can be 'range', 'tail' or 'search'.
537 # So far, this can be 'range', 'tail' or 'search'.
538 'hist_access_type' : str,
538 'hist_access_type' : str,
539
539
540 # If hist_access_type is 'range', get a range of input cells. session can
540 # If hist_access_type is 'range', get a range of input cells. session can
541 # be a positive session number, or a negative number to count back from
541 # be a positive session number, or a negative number to count back from
542 # the current session.
542 # the current session.
543 'session' : int,
543 'session' : int,
544 # start and stop are line numbers within that session.
544 # start and stop are line numbers within that session.
545 'start' : int,
545 'start' : int,
546 'stop' : int,
546 'stop' : int,
547
547
548 # If hist_access_type is 'tail' or 'search', get the last n cells.
548 # If hist_access_type is 'tail' or 'search', get the last n cells.
549 'n' : int,
549 'n' : int,
550
550
551 # If hist_access_type is 'search', get cells matching the specified glob
551 # If hist_access_type is 'search', get cells matching the specified glob
552 # pattern (with * and ? as wildcards).
552 # pattern (with * and ? as wildcards).
553 'pattern' : str,
553 'pattern' : str,
554
554
555 # If hist_access_type is 'search' and unique is true, do not
555 # If hist_access_type is 'search' and unique is true, do not
556 # include duplicated history. Default is false.
556 # include duplicated history. Default is false.
557 'unique' : bool,
557 'unique' : bool,
558
558
559 }
559 }
560
560
561 .. versionadded:: 4.0
561 .. versionadded:: 4.0
562 The key ``unique`` for ``history_request``.
562 The key ``unique`` for ``history_request``.
563
563
564 Message type: ``history_reply``::
564 Message type: ``history_reply``::
565
565
566 content = {
566 content = {
567 # A list of 3 tuples, either:
567 # A list of 3 tuples, either:
568 # (session, line_number, input) or
568 # (session, line_number, input) or
569 # (session, line_number, (input, output)),
569 # (session, line_number, (input, output)),
570 # depending on whether output was False or True, respectively.
570 # depending on whether output was False or True, respectively.
571 'history' : list,
571 'history' : list,
572 }
572 }
573
573
574
574
575 Connect
575 Connect
576 -------
576 -------
577
577
578 When a client connects to the request/reply socket of the kernel, it can issue
578 When a client connects to the request/reply socket of the kernel, it can issue
579 a connect request to get basic information about the kernel, such as the ports
579 a connect request to get basic information about the kernel, such as the ports
580 the other ZeroMQ sockets are listening on. This allows clients to only have
580 the other ZeroMQ sockets are listening on. This allows clients to only have
581 to know about a single port (the shell channel) to connect to a kernel.
581 to know about a single port (the shell channel) to connect to a kernel.
582
582
583 Message type: ``connect_request``::
583 Message type: ``connect_request``::
584
584
585 content = {
585 content = {
586 }
586 }
587
587
588 Message type: ``connect_reply``::
588 Message type: ``connect_reply``::
589
589
590 content = {
590 content = {
591 'shell_port' : int, # The port the shell ROUTER socket is listening on.
591 'shell_port' : int, # The port the shell ROUTER socket is listening on.
592 'iopub_port' : int, # The port the PUB socket is listening on.
592 'iopub_port' : int, # The port the PUB socket is listening on.
593 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
593 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
594 'hb_port' : int, # The port the heartbeat socket is listening on.
594 'hb_port' : int, # The port the heartbeat socket is listening on.
595 }
595 }
596
596
597 .. _msging_kernel_info:
597 .. _msging_kernel_info:
598
598
599 Kernel info
599 Kernel info
600 -----------
600 -----------
601
601
602 If a client needs to know information about the kernel, it can
602 If a client needs to know information about the kernel, it can
603 make a request of the kernel's information.
603 make a request of the kernel's information.
604 This message can be used to fetch core information of the
604 This message can be used to fetch core information of the
605 kernel, including language (e.g., Python), language version number and
605 kernel, including language (e.g., Python), language version number and
606 IPython version number, and the IPython message spec version number.
606 IPython version number, and the IPython message spec version number.
607
607
608 Message type: ``kernel_info_request``::
608 Message type: ``kernel_info_request``::
609
609
610 content = {
610 content = {
611 }
611 }
612
612
613 Message type: ``kernel_info_reply``::
613 Message type: ``kernel_info_reply``::
614
614
615 content = {
615 content = {
616 # Version of messaging protocol.
616 # Version of messaging protocol.
617 # The first integer indicates major version. It is incremented when
617 # The first integer indicates major version. It is incremented when
618 # there is any backward incompatible change.
618 # there is any backward incompatible change.
619 # The second integer indicates minor version. It is incremented when
619 # The second integer indicates minor version. It is incremented when
620 # there is any backward compatible change.
620 # there is any backward compatible change.
621 'protocol_version': 'X.Y.Z',
621 'protocol_version': 'X.Y.Z',
622
622
623 # The kernel implementation name
623 # The kernel implementation name
624 # (e.g. 'ipython' for the IPython kernel)
624 # (e.g. 'ipython' for the IPython kernel)
625 'implementation': str,
625 'implementation': str,
626
626
627 # Implementation version number.
627 # Implementation version number.
628 # The version number of the kernel's implementation
628 # The version number of the kernel's implementation
629 # (e.g. IPython.__version__ for the IPython kernel)
629 # (e.g. IPython.__version__ for the IPython kernel)
630 'implementation_version': 'X.Y.Z',
630 'implementation_version': 'X.Y.Z',
631
631
632 # Programming language in which kernel is implemented.
632 # Programming language in which kernel is implemented.
633 # Kernel included in IPython returns 'python'.
633 # Kernel included in IPython returns 'python'.
634 'language': str,
634 'language': str,
635
635
636 # Language version number.
636 # Language version number.
637 # It is Python version number (e.g., '2.7.3') for the kernel
637 # It is Python version number (e.g., '2.7.3') for the kernel
638 # included in IPython.
638 # included in IPython.
639 'language_version': 'X.Y.Z',
639 'language_version': 'X.Y.Z',
640
640
641 # A banner of information about the kernel,
641 # A banner of information about the kernel,
642 # which may be desplayed in console environments.
642 # which may be desplayed in console environments.
643 'banner' : str,
643 'banner' : str,
644 }
644 }
645
645
646 .. versionchanged:: 5.0
646 .. versionchanged:: 5.0
647
647
648 Versions changed from lists of integers to strings.
648 Versions changed from lists of integers to strings.
649
649
650 .. versionchanged:: 5.0
650 .. versionchanged:: 5.0
651
651
652 ``ipython_version`` is removed.
652 ``ipython_version`` is removed.
653
653
654 .. versionchanged:: 5.0
654 .. versionchanged:: 5.0
655
655
656 ``implementation``, ``implementation_version``, and ``banner`` keys are added.
656 ``implementation``, ``implementation_version``, and ``banner`` keys are added.
657
657
658 .. _msging_shutdown:
658 .. _msging_shutdown:
659
659
660 Kernel shutdown
660 Kernel shutdown
661 ---------------
661 ---------------
662
662
663 The clients can request the kernel to shut itself down; this is used in
663 The clients can request the kernel to shut itself down; this is used in
664 multiple cases:
664 multiple cases:
665
665
666 - when the user chooses to close the client application via a menu or window
666 - when the user chooses to close the client application via a menu or window
667 control.
667 control.
668 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
668 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
669 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
669 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
670 IPythonQt client) to force a kernel restart to get a clean kernel without
670 IPythonQt client) to force a kernel restart to get a clean kernel without
671 losing client-side state like history or inlined figures.
671 losing client-side state like history or inlined figures.
672
672
673 The client sends a shutdown request to the kernel, and once it receives the
673 The client sends a shutdown request to the kernel, and once it receives the
674 reply message (which is otherwise empty), it can assume that the kernel has
674 reply message (which is otherwise empty), it can assume that the kernel has
675 completed shutdown safely.
675 completed shutdown safely.
676
676
677 Upon their own shutdown, client applications will typically execute a last
677 Upon their own shutdown, client applications will typically execute a last
678 minute sanity check and forcefully terminate any kernel that is still alive, to
678 minute sanity check and forcefully terminate any kernel that is still alive, to
679 avoid leaving stray processes in the user's machine.
679 avoid leaving stray processes in the user's machine.
680
680
681 Message type: ``shutdown_request``::
681 Message type: ``shutdown_request``::
682
682
683 content = {
683 content = {
684 'restart' : bool # whether the shutdown is final, or precedes a restart
684 'restart' : bool # whether the shutdown is final, or precedes a restart
685 }
685 }
686
686
687 Message type: ``shutdown_reply``::
687 Message type: ``shutdown_reply``::
688
688
689 content = {
689 content = {
690 'restart' : bool # whether the shutdown is final, or precedes a restart
690 'restart' : bool # whether the shutdown is final, or precedes a restart
691 }
691 }
692
692
693 .. Note::
693 .. Note::
694
694
695 When the clients detect a dead kernel thanks to inactivity on the heartbeat
695 When the clients detect a dead kernel thanks to inactivity on the heartbeat
696 socket, they simply send a forceful process termination signal, since a dead
696 socket, they simply send a forceful process termination signal, since a dead
697 process is unlikely to respond in any useful way to messages.
697 process is unlikely to respond in any useful way to messages.
698
698
699
699
700 Messages on the PUB/SUB socket
700 Messages on the PUB/SUB socket
701 ==============================
701 ==============================
702
702
703 Streams (stdout, stderr, etc)
703 Streams (stdout, stderr, etc)
704 ------------------------------
704 ------------------------------
705
705
706 Message type: ``stream``::
706 Message type: ``stream``::
707
707
708 content = {
708 content = {
709 # The name of the stream is one of 'stdout', 'stderr'
709 # The name of the stream is one of 'stdout', 'stderr'
710 'name' : str,
710 'name' : str,
711
711
712 # The data is an arbitrary string to be written to that stream
712 # The data is an arbitrary string to be written to that stream
713 'data' : str,
713 'data' : str,
714 }
714 }
715
715
716 Display Data
716 Display Data
717 ------------
717 ------------
718
718
719 This type of message is used to bring back data that should be displayed (text,
719 This type of message is used to bring back data that should be displayed (text,
720 html, svg, etc.) in the frontends. This data is published to all frontends.
720 html, svg, etc.) in the frontends. This data is published to all frontends.
721 Each message can have multiple representations of the data; it is up to the
721 Each message can have multiple representations of the data; it is up to the
722 frontend to decide which to use and how. A single message should contain all
722 frontend to decide which to use and how. A single message should contain all
723 possible representations of the same information. Each representation should
723 possible representations of the same information. Each representation should
724 be a JSON'able data structure, and should be a valid MIME type.
724 be a JSON'able data structure, and should be a valid MIME type.
725
725
726 Some questions remain about this design:
726 Some questions remain about this design:
727
727
728 * Do we use this message type for execute_result/displayhook? Probably not, because
728 * Do we use this message type for execute_result/displayhook? Probably not, because
729 the displayhook also has to handle the Out prompt display. On the other hand
729 the displayhook also has to handle the Out prompt display. On the other hand
730 we could put that information into the metadata section.
730 we could put that information into the metadata section.
731
731
732 .. _display_data:
732 .. _display_data:
733
733
734 Message type: ``display_data``::
734 Message type: ``display_data``::
735
735
736 content = {
736 content = {
737
737
738 # Who create the data
738 # Who create the data
739 'source' : str,
739 'source' : str,
740
740
741 # The data dict contains key/value pairs, where the keys are MIME
741 # The data dict contains key/value pairs, where the keys are MIME
742 # types and the values are the raw data of the representation in that
742 # types and the values are the raw data of the representation in that
743 # format.
743 # format.
744 'data' : dict,
744 'data' : dict,
745
745
746 # Any metadata that describes the data
746 # Any metadata that describes the data
747 'metadata' : dict
747 'metadata' : dict
748 }
748 }
749
749
750
750
751 The ``metadata`` contains any metadata that describes the output.
751 The ``metadata`` contains any metadata that describes the output.
752 Global keys are assumed to apply to the output as a whole.
752 Global keys are assumed to apply to the output as a whole.
753 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
753 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
754 which are interpreted as applying only to output of that type.
754 which are interpreted as applying only to output of that type.
755 Third parties should put any data they write into a single dict
755 Third parties should put any data they write into a single dict
756 with a reasonably unique name to avoid conflicts.
756 with a reasonably unique name to avoid conflicts.
757
757
758 The only metadata keys currently defined in IPython are the width and height
758 The only metadata keys currently defined in IPython are the width and height
759 of images::
759 of images::
760
760
761 metadata = {
761 metadata = {
762 'image/png' : {
762 'image/png' : {
763 'width': 640,
763 'width': 640,
764 'height': 480
764 'height': 480
765 }
765 }
766 }
766 }
767
767
768
768
769 .. versionchanged:: 5.0
769 .. versionchanged:: 5.0
770
770
771 `application/json` data should be unpacked JSON data,
771 `application/json` data should be unpacked JSON data,
772 not double-serialized as a JSON string.
772 not double-serialized as a JSON string.
773
773
774
774
775 Raw Data Publication
775 Raw Data Publication
776 --------------------
776 --------------------
777
777
778 ``display_data`` lets you publish *representations* of data, such as images and html.
778 ``display_data`` lets you publish *representations* of data, such as images and html.
779 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
779 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
780
780
781 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
781 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
782
782
783 .. sourcecode:: python
783 .. sourcecode:: python
784
784
785 from IPython.kernel.zmq.datapub import publish_data
785 from IPython.kernel.zmq.datapub import publish_data
786 ns = dict(x=my_array)
786 ns = dict(x=my_array)
787 publish_data(ns)
787 publish_data(ns)
788
788
789
789
790 Message type: ``data_pub``::
790 Message type: ``data_pub``::
791
791
792 content = {
792 content = {
793 # the keys of the data dict, after it has been unserialized
793 # the keys of the data dict, after it has been unserialized
794 'keys' : ['a', 'b']
794 'keys' : ['a', 'b']
795 }
795 }
796 # the namespace dict will be serialized in the message buffers,
796 # the namespace dict will be serialized in the message buffers,
797 # which will have a length of at least one
797 # which will have a length of at least one
798 buffers = [b'pdict', ...]
798 buffers = [b'pdict', ...]
799
799
800
800
801 The interpretation of a sequence of data_pub messages for a given parent request should be
801 The interpretation of a sequence of data_pub messages for a given parent request should be
802 to update a single namespace with subsequent results.
802 to update a single namespace with subsequent results.
803
803
804 .. note::
804 .. note::
805
805
806 No frontends directly handle data_pub messages at this time.
806 No frontends directly handle data_pub messages at this time.
807 It is currently only used by the client/engines in :mod:`IPython.parallel`,
807 It is currently only used by the client/engines in :mod:`IPython.parallel`,
808 where engines may publish *data* to the Client,
808 where engines may publish *data* to the Client,
809 of which the Client can then publish *representations* via ``display_data``
809 of which the Client can then publish *representations* via ``display_data``
810 to various frontends.
810 to various frontends.
811
811
812 Code inputs
812 Code inputs
813 -----------
813 -----------
814
814
815 To let all frontends know what code is being executed at any given time, these
815 To let all frontends know what code is being executed at any given time, these
816 messages contain a re-broadcast of the ``code`` portion of an
816 messages contain a re-broadcast of the ``code`` portion of an
817 :ref:`execute_request <execute>`, along with the :ref:`execution_count
817 :ref:`execute_request <execute>`, along with the :ref:`execution_count
818 <execution_counter>`.
818 <execution_counter>`.
819
819
820 Message type: ``execute_input``::
820 Message type: ``execute_input``::
821
821
822 content = {
822 content = {
823 'code' : str, # Source code to be executed, one or more lines
823 'code' : str, # Source code to be executed, one or more lines
824
824
825 # The counter for this execution is also provided so that clients can
825 # The counter for this execution is also provided so that clients can
826 # display it, since IPython automatically creates variables called _iN
826 # display it, since IPython automatically creates variables called _iN
827 # (for input prompt In[N]).
827 # (for input prompt In[N]).
828 'execution_count' : int
828 'execution_count' : int
829 }
829 }
830
830
831 .. versionchanged:: 5.0
831 .. versionchanged:: 5.0
832
832
833 ``pyin`` is renamed to ``execute_input``.
833 ``pyin`` is renamed to ``execute_input``.
834
834
835
835
836 Execution results
836 Execution results
837 -----------------
837 -----------------
838
838
839 Results of an execution are published as an ``execute_result``.
839 Results of an execution are published as an ``execute_result``.
840 These are identical to `display_data`_ messages, with the addition of an ``execution_count`` key.
840 These are identical to `display_data`_ messages, with the addition of an ``execution_count`` key.
841
841
842 Results can have multiple simultaneous formats depending on its
842 Results can have multiple simultaneous formats depending on its
843 configuration. A plain text representation should always be provided
843 configuration. A plain text representation should always be provided
844 in the ``text/plain`` mime-type. Frontends are free to display any or all of these
844 in the ``text/plain`` mime-type. Frontends are free to display any or all of these
845 according to its capabilities.
845 according to its capabilities.
846 Frontends should ignore mime-types they do not understand. The data itself is
846 Frontends should ignore mime-types they do not understand. The data itself is
847 any JSON object and depends on the format. It is often, but not always a string.
847 any JSON object and depends on the format. It is often, but not always a string.
848
848
849 Message type: ``execute_result``::
849 Message type: ``execute_result``::
850
850
851 content = {
851 content = {
852
852
853 # The counter for this execution is also provided so that clients can
853 # The counter for this execution is also provided so that clients can
854 # display it, since IPython automatically creates variables called _N
854 # display it, since IPython automatically creates variables called _N
855 # (for prompt N).
855 # (for prompt N).
856 'execution_count' : int,
856 'execution_count' : int,
857
857
858 # data and metadata are identical to a display_data message.
858 # data and metadata are identical to a display_data message.
859 # the object being displayed is that passed to the display hook,
859 # the object being displayed is that passed to the display hook,
860 # i.e. the *result* of the execution.
860 # i.e. the *result* of the execution.
861 'data' : dict,
861 'data' : dict,
862 'metadata' : dict,
862 'metadata' : dict,
863 }
863 }
864
864
865 Execution errors
865 Execution errors
866 ----------------
866 ----------------
867
867
868 When an error occurs during code execution
868 When an error occurs during code execution
869
869
870 Message type: ``error``::
870 Message type: ``error``::
871
871
872 content = {
872 content = {
873 # Similar content to the execute_reply messages for the 'error' case,
873 # Similar content to the execute_reply messages for the 'error' case,
874 # except the 'status' field is omitted.
874 # except the 'status' field is omitted.
875 }
875 }
876
876
877 .. versionchanged:: 5.0
877 .. versionchanged:: 5.0
878
878
879 ``pyerr`` renamed to ``error``
879 ``pyerr`` renamed to ``error``
880
880
881 Kernel status
881 Kernel status
882 -------------
882 -------------
883
883
884 This message type is used by frontends to monitor the status of the kernel.
884 This message type is used by frontends to monitor the status of the kernel.
885
885
886 Message type: ``status``::
886 Message type: ``status``::
887
887
888 content = {
888 content = {
889 # When the kernel starts to handle a message, it will enter the 'busy'
889 # When the kernel starts to handle a message, it will enter the 'busy'
890 # state and when it finishes, it will enter the 'idle' state.
890 # state and when it finishes, it will enter the 'idle' state.
891 # The kernel will publish state 'starting' exactly once at process startup.
891 # The kernel will publish state 'starting' exactly once at process startup.
892 execution_state : ('busy', 'idle', 'starting')
892 execution_state : ('busy', 'idle', 'starting')
893 }
893 }
894
894
895 .. versionchanged:: 5.0
895 .. versionchanged:: 5.0
896
896
897 Busy and idle messages should be sent before/after handling every shell message,
897 Busy and idle messages should be sent before/after handling every message,
898 not just execution.
898 not just execution.
899
899
900 Clear output
900 Clear output
901 ------------
901 ------------
902
902
903 This message type is used to clear the output that is visible on the frontend.
903 This message type is used to clear the output that is visible on the frontend.
904
904
905 Message type: ``clear_output``::
905 Message type: ``clear_output``::
906
906
907 content = {
907 content = {
908
908
909 # Wait to clear the output until new output is available. Clears the
909 # Wait to clear the output until new output is available. Clears the
910 # existing output immediately before the new output is displayed.
910 # existing output immediately before the new output is displayed.
911 # Useful for creating simple animations with minimal flickering.
911 # Useful for creating simple animations with minimal flickering.
912 'wait' : bool,
912 'wait' : bool,
913 }
913 }
914
914
915 .. versionchanged:: 4.1
915 .. versionchanged:: 4.1
916
916
917 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
917 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
918 and ``wait`` is added.
918 and ``wait`` is added.
919 The selective clearing keys are ignored in v4 and the default behavior remains the same,
919 The selective clearing keys are ignored in v4 and the default behavior remains the same,
920 so v4 clear_output messages will be safely handled by a v4.1 frontend.
920 so v4 clear_output messages will be safely handled by a v4.1 frontend.
921
921
922
922
923 Messages on the stdin ROUTER/DEALER sockets
923 Messages on the stdin ROUTER/DEALER sockets
924 ===========================================
924 ===========================================
925
925
926 This is a socket where the request/reply pattern goes in the opposite direction:
926 This is a socket where the request/reply pattern goes in the opposite direction:
927 from the kernel to a *single* frontend, and its purpose is to allow
927 from the kernel to a *single* frontend, and its purpose is to allow
928 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
928 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
929 to be fulfilled by the client. The request should be made to the frontend that
929 to be fulfilled by the client. The request should be made to the frontend that
930 made the execution request that prompted ``raw_input`` to be called. For now we
930 made the execution request that prompted ``raw_input`` to be called. For now we
931 will keep these messages as simple as possible, since they only mean to convey
931 will keep these messages as simple as possible, since they only mean to convey
932 the ``raw_input(prompt)`` call.
932 the ``raw_input(prompt)`` call.
933
933
934 Message type: ``input_request``::
934 Message type: ``input_request``::
935
935
936 content = {
936 content = {
937 # the text to show at the prompt
937 # the text to show at the prompt
938 'prompt' : str,
938 'prompt' : str,
939 # Is the request for a password?
939 # Is the request for a password?
940 # If so, the frontend shouldn't echo input.
940 # If so, the frontend shouldn't echo input.
941 'password' : bool
941 'password' : bool
942 }
942 }
943
943
944 Message type: ``input_reply``::
944 Message type: ``input_reply``::
945
945
946 content = { 'value' : str }
946 content = { 'value' : str }
947
947
948
948
949 When ``password`` is True, the frontend should not echo the input as it is entered.
949 When ``password`` is True, the frontend should not echo the input as it is entered.
950
950
951 .. versionchanged:: 5.0
951 .. versionchanged:: 5.0
952
952
953 ``password`` key added.
953 ``password`` key added.
954
954
955 .. note::
955 .. note::
956
956
957 The stdin socket of the client is required to have the same zmq IDENTITY
957 The stdin socket of the client is required to have the same zmq IDENTITY
958 as the client's shell socket.
958 as the client's shell socket.
959 Because of this, the ``input_request`` must be sent with the same IDENTITY
959 Because of this, the ``input_request`` must be sent with the same IDENTITY
960 routing prefix as the ``execute_reply`` in order for the frontend to receive
960 routing prefix as the ``execute_reply`` in order for the frontend to receive
961 the message.
961 the message.
962
962
963 .. note::
963 .. note::
964
964
965 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
965 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
966 practice the kernel should behave like an interactive program. When a
966 practice the kernel should behave like an interactive program. When a
967 program is opened on the console, the keyboard effectively takes over the
967 program is opened on the console, the keyboard effectively takes over the
968 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
968 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
969 Since the IPython kernel effectively behaves like a console program (albeit
969 Since the IPython kernel effectively behaves like a console program (albeit
970 one whose "keyboard" is actually living in a separate process and
970 one whose "keyboard" is actually living in a separate process and
971 transported over the zmq connection), raw ``stdin`` isn't expected to be
971 transported over the zmq connection), raw ``stdin`` isn't expected to be
972 available.
972 available.
973
973
974
974
975 Heartbeat for kernels
975 Heartbeat for kernels
976 =====================
976 =====================
977
977
978 Clients send ping messages on a REQ socket, which are echoed right back
978 Clients send ping messages on a REQ socket, which are echoed right back
979 from the Kernel's REP socket. These are simple bytestrings, not full JSON messages described above.
979 from the Kernel's REP socket. These are simple bytestrings, not full JSON messages described above.
980
980
981
981
982 Custom Messages
982 Custom Messages
983 ===============
983 ===============
984
984
985 .. versionadded:: 4.1
985 .. versionadded:: 4.1
986
986
987 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
987 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
988 and Kernel-side components, and allow them to communicate with each other.
988 and Kernel-side components, and allow them to communicate with each other.
989 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
989 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
990 and can communicate in either direction.
990 and can communicate in either direction.
991
991
992 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
992 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
993 and no messages expect a reply.
993 and no messages expect a reply.
994 The Kernel listens for these messages on the Shell channel,
994 The Kernel listens for these messages on the Shell channel,
995 and the Frontend listens for them on the IOPub channel.
995 and the Frontend listens for them on the IOPub channel.
996
996
997 Opening a Comm
997 Opening a Comm
998 --------------
998 --------------
999
999
1000 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1000 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1001
1001
1002 {
1002 {
1003 'comm_id' : 'u-u-i-d',
1003 'comm_id' : 'u-u-i-d',
1004 'target_name' : 'my_comm',
1004 'target_name' : 'my_comm',
1005 'data' : {}
1005 'data' : {}
1006 }
1006 }
1007
1007
1008 Every Comm has an ID and a target name.
1008 Every Comm has an ID and a target name.
1009 The code handling the message on the receiving side is responsible for maintaining a mapping
1009 The code handling the message on the receiving side is responsible for maintaining a mapping
1010 of target_name keys to constructors.
1010 of target_name keys to constructors.
1011 After a ``comm_open`` message has been sent,
1011 After a ``comm_open`` message has been sent,
1012 there should be a corresponding Comm instance on both sides.
1012 there should be a corresponding Comm instance on both sides.
1013 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1013 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1014
1014
1015 If the ``target_name`` key is not found on the receiving side,
1015 If the ``target_name`` key is not found on the receiving side,
1016 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1016 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1017
1017
1018 Comm Messages
1018 Comm Messages
1019 -------------
1019 -------------
1020
1020
1021 Comm messages are one-way communications to update comm state,
1021 Comm messages are one-way communications to update comm state,
1022 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1022 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1023
1023
1024 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1024 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1025
1025
1026 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1026 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1027
1027
1028 Message type: ``comm_msg``::
1028 Message type: ``comm_msg``::
1029
1029
1030 {
1030 {
1031 'comm_id' : 'u-u-i-d',
1031 'comm_id' : 'u-u-i-d',
1032 'data' : {}
1032 'data' : {}
1033 }
1033 }
1034
1034
1035 Tearing Down Comms
1035 Tearing Down Comms
1036 ------------------
1036 ------------------
1037
1037
1038 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1038 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1039 This is done with a ``comm_close`` message.
1039 This is done with a ``comm_close`` message.
1040
1040
1041 Message type: ``comm_close``::
1041 Message type: ``comm_close``::
1042
1042
1043 {
1043 {
1044 'comm_id' : 'u-u-i-d',
1044 'comm_id' : 'u-u-i-d',
1045 'data' : {}
1045 'data' : {}
1046 }
1046 }
1047
1047
1048 Output Side Effects
1048 Output Side Effects
1049 -------------------
1049 -------------------
1050
1050
1051 Since comm messages can execute arbitrary user code,
1051 Since comm messages can execute arbitrary user code,
1052 handlers should set the parent header and publish status busy / idle,
1052 handlers should set the parent header and publish status busy / idle,
1053 just like an execute request.
1053 just like an execute request.
1054
1054
1055
1055
1056 To Do
1056 To Do
1057 =====
1057 =====
1058
1058
1059 Missing things include:
1059 Missing things include:
1060
1060
1061 * Important: finish thinking through the payload concept and API.
1061 * Important: finish thinking through the payload concept and API.
1062
1062
1063 .. include:: ../links.txt
1063 .. include:: ../links.txt
General Comments 0
You need to be logged in to leave comments. Login now