##// END OF EJS Templates
Add the new search option `n` to the messaging protocol
Takafumi Arakaki -
Show More
@@ -1,931 +1,932 b''
1 1 #!/usr/bin/env python
2 2 """A simple interactive kernel that talks to a frontend over 0MQ.
3 3
4 4 Things to do:
5 5
6 6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 7 call set_parent on all the PUB objects with the message about to be executed.
8 8 * Implement random port and security key logic.
9 9 * Implement control messages.
10 10 * Implement event loop and poll version.
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Standard library imports
19 19 import __builtin__
20 20 import atexit
21 21 import sys
22 22 import time
23 23 import traceback
24 24 import logging
25 25 import uuid
26 26
27 27 from datetime import datetime
28 28 from signal import (
29 29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
30 30 )
31 31
32 32 # System library imports
33 33 import zmq
34 34 from zmq.eventloop import ioloop
35 35 from zmq.eventloop.zmqstream import ZMQStream
36 36
37 37 # Local imports
38 38 from IPython.config.configurable import Configurable
39 39 from IPython.config.application import boolean_flag, catch_config_error
40 40 from IPython.core.application import ProfileDir
41 41 from IPython.core.error import StdinNotImplementedError
42 42 from IPython.core.shellapp import (
43 43 InteractiveShellApp, shell_flags, shell_aliases
44 44 )
45 45 from IPython.utils import io
46 46 from IPython.utils import py3compat
47 47 from IPython.utils.frame import extract_module_locals
48 48 from IPython.utils.jsonutil import json_clean
49 49 from IPython.utils.traitlets import (
50 50 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
51 51 )
52 52
53 53 from entry_point import base_launch_kernel
54 54 from kernelapp import KernelApp, kernel_flags, kernel_aliases
55 55 from serialize import serialize_object, unpack_apply_message
56 56 from session import Session, Message
57 57 from zmqshell import ZMQInteractiveShell
58 58
59 59
60 60 #-----------------------------------------------------------------------------
61 61 # Main kernel class
62 62 #-----------------------------------------------------------------------------
63 63
64 64 class Kernel(Configurable):
65 65
66 66 #---------------------------------------------------------------------------
67 67 # Kernel interface
68 68 #---------------------------------------------------------------------------
69 69
70 70 # attribute to override with a GUI
71 71 eventloop = Any(None)
72 72 def _eventloop_changed(self, name, old, new):
73 73 """schedule call to eventloop from IOLoop"""
74 74 loop = ioloop.IOLoop.instance()
75 75 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
76 76
77 77 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
78 78 session = Instance(Session)
79 79 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
80 80 shell_streams = List()
81 81 control_stream = Instance(ZMQStream)
82 82 iopub_socket = Instance(zmq.Socket)
83 83 stdin_socket = Instance(zmq.Socket)
84 84 log = Instance(logging.Logger)
85 85
86 86 user_module = Any()
87 87 def _user_module_changed(self, name, old, new):
88 88 if self.shell is not None:
89 89 self.shell.user_module = new
90 90
91 91 user_ns = Dict(default_value=None)
92 92 def _user_ns_changed(self, name, old, new):
93 93 if self.shell is not None:
94 94 self.shell.user_ns = new
95 95 self.shell.init_user_ns()
96 96
97 97 # identities:
98 98 int_id = Integer(-1)
99 99 ident = Unicode()
100 100
101 101 def _ident_default(self):
102 102 return unicode(uuid.uuid4())
103 103
104 104
105 105 # Private interface
106 106
107 107 # Time to sleep after flushing the stdout/err buffers in each execute
108 108 # cycle. While this introduces a hard limit on the minimal latency of the
109 109 # execute cycle, it helps prevent output synchronization problems for
110 110 # clients.
111 111 # Units are in seconds. The minimum zmq latency on local host is probably
112 112 # ~150 microseconds, set this to 500us for now. We may need to increase it
113 113 # a little if it's not enough after more interactive testing.
114 114 _execute_sleep = Float(0.0005, config=True)
115 115
116 116 # Frequency of the kernel's event loop.
117 117 # Units are in seconds, kernel subclasses for GUI toolkits may need to
118 118 # adapt to milliseconds.
119 119 _poll_interval = Float(0.05, config=True)
120 120
121 121 # If the shutdown was requested over the network, we leave here the
122 122 # necessary reply message so it can be sent by our registered atexit
123 123 # handler. This ensures that the reply is only sent to clients truly at
124 124 # the end of our shutdown process (which happens after the underlying
125 125 # IPython shell's own shutdown).
126 126 _shutdown_message = None
127 127
128 128 # This is a dict of port number that the kernel is listening on. It is set
129 129 # by record_ports and used by connect_request.
130 130 _recorded_ports = Dict()
131 131
132 132 # set of aborted msg_ids
133 133 aborted = Set()
134 134
135 135
136 136 def __init__(self, **kwargs):
137 137 super(Kernel, self).__init__(**kwargs)
138 138
139 139 # Initialize the InteractiveShell subclass
140 140 self.shell = ZMQInteractiveShell.instance(config=self.config,
141 141 profile_dir = self.profile_dir,
142 142 user_module = self.user_module,
143 143 user_ns = self.user_ns,
144 144 )
145 145 self.shell.displayhook.session = self.session
146 146 self.shell.displayhook.pub_socket = self.iopub_socket
147 147 self.shell.displayhook.topic = self._topic('pyout')
148 148 self.shell.display_pub.session = self.session
149 149 self.shell.display_pub.pub_socket = self.iopub_socket
150 150 self.shell.data_pub.session = self.session
151 151 self.shell.data_pub.pub_socket = self.iopub_socket
152 152
153 153 # TMP - hack while developing
154 154 self.shell._reply_content = None
155 155
156 156 # Build dict of handlers for message types
157 157 msg_types = [ 'execute_request', 'complete_request',
158 158 'object_info_request', 'history_request',
159 159 'connect_request', 'shutdown_request',
160 160 'apply_request',
161 161 ]
162 162 self.shell_handlers = {}
163 163 for msg_type in msg_types:
164 164 self.shell_handlers[msg_type] = getattr(self, msg_type)
165 165
166 166 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
167 167 self.control_handlers = {}
168 168 for msg_type in control_msg_types:
169 169 self.control_handlers[msg_type] = getattr(self, msg_type)
170 170
171 171 def dispatch_control(self, msg):
172 172 """dispatch control requests"""
173 173 idents,msg = self.session.feed_identities(msg, copy=False)
174 174 try:
175 175 msg = self.session.unserialize(msg, content=True, copy=False)
176 176 except:
177 177 self.log.error("Invalid Control Message", exc_info=True)
178 178 return
179 179
180 180 self.log.debug("Control received: %s", msg)
181 181
182 182 header = msg['header']
183 183 msg_id = header['msg_id']
184 184 msg_type = header['msg_type']
185 185
186 186 handler = self.control_handlers.get(msg_type, None)
187 187 if handler is None:
188 188 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
189 189 else:
190 190 try:
191 191 handler(self.control_stream, idents, msg)
192 192 except Exception:
193 193 self.log.error("Exception in control handler:", exc_info=True)
194 194
195 195 def dispatch_shell(self, stream, msg):
196 196 """dispatch shell requests"""
197 197 # flush control requests first
198 198 if self.control_stream:
199 199 self.control_stream.flush()
200 200
201 201 idents,msg = self.session.feed_identities(msg, copy=False)
202 202 try:
203 203 msg = self.session.unserialize(msg, content=True, copy=False)
204 204 except:
205 205 self.log.error("Invalid Message", exc_info=True)
206 206 return
207 207
208 208 header = msg['header']
209 209 msg_id = header['msg_id']
210 210 msg_type = msg['header']['msg_type']
211 211
212 212 # Print some info about this message and leave a '--->' marker, so it's
213 213 # easier to trace visually the message chain when debugging. Each
214 214 # handler prints its message at the end.
215 215 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
216 216 self.log.debug(' Content: %s\n --->\n ', msg['content'])
217 217
218 218 if msg_id in self.aborted:
219 219 self.aborted.remove(msg_id)
220 220 # is it safe to assume a msg_id will not be resubmitted?
221 221 reply_type = msg_type.split('_')[0] + '_reply'
222 222 status = {'status' : 'aborted'}
223 223 md = {'engine' : self.ident}
224 224 md.update(status)
225 225 reply_msg = self.session.send(stream, reply_type, metadata=md,
226 226 content=status, parent=msg, ident=idents)
227 227 return
228 228
229 229 handler = self.shell_handlers.get(msg_type, None)
230 230 if handler is None:
231 231 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
232 232 else:
233 233 # ensure default_int_handler during handler call
234 234 sig = signal(SIGINT, default_int_handler)
235 235 try:
236 236 handler(stream, idents, msg)
237 237 except Exception:
238 238 self.log.error("Exception in message handler:", exc_info=True)
239 239 finally:
240 240 signal(SIGINT, sig)
241 241
242 242 def enter_eventloop(self):
243 243 """enter eventloop"""
244 244 self.log.info("entering eventloop")
245 245 # restore default_int_handler
246 246 signal(SIGINT, default_int_handler)
247 247 while self.eventloop is not None:
248 248 try:
249 249 self.eventloop(self)
250 250 except KeyboardInterrupt:
251 251 # Ctrl-C shouldn't crash the kernel
252 252 self.log.error("KeyboardInterrupt caught in kernel")
253 253 continue
254 254 else:
255 255 # eventloop exited cleanly, this means we should stop (right?)
256 256 self.eventloop = None
257 257 break
258 258 self.log.info("exiting eventloop")
259 259
260 260 def start(self):
261 261 """register dispatchers for streams"""
262 262 self.shell.exit_now = False
263 263 if self.control_stream:
264 264 self.control_stream.on_recv(self.dispatch_control, copy=False)
265 265
266 266 def make_dispatcher(stream):
267 267 def dispatcher(msg):
268 268 return self.dispatch_shell(stream, msg)
269 269 return dispatcher
270 270
271 271 for s in self.shell_streams:
272 272 s.on_recv(make_dispatcher(s), copy=False)
273 273
274 274 def do_one_iteration(self):
275 275 """step eventloop just once"""
276 276 if self.control_stream:
277 277 self.control_stream.flush()
278 278 for stream in self.shell_streams:
279 279 # handle at most one request per iteration
280 280 stream.flush(zmq.POLLIN, 1)
281 281 stream.flush(zmq.POLLOUT)
282 282
283 283
284 284 def record_ports(self, ports):
285 285 """Record the ports that this kernel is using.
286 286
287 287 The creator of the Kernel instance must call this methods if they
288 288 want the :meth:`connect_request` method to return the port numbers.
289 289 """
290 290 self._recorded_ports = ports
291 291
292 292 #---------------------------------------------------------------------------
293 293 # Kernel request handlers
294 294 #---------------------------------------------------------------------------
295 295
296 296 def _make_metadata(self, other=None):
297 297 """init metadata dict, for execute/apply_reply"""
298 298 new_md = {
299 299 'dependencies_met' : True,
300 300 'engine' : self.ident,
301 301 'started': datetime.now(),
302 302 }
303 303 if other:
304 304 new_md.update(other)
305 305 return new_md
306 306
307 307 def _publish_pyin(self, code, parent, execution_count):
308 308 """Publish the code request on the pyin stream."""
309 309
310 310 self.session.send(self.iopub_socket, u'pyin',
311 311 {u'code':code, u'execution_count': execution_count},
312 312 parent=parent, ident=self._topic('pyin')
313 313 )
314 314
315 315 def _publish_status(self, status, parent=None):
316 316 """send status (busy/idle) on IOPub"""
317 317 self.session.send(self.iopub_socket,
318 318 u'status',
319 319 {u'execution_state': status},
320 320 parent=parent,
321 321 ident=self._topic('status'),
322 322 )
323 323
324 324
325 325 def execute_request(self, stream, ident, parent):
326 326 """handle an execute_request"""
327 327
328 328 self._publish_status(u'busy', parent)
329 329
330 330 try:
331 331 content = parent[u'content']
332 332 code = content[u'code']
333 333 silent = content[u'silent']
334 334 store_history = content.get(u'store_history', not silent)
335 335 except:
336 336 self.log.error("Got bad msg: ")
337 337 self.log.error("%s", parent)
338 338 return
339 339
340 340 md = self._make_metadata(parent['metadata'])
341 341
342 342 shell = self.shell # we'll need this a lot here
343 343
344 344 # Replace raw_input. Note that is not sufficient to replace
345 345 # raw_input in the user namespace.
346 346 if content.get('allow_stdin', False):
347 347 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
348 348 else:
349 349 raw_input = lambda prompt='' : self._no_raw_input()
350 350
351 351 if py3compat.PY3:
352 352 __builtin__.input = raw_input
353 353 else:
354 354 __builtin__.raw_input = raw_input
355 355
356 356 # Set the parent message of the display hook and out streams.
357 357 shell.displayhook.set_parent(parent)
358 358 shell.display_pub.set_parent(parent)
359 359 shell.data_pub.set_parent(parent)
360 360 sys.stdout.set_parent(parent)
361 361 sys.stderr.set_parent(parent)
362 362
363 363 # Re-broadcast our input for the benefit of listening clients, and
364 364 # start computing output
365 365 if not silent:
366 366 self._publish_pyin(code, parent, shell.execution_count)
367 367
368 368 reply_content = {}
369 369 try:
370 370 # FIXME: the shell calls the exception handler itself.
371 371 shell.run_cell(code, store_history=store_history, silent=silent)
372 372 except:
373 373 status = u'error'
374 374 # FIXME: this code right now isn't being used yet by default,
375 375 # because the run_cell() call above directly fires off exception
376 376 # reporting. This code, therefore, is only active in the scenario
377 377 # where runlines itself has an unhandled exception. We need to
378 378 # uniformize this, for all exception construction to come from a
379 379 # single location in the codbase.
380 380 etype, evalue, tb = sys.exc_info()
381 381 tb_list = traceback.format_exception(etype, evalue, tb)
382 382 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
383 383 else:
384 384 status = u'ok'
385 385
386 386 reply_content[u'status'] = status
387 387
388 388 # Return the execution counter so clients can display prompts
389 389 reply_content['execution_count'] = shell.execution_count - 1
390 390
391 391 # FIXME - fish exception info out of shell, possibly left there by
392 392 # runlines. We'll need to clean up this logic later.
393 393 if shell._reply_content is not None:
394 394 reply_content.update(shell._reply_content)
395 395 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
396 396 reply_content['engine_info'] = e_info
397 397 # reset after use
398 398 shell._reply_content = None
399 399
400 400 # At this point, we can tell whether the main code execution succeeded
401 401 # or not. If it did, we proceed to evaluate user_variables/expressions
402 402 if reply_content['status'] == 'ok':
403 403 reply_content[u'user_variables'] = \
404 404 shell.user_variables(content.get(u'user_variables', []))
405 405 reply_content[u'user_expressions'] = \
406 406 shell.user_expressions(content.get(u'user_expressions', {}))
407 407 else:
408 408 # If there was an error, don't even try to compute variables or
409 409 # expressions
410 410 reply_content[u'user_variables'] = {}
411 411 reply_content[u'user_expressions'] = {}
412 412
413 413 # Payloads should be retrieved regardless of outcome, so we can both
414 414 # recover partial output (that could have been generated early in a
415 415 # block, before an error) and clear the payload system always.
416 416 reply_content[u'payload'] = shell.payload_manager.read_payload()
417 417 # Be agressive about clearing the payload because we don't want
418 418 # it to sit in memory until the next execute_request comes in.
419 419 shell.payload_manager.clear_payload()
420 420
421 421 # Flush output before sending the reply.
422 422 sys.stdout.flush()
423 423 sys.stderr.flush()
424 424 # FIXME: on rare occasions, the flush doesn't seem to make it to the
425 425 # clients... This seems to mitigate the problem, but we definitely need
426 426 # to better understand what's going on.
427 427 if self._execute_sleep:
428 428 time.sleep(self._execute_sleep)
429 429
430 430 # Send the reply.
431 431 reply_content = json_clean(reply_content)
432 432
433 433 md['status'] = reply_content['status']
434 434 if reply_content['status'] == 'error' and \
435 435 reply_content['ename'] == 'UnmetDependency':
436 436 md['dependencies_met'] = False
437 437
438 438 reply_msg = self.session.send(stream, u'execute_reply',
439 439 reply_content, parent, metadata=md,
440 440 ident=ident)
441 441
442 442 self.log.debug("%s", reply_msg)
443 443
444 444 if not silent and reply_msg['content']['status'] == u'error':
445 445 self._abort_queues()
446 446
447 447 self._publish_status(u'idle', parent)
448 448
449 449 def complete_request(self, stream, ident, parent):
450 450 txt, matches = self._complete(parent)
451 451 matches = {'matches' : matches,
452 452 'matched_text' : txt,
453 453 'status' : 'ok'}
454 454 matches = json_clean(matches)
455 455 completion_msg = self.session.send(stream, 'complete_reply',
456 456 matches, parent, ident)
457 457 self.log.debug("%s", completion_msg)
458 458
459 459 def object_info_request(self, stream, ident, parent):
460 460 content = parent['content']
461 461 object_info = self.shell.object_inspect(content['oname'],
462 462 detail_level = content.get('detail_level', 0)
463 463 )
464 464 # Before we send this object over, we scrub it for JSON usage
465 465 oinfo = json_clean(object_info)
466 466 msg = self.session.send(stream, 'object_info_reply',
467 467 oinfo, parent, ident)
468 468 self.log.debug("%s", msg)
469 469
470 470 def history_request(self, stream, ident, parent):
471 471 # We need to pull these out, as passing **kwargs doesn't work with
472 472 # unicode keys before Python 2.6.5.
473 473 hist_access_type = parent['content']['hist_access_type']
474 474 raw = parent['content']['raw']
475 475 output = parent['content']['output']
476 476 if hist_access_type == 'tail':
477 477 n = parent['content']['n']
478 478 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
479 479 include_latest=True)
480 480
481 481 elif hist_access_type == 'range':
482 482 session = parent['content']['session']
483 483 start = parent['content']['start']
484 484 stop = parent['content']['stop']
485 485 hist = self.shell.history_manager.get_range(session, start, stop,
486 486 raw=raw, output=output)
487 487
488 488 elif hist_access_type == 'search':
489 n = parent['content']['n']
489 490 pattern = parent['content']['pattern']
490 491 hist = self.shell.history_manager.search(pattern, raw=raw,
491 output=output)
492 output=output, n=n)
492 493
493 494 else:
494 495 hist = []
495 496 hist = list(hist)
496 497 content = {'history' : hist}
497 498 content = json_clean(content)
498 499 msg = self.session.send(stream, 'history_reply',
499 500 content, parent, ident)
500 501 self.log.debug("Sending history reply with %i entries", len(hist))
501 502
502 503 def connect_request(self, stream, ident, parent):
503 504 if self._recorded_ports is not None:
504 505 content = self._recorded_ports.copy()
505 506 else:
506 507 content = {}
507 508 msg = self.session.send(stream, 'connect_reply',
508 509 content, parent, ident)
509 510 self.log.debug("%s", msg)
510 511
511 512 def shutdown_request(self, stream, ident, parent):
512 513 self.shell.exit_now = True
513 514 content = dict(status='ok')
514 515 content.update(parent['content'])
515 516 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
516 517 # same content, but different msg_id for broadcasting on IOPub
517 518 self._shutdown_message = self.session.msg(u'shutdown_reply',
518 519 content, parent
519 520 )
520 521
521 522 self._at_shutdown()
522 523 # call sys.exit after a short delay
523 524 loop = ioloop.IOLoop.instance()
524 525 loop.add_timeout(time.time()+0.1, loop.stop)
525 526
526 527 #---------------------------------------------------------------------------
527 528 # Engine methods
528 529 #---------------------------------------------------------------------------
529 530
530 531 def apply_request(self, stream, ident, parent):
531 532 try:
532 533 content = parent[u'content']
533 534 bufs = parent[u'buffers']
534 535 msg_id = parent['header']['msg_id']
535 536 except:
536 537 self.log.error("Got bad msg: %s", parent, exc_info=True)
537 538 return
538 539
539 540 self._publish_status(u'busy', parent)
540 541
541 542 # Set the parent message of the display hook and out streams.
542 543 shell = self.shell
543 544 shell.displayhook.set_parent(parent)
544 545 shell.display_pub.set_parent(parent)
545 546 shell.data_pub.set_parent(parent)
546 547 sys.stdout.set_parent(parent)
547 548 sys.stderr.set_parent(parent)
548 549
549 550 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
550 551 # self.iopub_socket.send(pyin_msg)
551 552 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
552 553 md = self._make_metadata(parent['metadata'])
553 554 try:
554 555 working = shell.user_ns
555 556
556 557 prefix = "_"+str(msg_id).replace("-","")+"_"
557 558
558 559 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
559 560
560 561 fname = getattr(f, '__name__', 'f')
561 562
562 563 fname = prefix+"f"
563 564 argname = prefix+"args"
564 565 kwargname = prefix+"kwargs"
565 566 resultname = prefix+"result"
566 567
567 568 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
568 569 # print ns
569 570 working.update(ns)
570 571 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
571 572 try:
572 573 exec code in shell.user_global_ns, shell.user_ns
573 574 result = working.get(resultname)
574 575 finally:
575 576 for key in ns.iterkeys():
576 577 working.pop(key)
577 578
578 579 result_buf = serialize_object(result,
579 580 buffer_threshold=self.session.buffer_threshold,
580 581 item_threshold=self.session.item_threshold,
581 582 )
582 583
583 584 except:
584 585 # invoke IPython traceback formatting
585 586 shell.showtraceback()
586 587 # FIXME - fish exception info out of shell, possibly left there by
587 588 # run_code. We'll need to clean up this logic later.
588 589 reply_content = {}
589 590 if shell._reply_content is not None:
590 591 reply_content.update(shell._reply_content)
591 592 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
592 593 reply_content['engine_info'] = e_info
593 594 # reset after use
594 595 shell._reply_content = None
595 596
596 597 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
597 598 ident=self._topic('pyerr'))
598 599 result_buf = []
599 600
600 601 if reply_content['ename'] == 'UnmetDependency':
601 602 md['dependencies_met'] = False
602 603 else:
603 604 reply_content = {'status' : 'ok'}
604 605
605 606 # put 'ok'/'error' status in header, for scheduler introspection:
606 607 md['status'] = reply_content['status']
607 608
608 609 # flush i/o
609 610 sys.stdout.flush()
610 611 sys.stderr.flush()
611 612
612 613 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
613 614 parent=parent, ident=ident,buffers=result_buf, metadata=md)
614 615
615 616 self._publish_status(u'idle', parent)
616 617
617 618 #---------------------------------------------------------------------------
618 619 # Control messages
619 620 #---------------------------------------------------------------------------
620 621
621 622 def abort_request(self, stream, ident, parent):
622 623 """abort a specifig msg by id"""
623 624 msg_ids = parent['content'].get('msg_ids', None)
624 625 if isinstance(msg_ids, basestring):
625 626 msg_ids = [msg_ids]
626 627 if not msg_ids:
627 628 self.abort_queues()
628 629 for mid in msg_ids:
629 630 self.aborted.add(str(mid))
630 631
631 632 content = dict(status='ok')
632 633 reply_msg = self.session.send(stream, 'abort_reply', content=content,
633 634 parent=parent, ident=ident)
634 635 self.log.debug("%s", reply_msg)
635 636
636 637 def clear_request(self, stream, idents, parent):
637 638 """Clear our namespace."""
638 639 self.shell.reset(False)
639 640 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
640 641 content = dict(status='ok'))
641 642
642 643
643 644 #---------------------------------------------------------------------------
644 645 # Protected interface
645 646 #---------------------------------------------------------------------------
646 647
647 648
648 649 def _wrap_exception(self, method=None):
649 650 # import here, because _wrap_exception is only used in parallel,
650 651 # and parallel has higher min pyzmq version
651 652 from IPython.parallel.error import wrap_exception
652 653 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
653 654 content = wrap_exception(e_info)
654 655 return content
655 656
656 657 def _topic(self, topic):
657 658 """prefixed topic for IOPub messages"""
658 659 if self.int_id >= 0:
659 660 base = "engine.%i" % self.int_id
660 661 else:
661 662 base = "kernel.%s" % self.ident
662 663
663 664 return py3compat.cast_bytes("%s.%s" % (base, topic))
664 665
665 666 def _abort_queues(self):
666 667 for stream in self.shell_streams:
667 668 if stream:
668 669 self._abort_queue(stream)
669 670
670 671 def _abort_queue(self, stream):
671 672 poller = zmq.Poller()
672 673 poller.register(stream.socket, zmq.POLLIN)
673 674 while True:
674 675 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
675 676 if msg is None:
676 677 return
677 678
678 679 self.log.info("Aborting:")
679 680 self.log.info("%s", msg)
680 681 msg_type = msg['header']['msg_type']
681 682 reply_type = msg_type.split('_')[0] + '_reply'
682 683
683 684 status = {'status' : 'aborted'}
684 685 md = {'engine' : self.ident}
685 686 md.update(status)
686 687 reply_msg = self.session.send(stream, reply_type, metadata=md,
687 688 content=status, parent=msg, ident=idents)
688 689 self.log.debug("%s", reply_msg)
689 690 # We need to wait a bit for requests to come in. This can probably
690 691 # be set shorter for true asynchronous clients.
691 692 poller.poll(50)
692 693
693 694
694 695 def _no_raw_input(self):
695 696 """Raise StdinNotImplentedError if active frontend doesn't support
696 697 stdin."""
697 698 raise StdinNotImplementedError("raw_input was called, but this "
698 699 "frontend does not support stdin.")
699 700
700 701 def _raw_input(self, prompt, ident, parent):
701 702 # Flush output before making the request.
702 703 sys.stderr.flush()
703 704 sys.stdout.flush()
704 705
705 706 # Send the input request.
706 707 content = json_clean(dict(prompt=prompt))
707 708 self.session.send(self.stdin_socket, u'input_request', content, parent,
708 709 ident=ident)
709 710
710 711 # Await a response.
711 712 while True:
712 713 try:
713 714 ident, reply = self.session.recv(self.stdin_socket, 0)
714 715 except Exception:
715 716 self.log.warn("Invalid Message:", exc_info=True)
716 717 else:
717 718 break
718 719 try:
719 720 value = reply['content']['value']
720 721 except:
721 722 self.log.error("Got bad raw_input reply: ")
722 723 self.log.error("%s", parent)
723 724 value = ''
724 725 if value == '\x04':
725 726 # EOF
726 727 raise EOFError
727 728 return value
728 729
729 730 def _complete(self, msg):
730 731 c = msg['content']
731 732 try:
732 733 cpos = int(c['cursor_pos'])
733 734 except:
734 735 # If we don't get something that we can convert to an integer, at
735 736 # least attempt the completion guessing the cursor is at the end of
736 737 # the text, if there's any, and otherwise of the line
737 738 cpos = len(c['text'])
738 739 if cpos==0:
739 740 cpos = len(c['line'])
740 741 return self.shell.complete(c['text'], c['line'], cpos)
741 742
742 743 def _object_info(self, context):
743 744 symbol, leftover = self._symbol_from_context(context)
744 745 if symbol is not None and not leftover:
745 746 doc = getattr(symbol, '__doc__', '')
746 747 else:
747 748 doc = ''
748 749 object_info = dict(docstring = doc)
749 750 return object_info
750 751
751 752 def _symbol_from_context(self, context):
752 753 if not context:
753 754 return None, context
754 755
755 756 base_symbol_string = context[0]
756 757 symbol = self.shell.user_ns.get(base_symbol_string, None)
757 758 if symbol is None:
758 759 symbol = __builtin__.__dict__.get(base_symbol_string, None)
759 760 if symbol is None:
760 761 return None, context
761 762
762 763 context = context[1:]
763 764 for i, name in enumerate(context):
764 765 new_symbol = getattr(symbol, name, None)
765 766 if new_symbol is None:
766 767 return symbol, context[i:]
767 768 else:
768 769 symbol = new_symbol
769 770
770 771 return symbol, []
771 772
772 773 def _at_shutdown(self):
773 774 """Actions taken at shutdown by the kernel, called by python's atexit.
774 775 """
775 776 # io.rprint("Kernel at_shutdown") # dbg
776 777 if self._shutdown_message is not None:
777 778 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
778 779 self.log.debug("%s", self._shutdown_message)
779 780 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
780 781
781 782 #-----------------------------------------------------------------------------
782 783 # Aliases and Flags for the IPKernelApp
783 784 #-----------------------------------------------------------------------------
784 785
785 786 flags = dict(kernel_flags)
786 787 flags.update(shell_flags)
787 788
788 789 addflag = lambda *args: flags.update(boolean_flag(*args))
789 790
790 791 flags['pylab'] = (
791 792 {'IPKernelApp' : {'pylab' : 'auto'}},
792 793 """Pre-load matplotlib and numpy for interactive use with
793 794 the default matplotlib backend."""
794 795 )
795 796
796 797 aliases = dict(kernel_aliases)
797 798 aliases.update(shell_aliases)
798 799
799 800 #-----------------------------------------------------------------------------
800 801 # The IPKernelApp class
801 802 #-----------------------------------------------------------------------------
802 803
803 804 class IPKernelApp(KernelApp, InteractiveShellApp):
804 805 name = 'ipkernel'
805 806
806 807 aliases = Dict(aliases)
807 808 flags = Dict(flags)
808 809 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
809 810
810 811 @catch_config_error
811 812 def initialize(self, argv=None):
812 813 super(IPKernelApp, self).initialize(argv)
813 814 self.init_path()
814 815 self.init_shell()
815 816 self.init_gui_pylab()
816 817 self.init_extensions()
817 818 self.init_code()
818 819
819 820 def init_kernel(self):
820 821
821 822 shell_stream = ZMQStream(self.shell_socket)
822 823
823 824 kernel = Kernel(config=self.config, session=self.session,
824 825 shell_streams=[shell_stream],
825 826 iopub_socket=self.iopub_socket,
826 827 stdin_socket=self.stdin_socket,
827 828 log=self.log,
828 829 profile_dir=self.profile_dir,
829 830 )
830 831 self.kernel = kernel
831 832 kernel.record_ports(self.ports)
832 833 shell = kernel.shell
833 834
834 835 def init_gui_pylab(self):
835 836 """Enable GUI event loop integration, taking pylab into account."""
836 837
837 838 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
838 839 # to ensure that any exception is printed straight to stderr.
839 840 # Normally _showtraceback associates the reply with an execution,
840 841 # which means frontends will never draw it, as this exception
841 842 # is not associated with any execute request.
842 843
843 844 shell = self.shell
844 845 _showtraceback = shell._showtraceback
845 846 try:
846 847 # replace pyerr-sending traceback with stderr
847 848 def print_tb(etype, evalue, stb):
848 849 print ("GUI event loop or pylab initialization failed",
849 850 file=io.stderr)
850 851 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
851 852 shell._showtraceback = print_tb
852 853 InteractiveShellApp.init_gui_pylab(self)
853 854 finally:
854 855 shell._showtraceback = _showtraceback
855 856
856 857 def init_shell(self):
857 858 self.shell = self.kernel.shell
858 859 self.shell.configurables.append(self)
859 860
860 861
861 862 #-----------------------------------------------------------------------------
862 863 # Kernel main and launch functions
863 864 #-----------------------------------------------------------------------------
864 865
865 866 def launch_kernel(*args, **kwargs):
866 867 """Launches a localhost IPython kernel, binding to the specified ports.
867 868
868 869 This function simply calls entry_point.base_launch_kernel with the right
869 870 first command to start an ipkernel. See base_launch_kernel for arguments.
870 871
871 872 Returns
872 873 -------
873 874 A tuple of form:
874 875 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
875 876 where kernel_process is a Popen object and the ports are integers.
876 877 """
877 878 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
878 879 *args, **kwargs)
879 880
880 881
881 882 def embed_kernel(module=None, local_ns=None, **kwargs):
882 883 """Embed and start an IPython kernel in a given scope.
883 884
884 885 Parameters
885 886 ----------
886 887 module : ModuleType, optional
887 888 The module to load into IPython globals (default: caller)
888 889 local_ns : dict, optional
889 890 The namespace to load into IPython user namespace (default: caller)
890 891
891 892 kwargs : various, optional
892 893 Further keyword args are relayed to the KernelApp constructor,
893 894 allowing configuration of the Kernel. Will only have an effect
894 895 on the first embed_kernel call for a given process.
895 896
896 897 """
897 898 # get the app if it exists, or set it up if it doesn't
898 899 if IPKernelApp.initialized():
899 900 app = IPKernelApp.instance()
900 901 else:
901 902 app = IPKernelApp.instance(**kwargs)
902 903 app.initialize([])
903 904 # Undo unnecessary sys module mangling from init_sys_modules.
904 905 # This would not be necessary if we could prevent it
905 906 # in the first place by using a different InteractiveShell
906 907 # subclass, as in the regular embed case.
907 908 main = app.kernel.shell._orig_sys_modules_main_mod
908 909 if main is not None:
909 910 sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main
910 911
911 912 # load the calling scope if not given
912 913 (caller_module, caller_locals) = extract_module_locals(1)
913 914 if module is None:
914 915 module = caller_module
915 916 if local_ns is None:
916 917 local_ns = caller_locals
917 918
918 919 app.kernel.user_module = module
919 920 app.kernel.user_ns = local_ns
920 921 app.shell.set_completer_frame()
921 922 app.start()
922 923
923 924 def main():
924 925 """Run an IPKernel as an application"""
925 926 app = IPKernelApp.instance()
926 927 app.initialize()
927 928 app.start()
928 929
929 930
930 931 if __name__ == '__main__':
931 932 main()
@@ -1,1002 +1,1002 b''
1 1 .. _messaging:
2 2
3 3 ======================
4 4 Messaging in IPython
5 5 ======================
6 6
7 7
8 8 Introduction
9 9 ============
10 10
11 11 This document explains the basic communications design and messaging
12 12 specification for how the various IPython objects interact over a network
13 13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 14 within and between hosts.
15 15
16 16 .. Note::
17 17
18 18 This document should be considered the authoritative description of the
19 19 IPython messaging protocol, and all developers are strongly encouraged to
20 20 keep it updated as the implementation evolves, so that we have a single
21 21 common reference for all protocol details.
22 22
23 23 The basic design is explained in the following diagram:
24 24
25 25 .. image:: figs/frontend-kernel.png
26 26 :width: 450px
27 27 :alt: IPython kernel/frontend messaging architecture.
28 28 :align: center
29 29 :target: ../_images/frontend-kernel.png
30 30
31 31 A single kernel can be simultaneously connected to one or more frontends. The
32 32 kernel has three sockets that serve the following functions:
33 33
34 34 1. stdin: this ROUTER socket is connected to all frontends, and it allows
35 35 the kernel to request input from the active frontend when :func:`raw_input` is called.
36 36 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
37 37 for the kernel while this communication is happening (illustrated in the
38 38 figure by the black outline around the central keyboard). In practice,
39 39 frontends may display such kernel requests using a special input widget or
40 40 otherwise indicating that the user is to type input for the kernel instead
41 41 of normal commands in the frontend.
42 42
43 43 2. Shell: this single ROUTER socket allows multiple incoming connections from
44 44 frontends, and this is the socket where requests for code execution, object
45 45 information, prompts, etc. are made to the kernel by any frontend. The
46 46 communication on this socket is a sequence of request/reply actions from
47 47 each frontend and the kernel.
48 48
49 49 3. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
50 50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 51 client over the shell socket and its own requests on the stdin socket. There
52 52 are a number of actions in Python which generate side effects: :func:`print`
53 53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 54 a multi-client scenario, we want all frontends to be able to know what each
55 55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 56 for example). This socket allows both side effects and the information
57 57 about communications taking place with one client over the shell channel
58 58 to be made available to all clients in a uniform manner.
59 59
60 60 All messages are tagged with enough information (details below) for clients
61 61 to know which messages come from their own interaction with the kernel and
62 62 which ones are from other clients, so they can display each type
63 63 appropriately.
64 64
65 65 The actual format of the messages allowed on each of these channels is
66 66 specified below. Messages are dicts of dicts with string keys and values that
67 67 are reasonably representable in JSON. Our current implementation uses JSON
68 68 explicitly as its message format, but this shouldn't be considered a permanent
69 69 feature. As we've discovered that JSON has non-trivial performance issues due
70 70 to excessive copying, we may in the future move to a pure pickle-based raw
71 71 message format. However, it should be possible to easily convert from the raw
72 72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 73 As long as it's easy to make a JSON version of the objects that is a faithful
74 74 representation of all the data, we can communicate with such clients.
75 75
76 76 .. Note::
77 77
78 78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 79 kernel and frontend files for actual implementation details.
80 80
81 81 General Message Format
82 82 ======================
83 83
84 84 A message is defined by the following four-dictionary structure::
85 85
86 86 {
87 87 # The message header contains a pair of unique identifiers for the
88 88 # originating session and the actual message id, in addition to the
89 89 # username for the process that generated the message. This is useful in
90 90 # collaborative settings where multiple users may be interacting with the
91 91 # same kernel simultaneously, so that frontends can label the various
92 92 # messages in a meaningful way.
93 93 'header' : {
94 94 'msg_id' : uuid,
95 95 'username' : str,
96 96 'session' : uuid
97 97 # All recognized message type strings are listed below.
98 98 'msg_type' : str,
99 99 },
100 100
101 101 # In a chain of messages, the header from the parent is copied so that
102 102 # clients can track where messages come from.
103 103 'parent_header' : dict,
104 104
105 105 # The actual content of the message must be a dict, whose structure
106 106 # depends on the message type.
107 107 'content' : dict,
108 108
109 109 # Any metadata associated with the message.
110 110 'metadata' : dict,
111 111 }
112 112
113 113
114 114 Python functional API
115 115 =====================
116 116
117 117 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
118 118 should develop, at a few key points, functional forms of all the requests that
119 119 take arguments in this manner and automatically construct the necessary dict
120 120 for sending.
121 121
122 122 In addition, the Python implementation of the message specification extends
123 123 messages upon deserialization to the following form for convenience::
124 124
125 125 {
126 126 'header' : dict,
127 127 # The msg's unique identifier and type are always stored in the header,
128 128 # but the Python implementation copies them to the top level.
129 129 'msg_id' : uuid,
130 130 'msg_type' : str,
131 131 'parent_header' : dict,
132 132 'content' : dict,
133 133 'metadata' : dict,
134 134 }
135 135
136 136 All messages sent to or received by any IPython process should have this
137 137 extended structure.
138 138
139 139
140 140 Messages on the shell ROUTER/DEALER sockets
141 141 ===========================================
142 142
143 143 .. _execute:
144 144
145 145 Execute
146 146 -------
147 147
148 148 This message type is used by frontends to ask the kernel to execute code on
149 149 behalf of the user, in a namespace reserved to the user's variables (and thus
150 150 separate from the kernel's own internal code and variables).
151 151
152 152 Message type: ``execute_request``::
153 153
154 154 content = {
155 155 # Source code to be executed by the kernel, one or more lines.
156 156 'code' : str,
157 157
158 158 # A boolean flag which, if True, signals the kernel to execute
159 159 # this code as quietly as possible. This means that the kernel
160 160 # will compile the code with 'exec' instead of 'single' (so
161 161 # sys.displayhook will not fire), forces store_history to be False,
162 162 # and will *not*:
163 163 # - broadcast exceptions on the PUB socket
164 164 # - do any logging
165 165 #
166 166 # The default is False.
167 167 'silent' : bool,
168 168
169 169 # A boolean flag which, if True, signals the kernel to populate history
170 170 # The default is True if silent is False. If silent is True, store_history
171 171 # is forced to be False.
172 172 'store_history' : bool,
173 173
174 174 # A list of variable names from the user's namespace to be retrieved. What
175 175 # returns is a JSON string of the variable's repr(), not a python object.
176 176 'user_variables' : list,
177 177
178 178 # Similarly, a dict mapping names to expressions to be evaluated in the
179 179 # user's dict.
180 180 'user_expressions' : dict,
181 181
182 182 # Some frontends (e.g. the Notebook) do not support stdin requests. If
183 183 # raw_input is called from code executed from such a frontend, a
184 184 # StdinNotImplementedError will be raised.
185 185 'allow_stdin' : True,
186 186
187 187 }
188 188
189 189 The ``code`` field contains a single string (possibly multiline). The kernel
190 190 is responsible for splitting this into one or more independent execution blocks
191 191 and deciding whether to compile these in 'single' or 'exec' mode (see below for
192 192 detailed execution semantics).
193 193
194 194 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
195 195 the notion of a prompt string that allowed arbitrary code to be evaluated, and
196 196 this was put to good use by many in creating prompts that displayed system
197 197 status, path information, and even more esoteric uses like remote instrument
198 198 status aqcuired over the network. But now that IPython has a clean separation
199 199 between the kernel and the clients, the kernel has no prompt knowledge; prompts
200 200 are a frontend-side feature, and it should be even possible for different
201 201 frontends to display different prompts while interacting with the same kernel.
202 202
203 203 The kernel now provides the ability to retrieve data from the user's namespace
204 204 after the execution of the main ``code``, thanks to two fields in the
205 205 ``execute_request`` message:
206 206
207 207 - ``user_variables``: If only variables from the user's namespace are needed, a
208 208 list of variable names can be passed and a dict with these names as keys and
209 209 their :func:`repr()` as values will be returned.
210 210
211 211 - ``user_expressions``: For more complex expressions that require function
212 212 evaluations, a dict can be provided with string keys and arbitrary python
213 213 expressions as values. The return message will contain also a dict with the
214 214 same keys and the :func:`repr()` of the evaluated expressions as value.
215 215
216 216 With this information, frontends can display any status information they wish
217 217 in the form that best suits each frontend (a status line, a popup, inline for a
218 218 terminal, etc).
219 219
220 220 .. Note::
221 221
222 222 In order to obtain the current execution counter for the purposes of
223 223 displaying input prompts, frontends simply make an execution request with an
224 224 empty code string and ``silent=True``.
225 225
226 226 Execution semantics
227 227 ~~~~~~~~~~~~~~~~~~~
228 228
229 229 When the silent flag is false, the execution of use code consists of the
230 230 following phases (in silent mode, only the ``code`` field is executed):
231 231
232 232 1. Run the ``pre_runcode_hook``.
233 233
234 234 2. Execute the ``code`` field, see below for details.
235 235
236 236 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
237 237 computed. This ensures that any error in the latter don't harm the main
238 238 code execution.
239 239
240 240 4. Call any method registered with :meth:`register_post_execute`.
241 241
242 242 .. warning::
243 243
244 244 The API for running code before/after the main code block is likely to
245 245 change soon. Both the ``pre_runcode_hook`` and the
246 246 :meth:`register_post_execute` are susceptible to modification, as we find a
247 247 consistent model for both.
248 248
249 249 To understand how the ``code`` field is executed, one must know that Python
250 250 code can be compiled in one of three modes (controlled by the ``mode`` argument
251 251 to the :func:`compile` builtin):
252 252
253 253 *single*
254 254 Valid for a single interactive statement (though the source can contain
255 255 multiple lines, such as a for loop). When compiled in this mode, the
256 256 generated bytecode contains special instructions that trigger the calling of
257 257 :func:`sys.displayhook` for any expression in the block that returns a value.
258 258 This means that a single statement can actually produce multiple calls to
259 259 :func:`sys.displayhook`, if for example it contains a loop where each
260 260 iteration computes an unassigned expression would generate 10 calls::
261 261
262 262 for i in range(10):
263 263 i**2
264 264
265 265 *exec*
266 266 An arbitrary amount of source code, this is how modules are compiled.
267 267 :func:`sys.displayhook` is *never* implicitly called.
268 268
269 269 *eval*
270 270 A single expression that returns a value. :func:`sys.displayhook` is *never*
271 271 implicitly called.
272 272
273 273
274 274 The ``code`` field is split into individual blocks each of which is valid for
275 275 execution in 'single' mode, and then:
276 276
277 277 - If there is only a single block: it is executed in 'single' mode.
278 278
279 279 - If there is more than one block:
280 280
281 281 * if the last one is a single line long, run all but the last in 'exec' mode
282 282 and the very last one in 'single' mode. This makes it easy to type simple
283 283 expressions at the end to see computed values.
284 284
285 285 * if the last one is no more than two lines long, run all but the last in
286 286 'exec' mode and the very last one in 'single' mode. This makes it easy to
287 287 type simple expressions at the end to see computed values. - otherwise
288 288 (last one is also multiline), run all in 'exec' mode
289 289
290 290 * otherwise (last one is also multiline), run all in 'exec' mode as a single
291 291 unit.
292 292
293 293 Any error in retrieving the ``user_variables`` or evaluating the
294 294 ``user_expressions`` will result in a simple error message in the return fields
295 295 of the form::
296 296
297 297 [ERROR] ExceptionType: Exception message
298 298
299 299 The user can simply send the same variable name or expression for evaluation to
300 300 see a regular traceback.
301 301
302 302 Errors in any registered post_execute functions are also reported similarly,
303 303 and the failing function is removed from the post_execution set so that it does
304 304 not continue triggering failures.
305 305
306 306 Upon completion of the execution request, the kernel *always* sends a reply,
307 307 with a status code indicating what happened and additional data depending on
308 308 the outcome. See :ref:`below <execution_results>` for the possible return
309 309 codes and associated data.
310 310
311 311
312 312 Execution counter (old prompt number)
313 313 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
314 314
315 315 The kernel has a single, monotonically increasing counter of all execution
316 316 requests that are made with ``store_history=True``. This counter is used to populate
317 317 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
318 318 display it in some form to the user, which will typically (but not necessarily)
319 319 be done in the prompts. The value of this counter will be returned as the
320 320 ``execution_count`` field of all ``execute_reply`` messages.
321 321
322 322 .. _execution_results:
323 323
324 324 Execution results
325 325 ~~~~~~~~~~~~~~~~~
326 326
327 327 Message type: ``execute_reply``::
328 328
329 329 content = {
330 330 # One of: 'ok' OR 'error' OR 'abort'
331 331 'status' : str,
332 332
333 333 # The global kernel counter that increases by one with each request that
334 334 # stores history. This will typically be used by clients to display
335 335 # prompt numbers to the user. If the request did not store history, this will
336 336 # be the current value of the counter in the kernel.
337 337 'execution_count' : int,
338 338 }
339 339
340 340 When status is 'ok', the following extra fields are present::
341 341
342 342 {
343 343 # 'payload' will be a list of payload dicts.
344 344 # Each execution payload is a dict with string keys that may have been
345 345 # produced by the code being executed. It is retrieved by the kernel at
346 346 # the end of the execution and sent back to the front end, which can take
347 347 # action on it as needed. See main text for further details.
348 348 'payload' : list(dict),
349 349
350 350 # Results for the user_variables and user_expressions.
351 351 'user_variables' : dict,
352 352 'user_expressions' : dict,
353 353 }
354 354
355 355 .. admonition:: Execution payloads
356 356
357 357 The notion of an 'execution payload' is different from a return value of a
358 358 given set of code, which normally is just displayed on the pyout stream
359 359 through the PUB socket. The idea of a payload is to allow special types of
360 360 code, typically magics, to populate a data container in the IPython kernel
361 361 that will be shipped back to the caller via this channel. The kernel
362 362 has an API for this in the PayloadManager::
363 363
364 364 ip.payload_manager.write_payload(payload_dict)
365 365
366 366 which appends a dictionary to the list of payloads.
367 367
368 368
369 369 When status is 'error', the following extra fields are present::
370 370
371 371 {
372 372 'ename' : str, # Exception name, as a string
373 373 'evalue' : str, # Exception value, as a string
374 374
375 375 # The traceback will contain a list of frames, represented each as a
376 376 # string. For now we'll stick to the existing design of ultraTB, which
377 377 # controls exception level of detail statefully. But eventually we'll
378 378 # want to grow into a model where more information is collected and
379 379 # packed into the traceback object, with clients deciding how little or
380 380 # how much of it to unpack. But for now, let's start with a simple list
381 381 # of strings, since that requires only minimal changes to ultratb as
382 382 # written.
383 383 'traceback' : list,
384 384 }
385 385
386 386
387 387 When status is 'abort', there are for now no additional data fields. This
388 388 happens when the kernel was interrupted by a signal.
389 389
390 390 Kernel attribute access
391 391 -----------------------
392 392
393 393 .. warning::
394 394
395 395 This part of the messaging spec is not actually implemented in the kernel
396 396 yet.
397 397
398 398 While this protocol does not specify full RPC access to arbitrary methods of
399 399 the kernel object, the kernel does allow read (and in some cases write) access
400 400 to certain attributes.
401 401
402 402 The policy for which attributes can be read is: any attribute of the kernel, or
403 403 its sub-objects, that belongs to a :class:`Configurable` object and has been
404 404 declared at the class-level with Traits validation, is in principle accessible
405 405 as long as its name does not begin with a leading underscore. The attribute
406 406 itself will have metadata indicating whether it allows remote read and/or write
407 407 access. The message spec follows for attribute read and write requests.
408 408
409 409 Message type: ``getattr_request``::
410 410
411 411 content = {
412 412 # The (possibly dotted) name of the attribute
413 413 'name' : str,
414 414 }
415 415
416 416 When a ``getattr_request`` fails, there are two possible error types:
417 417
418 418 - AttributeError: this type of error was raised when trying to access the
419 419 given name by the kernel itself. This means that the attribute likely
420 420 doesn't exist.
421 421
422 422 - AccessError: the attribute exists but its value is not readable remotely.
423 423
424 424
425 425 Message type: ``getattr_reply``::
426 426
427 427 content = {
428 428 # One of ['ok', 'AttributeError', 'AccessError'].
429 429 'status' : str,
430 430 # If status is 'ok', a JSON object.
431 431 'value' : object,
432 432 }
433 433
434 434 Message type: ``setattr_request``::
435 435
436 436 content = {
437 437 # The (possibly dotted) name of the attribute
438 438 'name' : str,
439 439
440 440 # A JSON-encoded object, that will be validated by the Traits
441 441 # information in the kernel
442 442 'value' : object,
443 443 }
444 444
445 445 When a ``setattr_request`` fails, there are also two possible error types with
446 446 similar meanings as those of the ``getattr_request`` case, but for writing.
447 447
448 448 Message type: ``setattr_reply``::
449 449
450 450 content = {
451 451 # One of ['ok', 'AttributeError', 'AccessError'].
452 452 'status' : str,
453 453 }
454 454
455 455
456 456
457 457 Object information
458 458 ------------------
459 459
460 460 One of IPython's most used capabilities is the introspection of Python objects
461 461 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
462 462 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
463 463 enough that it warrants an explicit message type, especially because frontends
464 464 may want to get object information in response to user keystrokes (like Tab or
465 465 F1) besides from the user explicitly typing code like ``x??``.
466 466
467 467 Message type: ``object_info_request``::
468 468
469 469 content = {
470 470 # The (possibly dotted) name of the object to be searched in all
471 471 # relevant namespaces
472 472 'name' : str,
473 473
474 474 # The level of detail desired. The default (0) is equivalent to typing
475 475 # 'x?' at the prompt, 1 is equivalent to 'x??'.
476 476 'detail_level' : int,
477 477 }
478 478
479 479 The returned information will be a dictionary with keys very similar to the
480 480 field names that IPython prints at the terminal.
481 481
482 482 Message type: ``object_info_reply``::
483 483
484 484 content = {
485 485 # The name the object was requested under
486 486 'name' : str,
487 487
488 488 # Boolean flag indicating whether the named object was found or not. If
489 489 # it's false, all other fields will be empty.
490 490 'found' : bool,
491 491
492 492 # Flags for magics and system aliases
493 493 'ismagic' : bool,
494 494 'isalias' : bool,
495 495
496 496 # The name of the namespace where the object was found ('builtin',
497 497 # 'magics', 'alias', 'interactive', etc.)
498 498 'namespace' : str,
499 499
500 500 # The type name will be type.__name__ for normal Python objects, but it
501 501 # can also be a string like 'Magic function' or 'System alias'
502 502 'type_name' : str,
503 503
504 504 # The string form of the object, possibly truncated for length if
505 505 # detail_level is 0
506 506 'string_form' : str,
507 507
508 508 # For objects with a __class__ attribute this will be set
509 509 'base_class' : str,
510 510
511 511 # For objects with a __len__ attribute this will be set
512 512 'length' : int,
513 513
514 514 # If the object is a function, class or method whose file we can find,
515 515 # we give its full path
516 516 'file' : str,
517 517
518 518 # For pure Python callable objects, we can reconstruct the object
519 519 # definition line which provides its call signature. For convenience this
520 520 # is returned as a single 'definition' field, but below the raw parts that
521 521 # compose it are also returned as the argspec field.
522 522 'definition' : str,
523 523
524 524 # The individual parts that together form the definition string. Clients
525 525 # with rich display capabilities may use this to provide a richer and more
526 526 # precise representation of the definition line (e.g. by highlighting
527 527 # arguments based on the user's cursor position). For non-callable
528 528 # objects, this field is empty.
529 529 'argspec' : { # The names of all the arguments
530 530 args : list,
531 531 # The name of the varargs (*args), if any
532 532 varargs : str,
533 533 # The name of the varkw (**kw), if any
534 534 varkw : str,
535 535 # The values (as strings) of all default arguments. Note
536 536 # that these must be matched *in reverse* with the 'args'
537 537 # list above, since the first positional args have no default
538 538 # value at all.
539 539 defaults : list,
540 540 },
541 541
542 542 # For instances, provide the constructor signature (the definition of
543 543 # the __init__ method):
544 544 'init_definition' : str,
545 545
546 546 # Docstrings: for any object (function, method, module, package) with a
547 547 # docstring, we show it. But in addition, we may provide additional
548 548 # docstrings. For example, for instances we will show the constructor
549 549 # and class docstrings as well, if available.
550 550 'docstring' : str,
551 551
552 552 # For instances, provide the constructor and class docstrings
553 553 'init_docstring' : str,
554 554 'class_docstring' : str,
555 555
556 556 # If it's a callable object whose call method has a separate docstring and
557 557 # definition line:
558 558 'call_def' : str,
559 559 'call_docstring' : str,
560 560
561 561 # If detail_level was 1, we also try to find the source code that
562 562 # defines the object, if possible. The string 'None' will indicate
563 563 # that no source was found.
564 564 'source' : str,
565 565 }
566 566
567 567
568 568 Complete
569 569 --------
570 570
571 571 Message type: ``complete_request``::
572 572
573 573 content = {
574 574 # The text to be completed, such as 'a.is'
575 575 'text' : str,
576 576
577 577 # The full line, such as 'print a.is'. This allows completers to
578 578 # make decisions that may require information about more than just the
579 579 # current word.
580 580 'line' : str,
581 581
582 582 # The entire block of text where the line is. This may be useful in the
583 583 # case of multiline completions where more context may be needed. Note: if
584 584 # in practice this field proves unnecessary, remove it to lighten the
585 585 # messages.
586 586
587 587 'block' : str,
588 588
589 589 # The position of the cursor where the user hit 'TAB' on the line.
590 590 'cursor_pos' : int,
591 591 }
592 592
593 593 Message type: ``complete_reply``::
594 594
595 595 content = {
596 596 # The list of all matches to the completion request, such as
597 597 # ['a.isalnum', 'a.isalpha'] for the above example.
598 598 'matches' : list
599 599 }
600 600
601 601
602 602 History
603 603 -------
604 604
605 605 For clients to explicitly request history from a kernel. The kernel has all
606 606 the actual execution history stored in a single location, so clients can
607 607 request it from the kernel when needed.
608 608
609 609 Message type: ``history_request``::
610 610
611 611 content = {
612 612
613 613 # If True, also return output history in the resulting dict.
614 614 'output' : bool,
615 615
616 616 # If True, return the raw input history, else the transformed input.
617 617 'raw' : bool,
618 618
619 619 # So far, this can be 'range', 'tail' or 'search'.
620 620 'hist_access_type' : str,
621 621
622 622 # If hist_access_type is 'range', get a range of input cells. session can
623 623 # be a positive session number, or a negative number to count back from
624 624 # the current session.
625 625 'session' : int,
626 626 # start and stop are line numbers within that session.
627 627 'start' : int,
628 628 'stop' : int,
629 629
630 # If hist_access_type is 'tail', get the last n cells.
630 # If hist_access_type is 'tail' or 'search', get the last n cells.
631 631 'n' : int,
632 632
633 633 # If hist_access_type is 'search', get cells matching the specified glob
634 634 # pattern (with * and ? as wildcards).
635 635 'pattern' : str,
636 636
637 637 }
638 638
639 639 Message type: ``history_reply``::
640 640
641 641 content = {
642 642 # A list of 3 tuples, either:
643 643 # (session, line_number, input) or
644 644 # (session, line_number, (input, output)),
645 645 # depending on whether output was False or True, respectively.
646 646 'history' : list,
647 647 }
648 648
649 649
650 650 Connect
651 651 -------
652 652
653 653 When a client connects to the request/reply socket of the kernel, it can issue
654 654 a connect request to get basic information about the kernel, such as the ports
655 655 the other ZeroMQ sockets are listening on. This allows clients to only have
656 656 to know about a single port (the shell channel) to connect to a kernel.
657 657
658 658 Message type: ``connect_request``::
659 659
660 660 content = {
661 661 }
662 662
663 663 Message type: ``connect_reply``::
664 664
665 665 content = {
666 666 'shell_port' : int # The port the shell ROUTER socket is listening on.
667 667 'iopub_port' : int # The port the PUB socket is listening on.
668 668 'stdin_port' : int # The port the stdin ROUTER socket is listening on.
669 669 'hb_port' : int # The port the heartbeat socket is listening on.
670 670 }
671 671
672 672
673 673
674 674 Kernel shutdown
675 675 ---------------
676 676
677 677 The clients can request the kernel to shut itself down; this is used in
678 678 multiple cases:
679 679
680 680 - when the user chooses to close the client application via a menu or window
681 681 control.
682 682 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
683 683 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
684 684 IPythonQt client) to force a kernel restart to get a clean kernel without
685 685 losing client-side state like history or inlined figures.
686 686
687 687 The client sends a shutdown request to the kernel, and once it receives the
688 688 reply message (which is otherwise empty), it can assume that the kernel has
689 689 completed shutdown safely.
690 690
691 691 Upon their own shutdown, client applications will typically execute a last
692 692 minute sanity check and forcefully terminate any kernel that is still alive, to
693 693 avoid leaving stray processes in the user's machine.
694 694
695 695 For both shutdown request and reply, there is no actual content that needs to
696 696 be sent, so the content dict is empty.
697 697
698 698 Message type: ``shutdown_request``::
699 699
700 700 content = {
701 701 'restart' : bool # whether the shutdown is final, or precedes a restart
702 702 }
703 703
704 704 Message type: ``shutdown_reply``::
705 705
706 706 content = {
707 707 'restart' : bool # whether the shutdown is final, or precedes a restart
708 708 }
709 709
710 710 .. Note::
711 711
712 712 When the clients detect a dead kernel thanks to inactivity on the heartbeat
713 713 socket, they simply send a forceful process termination signal, since a dead
714 714 process is unlikely to respond in any useful way to messages.
715 715
716 716
717 717 Messages on the PUB/SUB socket
718 718 ==============================
719 719
720 720 Streams (stdout, stderr, etc)
721 721 ------------------------------
722 722
723 723 Message type: ``stream``::
724 724
725 725 content = {
726 726 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
727 727 'name' : str,
728 728
729 729 # The data is an arbitrary string to be written to that stream
730 730 'data' : str,
731 731 }
732 732
733 733 When a kernel receives a raw_input call, it should also broadcast it on the pub
734 734 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
735 735 to monitor/display kernel interactions and possibly replay them to their user
736 736 or otherwise expose them.
737 737
738 738 Display Data
739 739 ------------
740 740
741 741 This type of message is used to bring back data that should be diplayed (text,
742 742 html, svg, etc.) in the frontends. This data is published to all frontends.
743 743 Each message can have multiple representations of the data; it is up to the
744 744 frontend to decide which to use and how. A single message should contain all
745 745 possible representations of the same information. Each representation should
746 746 be a JSON'able data structure, and should be a valid MIME type.
747 747
748 748 Some questions remain about this design:
749 749
750 750 * Do we use this message type for pyout/displayhook? Probably not, because
751 751 the displayhook also has to handle the Out prompt display. On the other hand
752 752 we could put that information into the metadata secion.
753 753
754 754 Message type: ``display_data``::
755 755
756 756 content = {
757 757
758 758 # Who create the data
759 759 'source' : str,
760 760
761 761 # The data dict contains key/value pairs, where the kids are MIME
762 762 # types and the values are the raw data of the representation in that
763 763 # format. The data dict must minimally contain the ``text/plain``
764 764 # MIME type which is used as a backup representation.
765 765 'data' : dict,
766 766
767 767 # Any metadata that describes the data
768 768 'metadata' : dict
769 769 }
770 770
771 771
772 772 Raw Data Publication
773 773 --------------------
774 774
775 775 ``display_data`` lets you publish *representations* of data, such as images and html.
776 776 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
777 777
778 778 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
779 779
780 780 .. sourcecode:: python
781 781
782 782 from IPython.zmq.datapub import publish_data
783 783 ns = dict(x=my_array)
784 784 publish_data(ns)
785 785
786 786
787 787 Message type: ``data_pub``::
788 788
789 789 content = {
790 790 # the keys of the data dict, after it has been unserialized
791 791 keys = ['a', 'b']
792 792 }
793 793 # the namespace dict will be serialized in the message buffers,
794 794 # which will have a length of at least one
795 795 buffers = ['pdict', ...]
796 796
797 797
798 798 The interpretation of a sequence of data_pub messages for a given parent request should be
799 799 to update a single namespace with subsequent results.
800 800
801 801 .. note::
802 802
803 803 No frontends directly handle data_pub messages at this time.
804 804 It is currently only used by the client/engines in :mod:`IPython.parallel`,
805 805 where engines may publish *data* to the Client,
806 806 of which the Client can then publish *representations* via ``display_data``
807 807 to various frontends.
808 808
809 809 Python inputs
810 810 -------------
811 811
812 812 These messages are the re-broadcast of the ``execute_request``.
813 813
814 814 Message type: ``pyin``::
815 815
816 816 content = {
817 817 'code' : str, # Source code to be executed, one or more lines
818 818
819 819 # The counter for this execution is also provided so that clients can
820 820 # display it, since IPython automatically creates variables called _iN
821 821 # (for input prompt In[N]).
822 822 'execution_count' : int
823 823 }
824 824
825 825 Python outputs
826 826 --------------
827 827
828 828 When Python produces output from code that has been compiled in with the
829 829 'single' flag to :func:`compile`, any expression that produces a value (such as
830 830 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
831 831 this value whatever it wants. The default behavior of ``sys.displayhook`` in
832 832 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
833 833 the value as long as it is not ``None`` (which isn't printed at all). In our
834 834 case, the kernel instantiates as ``sys.displayhook`` an object which has
835 835 similar behavior, but which instead of printing to stdout, broadcasts these
836 836 values as ``pyout`` messages for clients to display appropriately.
837 837
838 838 IPython's displayhook can handle multiple simultaneous formats depending on its
839 839 configuration. The default pretty-printed repr text is always given with the
840 840 ``data`` entry in this message. Any other formats are provided in the
841 841 ``extra_formats`` list. Frontends are free to display any or all of these
842 842 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
843 843 string, a type string, and the data. The ID is unique to the formatter
844 844 implementation that created the data. Frontends will typically ignore the ID
845 845 unless if it has requested a particular formatter. The type string tells the
846 846 frontend how to interpret the data. It is often, but not always a MIME type.
847 847 Frontends should ignore types that it does not understand. The data itself is
848 848 any JSON object and depends on the format. It is often, but not always a string.
849 849
850 850 Message type: ``pyout``::
851 851
852 852 content = {
853 853
854 854 # The counter for this execution is also provided so that clients can
855 855 # display it, since IPython automatically creates variables called _N
856 856 # (for prompt N).
857 857 'execution_count' : int,
858 858
859 859 # The data dict contains key/value pairs, where the kids are MIME
860 860 # types and the values are the raw data of the representation in that
861 861 # format. The data dict must minimally contain the ``text/plain``
862 862 # MIME type which is used as a backup representation.
863 863 'data' : dict,
864 864
865 865 }
866 866
867 867 Python errors
868 868 -------------
869 869
870 870 When an error occurs during code execution
871 871
872 872 Message type: ``pyerr``::
873 873
874 874 content = {
875 875 # Similar content to the execute_reply messages for the 'error' case,
876 876 # except the 'status' field is omitted.
877 877 }
878 878
879 879 Kernel status
880 880 -------------
881 881
882 882 This message type is used by frontends to monitor the status of the kernel.
883 883
884 884 Message type: ``status``::
885 885
886 886 content = {
887 887 # When the kernel starts to execute code, it will enter the 'busy'
888 888 # state and when it finishes, it will enter the 'idle' state.
889 889 execution_state : ('busy', 'idle')
890 890 }
891 891
892 892 Kernel crashes
893 893 --------------
894 894
895 895 When the kernel has an unexpected exception, caught by the last-resort
896 896 sys.excepthook, we should broadcast the crash handler's output before exiting.
897 897 This will allow clients to notice that a kernel died, inform the user and
898 898 propose further actions.
899 899
900 900 Message type: ``crash``::
901 901
902 902 content = {
903 903 # Similarly to the 'error' case for execute_reply messages, this will
904 904 # contain ename, etype and traceback fields.
905 905
906 906 # An additional field with supplementary information such as where to
907 907 # send the crash message
908 908 'info' : str,
909 909 }
910 910
911 911
912 912 Future ideas
913 913 ------------
914 914
915 915 Other potential message types, currently unimplemented, listed below as ideas.
916 916
917 917 Message type: ``file``::
918 918
919 919 content = {
920 920 'path' : 'cool.jpg',
921 921 'mimetype' : str,
922 922 'data' : str,
923 923 }
924 924
925 925
926 926 Messages on the stdin ROUTER/DEALER sockets
927 927 ===========================================
928 928
929 929 This is a socket where the request/reply pattern goes in the opposite direction:
930 930 from the kernel to a *single* frontend, and its purpose is to allow
931 931 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
932 932 to be fulfilled by the client. The request should be made to the frontend that
933 933 made the execution request that prompted ``raw_input`` to be called. For now we
934 934 will keep these messages as simple as possible, since they only mean to convey
935 935 the ``raw_input(prompt)`` call.
936 936
937 937 Message type: ``input_request``::
938 938
939 939 content = { 'prompt' : str }
940 940
941 941 Message type: ``input_reply``::
942 942
943 943 content = { 'value' : str }
944 944
945 945 .. Note::
946 946
947 947 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
948 948 practice the kernel should behave like an interactive program. When a
949 949 program is opened on the console, the keyboard effectively takes over the
950 950 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
951 951 Since the IPython kernel effectively behaves like a console program (albeit
952 952 one whose "keyboard" is actually living in a separate process and
953 953 transported over the zmq connection), raw ``stdin`` isn't expected to be
954 954 available.
955 955
956 956
957 957 Heartbeat for kernels
958 958 =====================
959 959
960 960 Initially we had considered using messages like those above over ZMQ for a
961 961 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
962 962 alive at all, even if it may be busy executing user code). But this has the
963 963 problem that if the kernel is locked inside extension code, it wouldn't execute
964 964 the python heartbeat code. But it turns out that we can implement a basic
965 965 heartbeat with pure ZMQ, without using any Python messaging at all.
966 966
967 967 The monitor sends out a single zmq message (right now, it is a str of the
968 968 monitor's lifetime in seconds), and gets the same message right back, prefixed
969 969 with the zmq identity of the DEALER socket in the heartbeat process. This can be
970 970 a uuid, or even a full message, but there doesn't seem to be a need for packing
971 971 up a message when the sender and receiver are the exact same Python object.
972 972
973 973 The model is this::
974 974
975 975 monitor.send(str(self.lifetime)) # '1.2345678910'
976 976
977 977 and the monitor receives some number of messages of the form::
978 978
979 979 ['uuid-abcd-dead-beef', '1.2345678910']
980 980
981 981 where the first part is the zmq.IDENTITY of the heart's DEALER on the engine, and
982 982 the rest is the message sent by the monitor. No Python code ever has any
983 983 access to the message between the monitor's send, and the monitor's recv.
984 984
985 985
986 986 ToDo
987 987 ====
988 988
989 989 Missing things include:
990 990
991 991 * Important: finish thinking through the payload concept and API.
992 992
993 993 * Important: ensure that we have a good solution for magics like %edit. It's
994 994 likely that with the payload concept we can build a full solution, but not
995 995 100% clear yet.
996 996
997 997 * Finishing the details of the heartbeat protocol.
998 998
999 999 * Signal handling: specify what kind of information kernel should broadcast (or
1000 1000 not) when it receives signals.
1001 1001
1002 1002 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now