##// END OF EJS Templates
send idle/busy on all shell messages...
MinRK -
Show More
@@ -1,186 +1,151 b''
1 """Base class to manage comms"""
1 """Base class to manage comms"""
2
2
3 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
4 # Copyright (C) 2013 The IPython Development Team
4 # Distributed under the terms of the Modified BSD License.
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
5
14 import sys
6 import sys
15
7
16 from IPython.config import LoggingConfigurable
8 from IPython.config import LoggingConfigurable
17 from IPython.core.prompts import LazyEvaluate
9 from IPython.core.prompts import LazyEvaluate
18 from IPython.core.getipython import get_ipython
10 from IPython.core.getipython import get_ipython
19
11
20 from IPython.utils.importstring import import_item
12 from IPython.utils.importstring import import_item
21 from IPython.utils.py3compat import string_types
13 from IPython.utils.py3compat import string_types
22 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
14 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
23
15
24 from .comm import Comm
16 from .comm import Comm
25
17
26 #-----------------------------------------------------------------------------
27 # Code
28 #-----------------------------------------------------------------------------
29
18
30 def lazy_keys(dikt):
19 def lazy_keys(dikt):
31 """Return lazy-evaluated string representation of a dictionary's keys
20 """Return lazy-evaluated string representation of a dictionary's keys
32
21
33 Key list is only constructed if it will actually be used.
22 Key list is only constructed if it will actually be used.
34 Used for debug-logging.
23 Used for debug-logging.
35 """
24 """
36 return LazyEvaluate(lambda d: list(d.keys()))
25 return LazyEvaluate(lambda d: list(d.keys()))
37
26
38
27
39 def with_output(method):
40 """method decorator for ensuring output is handled properly in a message handler
41
42 - sets parent header before entering the method
43 - publishes busy/idle
44 - flushes stdout/stderr after
45 """
46 def method_with_output(self, stream, ident, msg):
47 parent = msg['header']
48 self.shell.set_parent(parent)
49 self.shell.kernel._publish_status('busy', parent)
50 try:
51 return method(self, stream, ident, msg)
52 finally:
53 sys.stdout.flush()
54 sys.stderr.flush()
55 self.shell.kernel._publish_status('idle', parent)
56
57 return method_with_output
58
59
60 class CommManager(LoggingConfigurable):
28 class CommManager(LoggingConfigurable):
61 """Manager for Comms in the Kernel"""
29 """Manager for Comms in the Kernel"""
62
30
63 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
31 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
64 def _shell_default(self):
32 def _shell_default(self):
65 return get_ipython()
33 return get_ipython()
66 iopub_socket = Any()
34 iopub_socket = Any()
67 def _iopub_socket_default(self):
35 def _iopub_socket_default(self):
68 return self.shell.kernel.iopub_socket
36 return self.shell.kernel.iopub_socket
69 session = Instance('IPython.kernel.zmq.session.Session')
37 session = Instance('IPython.kernel.zmq.session.Session')
70 def _session_default(self):
38 def _session_default(self):
71 if self.shell is None:
39 if self.shell is None:
72 return
40 return
73 return self.shell.kernel.session
41 return self.shell.kernel.session
74
42
75 comms = Dict()
43 comms = Dict()
76 targets = Dict()
44 targets = Dict()
77
45
78 # Public APIs
46 # Public APIs
79
47
80 def register_target(self, target_name, f):
48 def register_target(self, target_name, f):
81 """Register a callable f for a given target name
49 """Register a callable f for a given target name
82
50
83 f will be called with two arguments when a comm_open message is received with `target`:
51 f will be called with two arguments when a comm_open message is received with `target`:
84
52
85 - the Comm instance
53 - the Comm instance
86 - the `comm_open` message itself.
54 - the `comm_open` message itself.
87
55
88 f can be a Python callable or an import string for one.
56 f can be a Python callable or an import string for one.
89 """
57 """
90 if isinstance(f, string_types):
58 if isinstance(f, string_types):
91 f = import_item(f)
59 f = import_item(f)
92
60
93 self.targets[target_name] = f
61 self.targets[target_name] = f
94
62
95 def unregister_target(self, target_name, f):
63 def unregister_target(self, target_name, f):
96 """Unregister a callable registered with register_target"""
64 """Unregister a callable registered with register_target"""
97 return self.targets.pop(target_name);
65 return self.targets.pop(target_name);
98
66
99 def register_comm(self, comm):
67 def register_comm(self, comm):
100 """Register a new comm"""
68 """Register a new comm"""
101 comm_id = comm.comm_id
69 comm_id = comm.comm_id
102 comm.shell = self.shell
70 comm.shell = self.shell
103 comm.iopub_socket = self.iopub_socket
71 comm.iopub_socket = self.iopub_socket
104 self.comms[comm_id] = comm
72 self.comms[comm_id] = comm
105 return comm_id
73 return comm_id
106
74
107 def unregister_comm(self, comm_id):
75 def unregister_comm(self, comm_id):
108 """Unregister a comm, and close its counterpart"""
76 """Unregister a comm, and close its counterpart"""
109 # unlike get_comm, this should raise a KeyError
77 # unlike get_comm, this should raise a KeyError
110 comm = self.comms.pop(comm_id)
78 comm = self.comms.pop(comm_id)
111 comm.close()
79 comm.close()
112
80
113 def get_comm(self, comm_id):
81 def get_comm(self, comm_id):
114 """Get a comm with a particular id
82 """Get a comm with a particular id
115
83
116 Returns the comm if found, otherwise None.
84 Returns the comm if found, otherwise None.
117
85
118 This will not raise an error,
86 This will not raise an error,
119 it will log messages if the comm cannot be found.
87 it will log messages if the comm cannot be found.
120 """
88 """
121 if comm_id not in self.comms:
89 if comm_id not in self.comms:
122 self.log.error("No such comm: %s", comm_id)
90 self.log.error("No such comm: %s", comm_id)
123 self.log.debug("Current comms: %s", lazy_keys(self.comms))
91 self.log.debug("Current comms: %s", lazy_keys(self.comms))
124 return
92 return
125 # call, because we store weakrefs
93 # call, because we store weakrefs
126 comm = self.comms[comm_id]
94 comm = self.comms[comm_id]
127 return comm
95 return comm
128
96
129 # Message handlers
97 # Message handlers
130 @with_output
131 def comm_open(self, stream, ident, msg):
98 def comm_open(self, stream, ident, msg):
132 """Handler for comm_open messages"""
99 """Handler for comm_open messages"""
133 content = msg['content']
100 content = msg['content']
134 comm_id = content['comm_id']
101 comm_id = content['comm_id']
135 target_name = content['target_name']
102 target_name = content['target_name']
136 f = self.targets.get(target_name, None)
103 f = self.targets.get(target_name, None)
137 comm = Comm(comm_id=comm_id,
104 comm = Comm(comm_id=comm_id,
138 shell=self.shell,
105 shell=self.shell,
139 iopub_socket=self.iopub_socket,
106 iopub_socket=self.iopub_socket,
140 primary=False,
107 primary=False,
141 )
108 )
142 if f is None:
109 if f is None:
143 self.log.error("No such comm target registered: %s", target_name)
110 self.log.error("No such comm target registered: %s", target_name)
144 comm.close()
111 comm.close()
145 return
112 return
146 self.register_comm(comm)
113 self.register_comm(comm)
147 try:
114 try:
148 f(comm, msg)
115 f(comm, msg)
149 except Exception:
116 except Exception:
150 self.log.error("Exception opening comm with target: %s", target_name, exc_info=True)
117 self.log.error("Exception opening comm with target: %s", target_name, exc_info=True)
151 comm.close()
118 comm.close()
152 self.unregister_comm(comm_id)
119 self.unregister_comm(comm_id)
153
120
154 @with_output
155 def comm_msg(self, stream, ident, msg):
121 def comm_msg(self, stream, ident, msg):
156 """Handler for comm_msg messages"""
122 """Handler for comm_msg messages"""
157 content = msg['content']
123 content = msg['content']
158 comm_id = content['comm_id']
124 comm_id = content['comm_id']
159 comm = self.get_comm(comm_id)
125 comm = self.get_comm(comm_id)
160 if comm is None:
126 if comm is None:
161 # no such comm
127 # no such comm
162 return
128 return
163 try:
129 try:
164 comm.handle_msg(msg)
130 comm.handle_msg(msg)
165 except Exception:
131 except Exception:
166 self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
132 self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
167
133
168 @with_output
169 def comm_close(self, stream, ident, msg):
134 def comm_close(self, stream, ident, msg):
170 """Handler for comm_close messages"""
135 """Handler for comm_close messages"""
171 content = msg['content']
136 content = msg['content']
172 comm_id = content['comm_id']
137 comm_id = content['comm_id']
173 comm = self.get_comm(comm_id)
138 comm = self.get_comm(comm_id)
174 if comm is None:
139 if comm is None:
175 # no such comm
140 # no such comm
176 self.log.debug("No such comm to close: %s", comm_id)
141 self.log.debug("No such comm to close: %s", comm_id)
177 return
142 return
178 del self.comms[comm_id]
143 del self.comms[comm_id]
179
144
180 try:
145 try:
181 comm.handle_close(msg)
146 comm.handle_close(msg)
182 except Exception:
147 except Exception:
183 self.log.error("Exception handling comm_close for %s", comm_id, exc_info=True)
148 self.log.error("Exception handling comm_close for %s", comm_id, exc_info=True)
184
149
185
150
186 __all__ = ['CommManager']
151 __all__ = ['CommManager']
@@ -1,675 +1,669 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 header = msg['header']
140 header = msg['header']
141 msg_type = header['msg_type']
141 msg_type = header['msg_type']
142
142
143 handler = self.control_handlers.get(msg_type, None)
143 handler = self.control_handlers.get(msg_type, None)
144 if handler is None:
144 if handler is None:
145 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
145 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
146 else:
146 else:
147 try:
147 try:
148 handler(self.control_stream, idents, msg)
148 handler(self.control_stream, idents, msg)
149 except Exception:
149 except Exception:
150 self.log.error("Exception in control handler:", exc_info=True)
150 self.log.error("Exception in control handler:", exc_info=True)
151
151
152 def dispatch_shell(self, stream, msg):
152 def dispatch_shell(self, stream, msg):
153 """dispatch shell requests"""
153 """dispatch shell requests"""
154 # flush control requests first
154 # flush control requests first
155 if self.control_stream:
155 if self.control_stream:
156 self.control_stream.flush()
156 self.control_stream.flush()
157
157
158 idents,msg = self.session.feed_identities(msg, copy=False)
158 idents,msg = self.session.feed_identities(msg, copy=False)
159 try:
159 try:
160 msg = self.session.unserialize(msg, content=True, copy=False)
160 msg = self.session.unserialize(msg, content=True, copy=False)
161 except:
161 except:
162 self.log.error("Invalid Message", exc_info=True)
162 self.log.error("Invalid Message", exc_info=True)
163 return
163 return
164
164
165 # Set the parent message for side effects.
166 self.set_parent(idents, msg)
167 self._publish_status(u'busy')
168
165 header = msg['header']
169 header = msg['header']
166 msg_id = header['msg_id']
170 msg_id = header['msg_id']
167 msg_type = msg['header']['msg_type']
171 msg_type = msg['header']['msg_type']
168
172
169 # Print some info about this message and leave a '--->' marker, so it's
173 # Print some info about this message and leave a '--->' marker, so it's
170 # easier to trace visually the message chain when debugging. Each
174 # easier to trace visually the message chain when debugging. Each
171 # handler prints its message at the end.
175 # handler prints its message at the end.
172 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
176 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
173 self.log.debug(' Content: %s\n --->\n ', msg['content'])
177 self.log.debug(' Content: %s\n --->\n ', msg['content'])
174
178
175 if msg_id in self.aborted:
179 if msg_id in self.aborted:
176 self.aborted.remove(msg_id)
180 self.aborted.remove(msg_id)
177 # is it safe to assume a msg_id will not be resubmitted?
181 # is it safe to assume a msg_id will not be resubmitted?
178 reply_type = msg_type.split('_')[0] + '_reply'
182 reply_type = msg_type.split('_')[0] + '_reply'
179 status = {'status' : 'aborted'}
183 status = {'status' : 'aborted'}
180 md = {'engine' : self.ident}
184 md = {'engine' : self.ident}
181 md.update(status)
185 md.update(status)
182 self.session.send(stream, reply_type, metadata=md,
186 self.session.send(stream, reply_type, metadata=md,
183 content=status, parent=msg, ident=idents)
187 content=status, parent=msg, ident=idents)
184 return
188 return
185
189
186 handler = self.shell_handlers.get(msg_type, None)
190 handler = self.shell_handlers.get(msg_type, None)
187 if handler is None:
191 if handler is None:
188 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
192 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
189 else:
193 else:
190 # ensure default_int_handler during handler call
194 # ensure default_int_handler during handler call
191 sig = signal(SIGINT, default_int_handler)
195 sig = signal(SIGINT, default_int_handler)
192 self.log.debug("%s: %s", msg_type, msg)
196 self.log.debug("%s: %s", msg_type, msg)
193 try:
197 try:
194 handler(stream, idents, msg)
198 handler(stream, idents, msg)
195 except Exception:
199 except Exception:
196 self.log.error("Exception in message handler:", exc_info=True)
200 self.log.error("Exception in message handler:", exc_info=True)
197 finally:
201 finally:
198 signal(SIGINT, sig)
202 signal(SIGINT, sig)
199
203
204 sys.stdout.flush()
205 sys.stderr.flush()
206 self._publish_status(u'idle')
207
200 def enter_eventloop(self):
208 def enter_eventloop(self):
201 """enter eventloop"""
209 """enter eventloop"""
202 self.log.info("entering eventloop %s", self.eventloop)
210 self.log.info("entering eventloop %s", self.eventloop)
203 for stream in self.shell_streams:
211 for stream in self.shell_streams:
204 # flush any pending replies,
212 # flush any pending replies,
205 # which may be skipped by entering the eventloop
213 # which may be skipped by entering the eventloop
206 stream.flush(zmq.POLLOUT)
214 stream.flush(zmq.POLLOUT)
207 # restore default_int_handler
215 # restore default_int_handler
208 signal(SIGINT, default_int_handler)
216 signal(SIGINT, default_int_handler)
209 while self.eventloop is not None:
217 while self.eventloop is not None:
210 try:
218 try:
211 self.eventloop(self)
219 self.eventloop(self)
212 except KeyboardInterrupt:
220 except KeyboardInterrupt:
213 # Ctrl-C shouldn't crash the kernel
221 # Ctrl-C shouldn't crash the kernel
214 self.log.error("KeyboardInterrupt caught in kernel")
222 self.log.error("KeyboardInterrupt caught in kernel")
215 continue
223 continue
216 else:
224 else:
217 # eventloop exited cleanly, this means we should stop (right?)
225 # eventloop exited cleanly, this means we should stop (right?)
218 self.eventloop = None
226 self.eventloop = None
219 break
227 break
220 self.log.info("exiting eventloop")
228 self.log.info("exiting eventloop")
221
229
222 def start(self):
230 def start(self):
223 """register dispatchers for streams"""
231 """register dispatchers for streams"""
224 if self.control_stream:
232 if self.control_stream:
225 self.control_stream.on_recv(self.dispatch_control, copy=False)
233 self.control_stream.on_recv(self.dispatch_control, copy=False)
226
234
227 def make_dispatcher(stream):
235 def make_dispatcher(stream):
228 def dispatcher(msg):
236 def dispatcher(msg):
229 return self.dispatch_shell(stream, msg)
237 return self.dispatch_shell(stream, msg)
230 return dispatcher
238 return dispatcher
231
239
232 for s in self.shell_streams:
240 for s in self.shell_streams:
233 s.on_recv(make_dispatcher(s), copy=False)
241 s.on_recv(make_dispatcher(s), copy=False)
234
242
235 # publish idle status
243 # publish idle status
236 self._publish_status('starting')
244 self._publish_status('starting')
237
245
238 def do_one_iteration(self):
246 def do_one_iteration(self):
239 """step eventloop just once"""
247 """step eventloop just once"""
240 if self.control_stream:
248 if self.control_stream:
241 self.control_stream.flush()
249 self.control_stream.flush()
242 for stream in self.shell_streams:
250 for stream in self.shell_streams:
243 # handle at most one request per iteration
251 # handle at most one request per iteration
244 stream.flush(zmq.POLLIN, 1)
252 stream.flush(zmq.POLLIN, 1)
245 stream.flush(zmq.POLLOUT)
253 stream.flush(zmq.POLLOUT)
246
254
247
255
248 def record_ports(self, ports):
256 def record_ports(self, ports):
249 """Record the ports that this kernel is using.
257 """Record the ports that this kernel is using.
250
258
251 The creator of the Kernel instance must call this methods if they
259 The creator of the Kernel instance must call this methods if they
252 want the :meth:`connect_request` method to return the port numbers.
260 want the :meth:`connect_request` method to return the port numbers.
253 """
261 """
254 self._recorded_ports = ports
262 self._recorded_ports = ports
255
263
256 #---------------------------------------------------------------------------
264 #---------------------------------------------------------------------------
257 # Kernel request handlers
265 # Kernel request handlers
258 #---------------------------------------------------------------------------
266 #---------------------------------------------------------------------------
259
267
260 def _make_metadata(self, other=None):
268 def _make_metadata(self, other=None):
261 """init metadata dict, for execute/apply_reply"""
269 """init metadata dict, for execute/apply_reply"""
262 new_md = {
270 new_md = {
263 'dependencies_met' : True,
271 'dependencies_met' : True,
264 'engine' : self.ident,
272 'engine' : self.ident,
265 'started': datetime.now(),
273 'started': datetime.now(),
266 }
274 }
267 if other:
275 if other:
268 new_md.update(other)
276 new_md.update(other)
269 return new_md
277 return new_md
270
278
271 def _publish_execute_input(self, code, parent, execution_count):
279 def _publish_execute_input(self, code, parent, execution_count):
272 """Publish the code request on the iopub stream."""
280 """Publish the code request on the iopub stream."""
273
281
274 self.session.send(self.iopub_socket, u'execute_input',
282 self.session.send(self.iopub_socket, u'execute_input',
275 {u'code':code, u'execution_count': execution_count},
283 {u'code':code, u'execution_count': execution_count},
276 parent=parent, ident=self._topic('execute_input')
284 parent=parent, ident=self._topic('execute_input')
277 )
285 )
278
286
279 def _publish_status(self, status, parent=None):
287 def _publish_status(self, status, parent=None):
280 """send status (busy/idle) on IOPub"""
288 """send status (busy/idle) on IOPub"""
281 self.session.send(self.iopub_socket,
289 self.session.send(self.iopub_socket,
282 u'status',
290 u'status',
283 {u'execution_state': status},
291 {u'execution_state': status},
284 parent=parent,
292 parent=parent or self._parent_header,
285 ident=self._topic('status'),
293 ident=self._topic('status'),
286 )
294 )
287
295
288 def set_parent(self, ident, parent):
296 def set_parent(self, ident, parent):
289 """Set the current parent_header
297 """Set the current parent_header
290
298
291 Side effects (IOPub messages) and replies are associated with
299 Side effects (IOPub messages) and replies are associated with
292 the request that caused them via the parent_header.
300 the request that caused them via the parent_header.
293
301
294 The parent identity is used to route input_request messages
302 The parent identity is used to route input_request messages
295 on the stdin channel.
303 on the stdin channel.
296 """
304 """
297 self._parent_ident = ident
305 self._parent_ident = ident
298 self._parent_header = parent
306 self._parent_header = parent
299
307
300 def send_response(self, stream, msg_or_type, content=None, ident=None,
308 def send_response(self, stream, msg_or_type, content=None, ident=None,
301 buffers=None, track=False, header=None, metadata=None):
309 buffers=None, track=False, header=None, metadata=None):
302 """Send a response to the message we're currently processing.
310 """Send a response to the message we're currently processing.
303
311
304 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
312 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
305 except ``parent``.
313 except ``parent``.
306
314
307 This relies on :meth:`set_parent` having been called for the current
315 This relies on :meth:`set_parent` having been called for the current
308 message.
316 message.
309 """
317 """
310 return self.session.send(stream, msg_or_type, content, self._parent_header,
318 return self.session.send(stream, msg_or_type, content, self._parent_header,
311 ident, buffers, track, header, metadata)
319 ident, buffers, track, header, metadata)
312
320
313 def execute_request(self, stream, ident, parent):
321 def execute_request(self, stream, ident, parent):
314 """handle an execute_request"""
322 """handle an execute_request"""
315
323
316 self._publish_status(u'busy', parent)
317
318 try:
324 try:
319 content = parent[u'content']
325 content = parent[u'content']
320 code = py3compat.cast_unicode_py2(content[u'code'])
326 code = py3compat.cast_unicode_py2(content[u'code'])
321 silent = content[u'silent']
327 silent = content[u'silent']
322 store_history = content.get(u'store_history', not silent)
328 store_history = content.get(u'store_history', not silent)
323 user_expressions = content.get('user_expressions', {})
329 user_expressions = content.get('user_expressions', {})
324 allow_stdin = content.get('allow_stdin', False)
330 allow_stdin = content.get('allow_stdin', False)
325 except:
331 except:
326 self.log.error("Got bad msg: ")
332 self.log.error("Got bad msg: ")
327 self.log.error("%s", parent)
333 self.log.error("%s", parent)
328 return
334 return
329
335
330 md = self._make_metadata(parent['metadata'])
336 md = self._make_metadata(parent['metadata'])
331
337
332 # Set the parent message of the display hook and out streams.
333 self.set_parent(ident, parent)
334
335 # Re-broadcast our input for the benefit of listening clients, and
338 # Re-broadcast our input for the benefit of listening clients, and
336 # start computing output
339 # start computing output
337 if not silent:
340 if not silent:
338 self.execution_count += 1
341 self.execution_count += 1
339 self._publish_execute_input(code, parent, self.execution_count)
342 self._publish_execute_input(code, parent, self.execution_count)
340
343
341 reply_content = self.do_execute(code, silent, store_history,
344 reply_content = self.do_execute(code, silent, store_history,
342 user_expressions, allow_stdin)
345 user_expressions, allow_stdin)
343
346
344 # Flush output before sending the reply.
347 # Flush output before sending the reply.
345 sys.stdout.flush()
348 sys.stdout.flush()
346 sys.stderr.flush()
349 sys.stderr.flush()
347 # FIXME: on rare occasions, the flush doesn't seem to make it to the
350 # FIXME: on rare occasions, the flush doesn't seem to make it to the
348 # clients... This seems to mitigate the problem, but we definitely need
351 # clients... This seems to mitigate the problem, but we definitely need
349 # to better understand what's going on.
352 # to better understand what's going on.
350 if self._execute_sleep:
353 if self._execute_sleep:
351 time.sleep(self._execute_sleep)
354 time.sleep(self._execute_sleep)
352
355
353 # Send the reply.
356 # Send the reply.
354 reply_content = json_clean(reply_content)
357 reply_content = json_clean(reply_content)
355
358
356 md['status'] = reply_content['status']
359 md['status'] = reply_content['status']
357 if reply_content['status'] == 'error' and \
360 if reply_content['status'] == 'error' and \
358 reply_content['ename'] == 'UnmetDependency':
361 reply_content['ename'] == 'UnmetDependency':
359 md['dependencies_met'] = False
362 md['dependencies_met'] = False
360
363
361 reply_msg = self.session.send(stream, u'execute_reply',
364 reply_msg = self.session.send(stream, u'execute_reply',
362 reply_content, parent, metadata=md,
365 reply_content, parent, metadata=md,
363 ident=ident)
366 ident=ident)
364
367
365 self.log.debug("%s", reply_msg)
368 self.log.debug("%s", reply_msg)
366
369
367 if not silent and reply_msg['content']['status'] == u'error':
370 if not silent and reply_msg['content']['status'] == u'error':
368 self._abort_queues()
371 self._abort_queues()
369
372
370 self._publish_status(u'idle', parent)
371
372 def do_execute(self, code, silent, store_history=True,
373 def do_execute(self, code, silent, store_history=True,
373 user_experssions=None, allow_stdin=False):
374 user_experssions=None, allow_stdin=False):
374 """Execute user code. Must be overridden by subclasses.
375 """Execute user code. Must be overridden by subclasses.
375 """
376 """
376 raise NotImplementedError
377 raise NotImplementedError
377
378
378 def complete_request(self, stream, ident, parent):
379 def complete_request(self, stream, ident, parent):
379 content = parent['content']
380 content = parent['content']
380 code = content['code']
381 code = content['code']
381 cursor_pos = content['cursor_pos']
382 cursor_pos = content['cursor_pos']
382
383
383 matches = self.do_complete(code, cursor_pos)
384 matches = self.do_complete(code, cursor_pos)
384 matches = json_clean(matches)
385 matches = json_clean(matches)
385 completion_msg = self.session.send(stream, 'complete_reply',
386 completion_msg = self.session.send(stream, 'complete_reply',
386 matches, parent, ident)
387 matches, parent, ident)
387 self.log.debug("%s", completion_msg)
388 self.log.debug("%s", completion_msg)
388
389
389 def do_complete(self, code, cursor_pos):
390 def do_complete(self, code, cursor_pos):
390 """Override in subclasses to find completions.
391 """Override in subclasses to find completions.
391 """
392 """
392 return {'matches' : [],
393 return {'matches' : [],
393 'cursor_end' : cursor_pos,
394 'cursor_end' : cursor_pos,
394 'cursor_start' : cursor_pos,
395 'cursor_start' : cursor_pos,
395 'metadata' : {},
396 'metadata' : {},
396 'status' : 'ok'}
397 'status' : 'ok'}
397
398
398 def inspect_request(self, stream, ident, parent):
399 def inspect_request(self, stream, ident, parent):
399 content = parent['content']
400 content = parent['content']
400
401
401 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
402 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
402 content.get('detail_level', 0))
403 content.get('detail_level', 0))
403 # Before we send this object over, we scrub it for JSON usage
404 # Before we send this object over, we scrub it for JSON usage
404 reply_content = json_clean(reply_content)
405 reply_content = json_clean(reply_content)
405 msg = self.session.send(stream, 'inspect_reply',
406 msg = self.session.send(stream, 'inspect_reply',
406 reply_content, parent, ident)
407 reply_content, parent, ident)
407 self.log.debug("%s", msg)
408 self.log.debug("%s", msg)
408
409
409 def do_inspect(self, code, cursor_pos, detail_level=0):
410 def do_inspect(self, code, cursor_pos, detail_level=0):
410 """Override in subclasses to allow introspection.
411 """Override in subclasses to allow introspection.
411 """
412 """
412 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
413 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
413
414
414 def history_request(self, stream, ident, parent):
415 def history_request(self, stream, ident, parent):
415 content = parent['content']
416 content = parent['content']
416
417
417 reply_content = self.do_history(**content)
418 reply_content = self.do_history(**content)
418
419
419 reply_content = json_clean(reply_content)
420 reply_content = json_clean(reply_content)
420 msg = self.session.send(stream, 'history_reply',
421 msg = self.session.send(stream, 'history_reply',
421 reply_content, parent, ident)
422 reply_content, parent, ident)
422 self.log.debug("%s", msg)
423 self.log.debug("%s", msg)
423
424
424 def do_history(self, hist_access_type, output, raw, session=None, start=None,
425 def do_history(self, hist_access_type, output, raw, session=None, start=None,
425 stop=None, n=None, pattern=None, unique=False):
426 stop=None, n=None, pattern=None, unique=False):
426 """Override in subclasses to access history.
427 """Override in subclasses to access history.
427 """
428 """
428 return {'history': []}
429 return {'history': []}
429
430
430 def connect_request(self, stream, ident, parent):
431 def connect_request(self, stream, ident, parent):
431 if self._recorded_ports is not None:
432 if self._recorded_ports is not None:
432 content = self._recorded_ports.copy()
433 content = self._recorded_ports.copy()
433 else:
434 else:
434 content = {}
435 content = {}
435 msg = self.session.send(stream, 'connect_reply',
436 msg = self.session.send(stream, 'connect_reply',
436 content, parent, ident)
437 content, parent, ident)
437 self.log.debug("%s", msg)
438 self.log.debug("%s", msg)
438
439
439 @property
440 @property
440 def kernel_info(self):
441 def kernel_info(self):
441 return {
442 return {
442 'protocol_version': release.kernel_protocol_version,
443 'protocol_version': release.kernel_protocol_version,
443 'implementation': self.implementation,
444 'implementation': self.implementation,
444 'implementation_version': self.implementation_version,
445 'implementation_version': self.implementation_version,
445 'language': self.language,
446 'language': self.language,
446 'language_version': self.language_version,
447 'language_version': self.language_version,
447 'banner': self.banner,
448 'banner': self.banner,
448 }
449 }
449
450
450 def kernel_info_request(self, stream, ident, parent):
451 def kernel_info_request(self, stream, ident, parent):
451 msg = self.session.send(stream, 'kernel_info_reply',
452 msg = self.session.send(stream, 'kernel_info_reply',
452 self.kernel_info, parent, ident)
453 self.kernel_info, parent, ident)
453 self.log.debug("%s", msg)
454 self.log.debug("%s", msg)
454
455
455 def shutdown_request(self, stream, ident, parent):
456 def shutdown_request(self, stream, ident, parent):
456 content = self.do_shutdown(parent['content']['restart'])
457 content = self.do_shutdown(parent['content']['restart'])
457 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
458 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
458 # same content, but different msg_id for broadcasting on IOPub
459 # same content, but different msg_id for broadcasting on IOPub
459 self._shutdown_message = self.session.msg(u'shutdown_reply',
460 self._shutdown_message = self.session.msg(u'shutdown_reply',
460 content, parent
461 content, parent
461 )
462 )
462
463
463 self._at_shutdown()
464 self._at_shutdown()
464 # call sys.exit after a short delay
465 # call sys.exit after a short delay
465 loop = ioloop.IOLoop.instance()
466 loop = ioloop.IOLoop.instance()
466 loop.add_timeout(time.time()+0.1, loop.stop)
467 loop.add_timeout(time.time()+0.1, loop.stop)
467
468
468 def do_shutdown(self, restart):
469 def do_shutdown(self, restart):
469 """Override in subclasses to do things when the frontend shuts down the
470 """Override in subclasses to do things when the frontend shuts down the
470 kernel.
471 kernel.
471 """
472 """
472 return {'status': 'ok', 'restart': restart}
473 return {'status': 'ok', 'restart': restart}
473
474
474 #---------------------------------------------------------------------------
475 #---------------------------------------------------------------------------
475 # Engine methods
476 # Engine methods
476 #---------------------------------------------------------------------------
477 #---------------------------------------------------------------------------
477
478
478 def apply_request(self, stream, ident, parent):
479 def apply_request(self, stream, ident, parent):
479 try:
480 try:
480 content = parent[u'content']
481 content = parent[u'content']
481 bufs = parent[u'buffers']
482 bufs = parent[u'buffers']
482 msg_id = parent['header']['msg_id']
483 msg_id = parent['header']['msg_id']
483 except:
484 except:
484 self.log.error("Got bad msg: %s", parent, exc_info=True)
485 self.log.error("Got bad msg: %s", parent, exc_info=True)
485 return
486 return
486
487
487 self._publish_status(u'busy', parent)
488
489 # Set the parent message of the display hook and out streams.
490 self.set_parent(ident, parent)
491
492 md = self._make_metadata(parent['metadata'])
488 md = self._make_metadata(parent['metadata'])
493
489
494 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
490 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
495
491
496 # put 'ok'/'error' status in header, for scheduler introspection:
492 # put 'ok'/'error' status in header, for scheduler introspection:
497 md['status'] = reply_content['status']
493 md['status'] = reply_content['status']
498
494
499 # flush i/o
495 # flush i/o
500 sys.stdout.flush()
496 sys.stdout.flush()
501 sys.stderr.flush()
497 sys.stderr.flush()
502
498
503 self.session.send(stream, u'apply_reply', reply_content,
499 self.session.send(stream, u'apply_reply', reply_content,
504 parent=parent, ident=ident,buffers=result_buf, metadata=md)
500 parent=parent, ident=ident,buffers=result_buf, metadata=md)
505
501
506 self._publish_status(u'idle', parent)
507
508 def do_apply(self, content, bufs, msg_id, reply_metadata):
502 def do_apply(self, content, bufs, msg_id, reply_metadata):
509 """Override in subclasses to support the IPython parallel framework.
503 """Override in subclasses to support the IPython parallel framework.
510 """
504 """
511 raise NotImplementedError
505 raise NotImplementedError
512
506
513 #---------------------------------------------------------------------------
507 #---------------------------------------------------------------------------
514 # Control messages
508 # Control messages
515 #---------------------------------------------------------------------------
509 #---------------------------------------------------------------------------
516
510
517 def abort_request(self, stream, ident, parent):
511 def abort_request(self, stream, ident, parent):
518 """abort a specifig msg by id"""
512 """abort a specifig msg by id"""
519 msg_ids = parent['content'].get('msg_ids', None)
513 msg_ids = parent['content'].get('msg_ids', None)
520 if isinstance(msg_ids, string_types):
514 if isinstance(msg_ids, string_types):
521 msg_ids = [msg_ids]
515 msg_ids = [msg_ids]
522 if not msg_ids:
516 if not msg_ids:
523 self.abort_queues()
517 self.abort_queues()
524 for mid in msg_ids:
518 for mid in msg_ids:
525 self.aborted.add(str(mid))
519 self.aborted.add(str(mid))
526
520
527 content = dict(status='ok')
521 content = dict(status='ok')
528 reply_msg = self.session.send(stream, 'abort_reply', content=content,
522 reply_msg = self.session.send(stream, 'abort_reply', content=content,
529 parent=parent, ident=ident)
523 parent=parent, ident=ident)
530 self.log.debug("%s", reply_msg)
524 self.log.debug("%s", reply_msg)
531
525
532 def clear_request(self, stream, idents, parent):
526 def clear_request(self, stream, idents, parent):
533 """Clear our namespace."""
527 """Clear our namespace."""
534 content = self.do_clear()
528 content = self.do_clear()
535 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
529 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
536 content = content)
530 content = content)
537
531
538 def do_clear(self):
532 def do_clear(self):
539 """Override in subclasses to clear the namespace
533 """Override in subclasses to clear the namespace
540
534
541 This is only required for IPython.parallel.
535 This is only required for IPython.parallel.
542 """
536 """
543 raise NotImplementedError
537 raise NotImplementedError
544
538
545 #---------------------------------------------------------------------------
539 #---------------------------------------------------------------------------
546 # Protected interface
540 # Protected interface
547 #---------------------------------------------------------------------------
541 #---------------------------------------------------------------------------
548
542
549 def _topic(self, topic):
543 def _topic(self, topic):
550 """prefixed topic for IOPub messages"""
544 """prefixed topic for IOPub messages"""
551 if self.int_id >= 0:
545 if self.int_id >= 0:
552 base = "engine.%i" % self.int_id
546 base = "engine.%i" % self.int_id
553 else:
547 else:
554 base = "kernel.%s" % self.ident
548 base = "kernel.%s" % self.ident
555
549
556 return py3compat.cast_bytes("%s.%s" % (base, topic))
550 return py3compat.cast_bytes("%s.%s" % (base, topic))
557
551
558 def _abort_queues(self):
552 def _abort_queues(self):
559 for stream in self.shell_streams:
553 for stream in self.shell_streams:
560 if stream:
554 if stream:
561 self._abort_queue(stream)
555 self._abort_queue(stream)
562
556
563 def _abort_queue(self, stream):
557 def _abort_queue(self, stream):
564 poller = zmq.Poller()
558 poller = zmq.Poller()
565 poller.register(stream.socket, zmq.POLLIN)
559 poller.register(stream.socket, zmq.POLLIN)
566 while True:
560 while True:
567 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
561 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
568 if msg is None:
562 if msg is None:
569 return
563 return
570
564
571 self.log.info("Aborting:")
565 self.log.info("Aborting:")
572 self.log.info("%s", msg)
566 self.log.info("%s", msg)
573 msg_type = msg['header']['msg_type']
567 msg_type = msg['header']['msg_type']
574 reply_type = msg_type.split('_')[0] + '_reply'
568 reply_type = msg_type.split('_')[0] + '_reply'
575
569
576 status = {'status' : 'aborted'}
570 status = {'status' : 'aborted'}
577 md = {'engine' : self.ident}
571 md = {'engine' : self.ident}
578 md.update(status)
572 md.update(status)
579 reply_msg = self.session.send(stream, reply_type, metadata=md,
573 reply_msg = self.session.send(stream, reply_type, metadata=md,
580 content=status, parent=msg, ident=idents)
574 content=status, parent=msg, ident=idents)
581 self.log.debug("%s", reply_msg)
575 self.log.debug("%s", reply_msg)
582 # We need to wait a bit for requests to come in. This can probably
576 # We need to wait a bit for requests to come in. This can probably
583 # be set shorter for true asynchronous clients.
577 # be set shorter for true asynchronous clients.
584 poller.poll(50)
578 poller.poll(50)
585
579
586
580
587 def _no_raw_input(self):
581 def _no_raw_input(self):
588 """Raise StdinNotImplentedError if active frontend doesn't support
582 """Raise StdinNotImplentedError if active frontend doesn't support
589 stdin."""
583 stdin."""
590 raise StdinNotImplementedError("raw_input was called, but this "
584 raise StdinNotImplementedError("raw_input was called, but this "
591 "frontend does not support stdin.")
585 "frontend does not support stdin.")
592
586
593 def getpass(self, prompt=''):
587 def getpass(self, prompt=''):
594 """Forward getpass to frontends
588 """Forward getpass to frontends
595
589
596 Raises
590 Raises
597 ------
591 ------
598 StdinNotImplentedError if active frontend doesn't support stdin.
592 StdinNotImplentedError if active frontend doesn't support stdin.
599 """
593 """
600 if not self._allow_stdin:
594 if not self._allow_stdin:
601 raise StdinNotImplementedError(
595 raise StdinNotImplementedError(
602 "getpass was called, but this frontend does not support input requests."
596 "getpass was called, but this frontend does not support input requests."
603 )
597 )
604 return self._input_request(prompt,
598 return self._input_request(prompt,
605 self._parent_ident,
599 self._parent_ident,
606 self._parent_header,
600 self._parent_header,
607 password=True,
601 password=True,
608 )
602 )
609
603
610 def raw_input(self, prompt=''):
604 def raw_input(self, prompt=''):
611 """Forward raw_input to frontends
605 """Forward raw_input to frontends
612
606
613 Raises
607 Raises
614 ------
608 ------
615 StdinNotImplentedError if active frontend doesn't support stdin.
609 StdinNotImplentedError if active frontend doesn't support stdin.
616 """
610 """
617 if not self._allow_stdin:
611 if not self._allow_stdin:
618 raise StdinNotImplementedError(
612 raise StdinNotImplementedError(
619 "raw_input was called, but this frontend does not support input requests."
613 "raw_input was called, but this frontend does not support input requests."
620 )
614 )
621 return self._input_request(prompt,
615 return self._input_request(prompt,
622 self._parent_ident,
616 self._parent_ident,
623 self._parent_header,
617 self._parent_header,
624 password=False,
618 password=False,
625 )
619 )
626
620
627 def _input_request(self, prompt, ident, parent, password=False):
621 def _input_request(self, prompt, ident, parent, password=False):
628 # Flush output before making the request.
622 # Flush output before making the request.
629 sys.stderr.flush()
623 sys.stderr.flush()
630 sys.stdout.flush()
624 sys.stdout.flush()
631 # flush the stdin socket, to purge stale replies
625 # flush the stdin socket, to purge stale replies
632 while True:
626 while True:
633 try:
627 try:
634 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
628 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
635 except zmq.ZMQError as e:
629 except zmq.ZMQError as e:
636 if e.errno == zmq.EAGAIN:
630 if e.errno == zmq.EAGAIN:
637 break
631 break
638 else:
632 else:
639 raise
633 raise
640
634
641 # Send the input request.
635 # Send the input request.
642 content = json_clean(dict(prompt=prompt, password=password))
636 content = json_clean(dict(prompt=prompt, password=password))
643 self.session.send(self.stdin_socket, u'input_request', content, parent,
637 self.session.send(self.stdin_socket, u'input_request', content, parent,
644 ident=ident)
638 ident=ident)
645
639
646 # Await a response.
640 # Await a response.
647 while True:
641 while True:
648 try:
642 try:
649 ident, reply = self.session.recv(self.stdin_socket, 0)
643 ident, reply = self.session.recv(self.stdin_socket, 0)
650 except Exception:
644 except Exception:
651 self.log.warn("Invalid Message:", exc_info=True)
645 self.log.warn("Invalid Message:", exc_info=True)
652 except KeyboardInterrupt:
646 except KeyboardInterrupt:
653 # re-raise KeyboardInterrupt, to truncate traceback
647 # re-raise KeyboardInterrupt, to truncate traceback
654 raise KeyboardInterrupt
648 raise KeyboardInterrupt
655 else:
649 else:
656 break
650 break
657 try:
651 try:
658 value = py3compat.unicode_to_str(reply['content']['value'])
652 value = py3compat.unicode_to_str(reply['content']['value'])
659 except:
653 except:
660 self.log.error("Bad input_reply: %s", parent)
654 self.log.error("Bad input_reply: %s", parent)
661 value = ''
655 value = ''
662 if value == '\x04':
656 if value == '\x04':
663 # EOF
657 # EOF
664 raise EOFError
658 raise EOFError
665 return value
659 return value
666
660
667 def _at_shutdown(self):
661 def _at_shutdown(self):
668 """Actions taken at shutdown by the kernel, called by python's atexit.
662 """Actions taken at shutdown by the kernel, called by python's atexit.
669 """
663 """
670 # io.rprint("Kernel at_shutdown") # dbg
664 # io.rprint("Kernel at_shutdown") # dbg
671 if self._shutdown_message is not None:
665 if self._shutdown_message is not None:
672 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
666 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
673 self.log.debug("%s", self._shutdown_message)
667 self.log.debug("%s", self._shutdown_message)
674 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
668 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
675
669
@@ -1,1058 +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 execute code, 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
896
897 Busy and idle messages should be sent before/after handling every shell message,
898 not just execution.
899
895 Clear output
900 Clear output
896 ------------
901 ------------
897
902
898 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.
899
904
900 Message type: ``clear_output``::
905 Message type: ``clear_output``::
901
906
902 content = {
907 content = {
903
908
904 # 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
905 # existing output immediately before the new output is displayed.
910 # existing output immediately before the new output is displayed.
906 # Useful for creating simple animations with minimal flickering.
911 # Useful for creating simple animations with minimal flickering.
907 'wait' : bool,
912 'wait' : bool,
908 }
913 }
909
914
910 .. versionchanged:: 4.1
915 .. versionchanged:: 4.1
911
916
912 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
917 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
913 and ``wait`` is added.
918 and ``wait`` is added.
914 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,
915 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.
916
921
917
922
918 Messages on the stdin ROUTER/DEALER sockets
923 Messages on the stdin ROUTER/DEALER sockets
919 ===========================================
924 ===========================================
920
925
921 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:
922 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
923 ``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
924 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
925 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
926 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
927 the ``raw_input(prompt)`` call.
932 the ``raw_input(prompt)`` call.
928
933
929 Message type: ``input_request``::
934 Message type: ``input_request``::
930
935
931 content = {
936 content = {
932 # the text to show at the prompt
937 # the text to show at the prompt
933 'prompt' : str,
938 'prompt' : str,
934 # Is the request for a password?
939 # Is the request for a password?
935 # If so, the frontend shouldn't echo input.
940 # If so, the frontend shouldn't echo input.
936 'password' : bool
941 'password' : bool
937 }
942 }
938
943
939 Message type: ``input_reply``::
944 Message type: ``input_reply``::
940
945
941 content = { 'value' : str }
946 content = { 'value' : str }
942
947
943
948
944 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.
945
950
946 .. versionchanged:: 5.0
951 .. versionchanged:: 5.0
947
952
948 ``password`` key added.
953 ``password`` key added.
949
954
950 .. note::
955 .. note::
951
956
952 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
953 as the client's shell socket.
958 as the client's shell socket.
954 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
955 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
956 the message.
961 the message.
957
962
958 .. note::
963 .. note::
959
964
960 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
961 practice the kernel should behave like an interactive program. When a
966 practice the kernel should behave like an interactive program. When a
962 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
963 ``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.
964 Since the IPython kernel effectively behaves like a console program (albeit
969 Since the IPython kernel effectively behaves like a console program (albeit
965 one whose "keyboard" is actually living in a separate process and
970 one whose "keyboard" is actually living in a separate process and
966 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
967 available.
972 available.
968
973
969
974
970 Heartbeat for kernels
975 Heartbeat for kernels
971 =====================
976 =====================
972
977
973 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
974 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.
975
980
976
981
977 Custom Messages
982 Custom Messages
978 ===============
983 ===============
979
984
980 .. versionadded:: 4.1
985 .. versionadded:: 4.1
981
986
982 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
983 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.
984 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,
985 and can communicate in either direction.
990 and can communicate in either direction.
986
991
987 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,
988 and no messages expect a reply.
993 and no messages expect a reply.
989 The Kernel listens for these messages on the Shell channel,
994 The Kernel listens for these messages on the Shell channel,
990 and the Frontend listens for them on the IOPub channel.
995 and the Frontend listens for them on the IOPub channel.
991
996
992 Opening a Comm
997 Opening a Comm
993 --------------
998 --------------
994
999
995 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::
996
1001
997 {
1002 {
998 'comm_id' : 'u-u-i-d',
1003 'comm_id' : 'u-u-i-d',
999 'target_name' : 'my_comm',
1004 'target_name' : 'my_comm',
1000 'data' : {}
1005 'data' : {}
1001 }
1006 }
1002
1007
1003 Every Comm has an ID and a target name.
1008 Every Comm has an ID and a target name.
1004 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
1005 of target_name keys to constructors.
1010 of target_name keys to constructors.
1006 After a ``comm_open`` message has been sent,
1011 After a ``comm_open`` message has been sent,
1007 there should be a corresponding Comm instance on both sides.
1012 there should be a corresponding Comm instance on both sides.
1008 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.
1009
1014
1010 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,
1011 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.
1012
1017
1013 Comm Messages
1018 Comm Messages
1014 -------------
1019 -------------
1015
1020
1016 Comm messages are one-way communications to update comm state,
1021 Comm messages are one-way communications to update comm state,
1017 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.
1018
1023
1019 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.
1020
1025
1021 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).
1022
1027
1023 Message type: ``comm_msg``::
1028 Message type: ``comm_msg``::
1024
1029
1025 {
1030 {
1026 'comm_id' : 'u-u-i-d',
1031 'comm_id' : 'u-u-i-d',
1027 'data' : {}
1032 'data' : {}
1028 }
1033 }
1029
1034
1030 Tearing Down Comms
1035 Tearing Down Comms
1031 ------------------
1036 ------------------
1032
1037
1033 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.
1034 This is done with a ``comm_close`` message.
1039 This is done with a ``comm_close`` message.
1035
1040
1036 Message type: ``comm_close``::
1041 Message type: ``comm_close``::
1037
1042
1038 {
1043 {
1039 'comm_id' : 'u-u-i-d',
1044 'comm_id' : 'u-u-i-d',
1040 'data' : {}
1045 'data' : {}
1041 }
1046 }
1042
1047
1043 Output Side Effects
1048 Output Side Effects
1044 -------------------
1049 -------------------
1045
1050
1046 Since comm messages can execute arbitrary user code,
1051 Since comm messages can execute arbitrary user code,
1047 handlers should set the parent header and publish status busy / idle,
1052 handlers should set the parent header and publish status busy / idle,
1048 just like an execute request.
1053 just like an execute request.
1049
1054
1050
1055
1051 To Do
1056 To Do
1052 =====
1057 =====
1053
1058
1054 Missing things include:
1059 Missing things include:
1055
1060
1056 * Important: finish thinking through the payload concept and API.
1061 * Important: finish thinking through the payload concept and API.
1057
1062
1058 .. include:: ../links.txt
1063 .. include:: ../links.txt
General Comments 0
You need to be logged in to leave comments. Login now