##// END OF EJS Templates
New connect_request message type added.
Brian Granger -
Show More
@@ -1,235 +1,239 b''
1 """ Defines helper functions for creating kernel entry points and process
1 """ Defines helper functions for creating kernel entry points and process
2 launchers.
2 launchers.
3 """
3 """
4
4
5 # Standard library imports.
5 # Standard library imports.
6 import os
6 import os
7 import socket
7 import socket
8 from subprocess import Popen, PIPE
8 from subprocess import Popen, PIPE
9 import sys
9 import sys
10
10
11 # System library imports.
11 # System library imports.
12 import zmq
12 import zmq
13
13
14 # Local imports.
14 # Local imports.
15 from IPython.core.ultratb import FormattedTB
15 from IPython.core.ultratb import FormattedTB
16 from IPython.external.argparse import ArgumentParser
16 from IPython.external.argparse import ArgumentParser
17 from IPython.utils import io
17 from IPython.utils import io
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
19 from displayhook import DisplayHook
19 from displayhook import DisplayHook
20 from iostream import OutStream
20 from iostream import OutStream
21 from session import Session
21 from session import Session
22 from heartbeat import Heartbeat
22 from heartbeat import Heartbeat
23
23
24 def bind_port(socket, ip, port):
24 def bind_port(socket, ip, port):
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
26 chosen. Returns the port that was bound.
26 chosen. Returns the port that was bound.
27 """
27 """
28 connection = 'tcp://%s' % ip
28 connection = 'tcp://%s' % ip
29 if port <= 0:
29 if port <= 0:
30 port = socket.bind_to_random_port(connection)
30 port = socket.bind_to_random_port(connection)
31 else:
31 else:
32 connection += ':%i' % port
32 connection += ':%i' % port
33 socket.bind(connection)
33 socket.bind(connection)
34 return port
34 return port
35
35
36
36
37 def make_argument_parser():
37 def make_argument_parser():
38 """ Creates an ArgumentParser for the generic arguments supported by all
38 """ Creates an ArgumentParser for the generic arguments supported by all
39 kernel entry points.
39 kernel entry points.
40 """
40 """
41 parser = ArgumentParser()
41 parser = ArgumentParser()
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
43 help='set the kernel\'s IP address [default: local]')
43 help='set the kernel\'s IP address [default: local]')
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
45 help='set the XREP channel port [default: random]')
45 help='set the XREP channel port [default: random]')
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
47 help='set the PUB channel port [default: random]')
47 help='set the PUB channel port [default: random]')
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
49 help='set the REQ channel port [default: random]')
49 help='set the REQ channel port [default: random]')
50 parser.add_argument('--hb', type=int, metavar='PORT', default=0,
50 parser.add_argument('--hb', type=int, metavar='PORT', default=0,
51 help='set the heartbeat port [default: random]')
51 help='set the heartbeat port [default: random]')
52
52
53 if sys.platform == 'win32':
53 if sys.platform == 'win32':
54 parser.add_argument('--parent', type=int, metavar='HANDLE',
54 parser.add_argument('--parent', type=int, metavar='HANDLE',
55 default=0, help='kill this process if the process '
55 default=0, help='kill this process if the process '
56 'with HANDLE dies')
56 'with HANDLE dies')
57 else:
57 else:
58 parser.add_argument('--parent', action='store_true',
58 parser.add_argument('--parent', action='store_true',
59 help='kill this process if its parent dies')
59 help='kill this process if its parent dies')
60
60
61 return parser
61 return parser
62
62
63
63
64 def make_kernel(namespace, kernel_factory,
64 def make_kernel(namespace, kernel_factory,
65 out_stream_factory=None, display_hook_factory=None):
65 out_stream_factory=None, display_hook_factory=None):
66 """ Creates a kernel, redirects stdout/stderr, and installs a display hook
66 """ Creates a kernel, redirects stdout/stderr, and installs a display hook
67 and exception handler.
67 and exception handler.
68 """
68 """
69 # If running under pythonw.exe, the interpreter will crash if more than 4KB
69 # If running under pythonw.exe, the interpreter will crash if more than 4KB
70 # of data is written to stdout or stderr. This is a bug that has been with
70 # of data is written to stdout or stderr. This is a bug that has been with
71 # Python for a very long time; see http://bugs.python.org/issue706263.
71 # Python for a very long time; see http://bugs.python.org/issue706263.
72 if sys.executable.endswith('pythonw.exe'):
72 if sys.executable.endswith('pythonw.exe'):
73 blackhole = file(os.devnull, 'w')
73 blackhole = file(os.devnull, 'w')
74 sys.stdout = sys.stderr = blackhole
74 sys.stdout = sys.stderr = blackhole
75 sys.__stdout__ = sys.__stderr__ = blackhole
75 sys.__stdout__ = sys.__stderr__ = blackhole
76
76
77 # Install minimal exception handling
77 # Install minimal exception handling
78 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
78 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
79 ostream=sys.__stdout__)
79 ostream=sys.__stdout__)
80
80
81 # Create a context, a session, and the kernel sockets.
81 # Create a context, a session, and the kernel sockets.
82 io.raw_print("Starting the kernel at pid:", os.getpid())
82 io.raw_print("Starting the kernel at pid:", os.getpid())
83 context = zmq.Context()
83 context = zmq.Context()
84 session = Session(username=u'kernel')
84 session = Session(username=u'kernel')
85
85
86 reply_socket = context.socket(zmq.XREP)
86 reply_socket = context.socket(zmq.XREP)
87 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
87 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
88 io.raw_print("XREP Channel on port", xrep_port)
88 io.raw_print("XREP Channel on port", xrep_port)
89
89
90 pub_socket = context.socket(zmq.PUB)
90 pub_socket = context.socket(zmq.PUB)
91 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
91 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
92 io.raw_print("PUB Channel on port", pub_port)
92 io.raw_print("PUB Channel on port", pub_port)
93
93
94 req_socket = context.socket(zmq.XREQ)
94 req_socket = context.socket(zmq.XREQ)
95 req_port = bind_port(req_socket, namespace.ip, namespace.req)
95 req_port = bind_port(req_socket, namespace.ip, namespace.req)
96 io.raw_print("REQ Channel on port", req_port)
96 io.raw_print("REQ Channel on port", req_port)
97
97
98 hb = Heartbeat(context, (namespace.ip, namespace.hb))
98 hb = Heartbeat(context, (namespace.ip, namespace.hb))
99 hb.start()
99 hb.start()
100 io.raw_print("Heartbeat REP Channel on port", hb.port)
100 hb_port = hb.port
101 io.raw_print("Heartbeat REP Channel on port", hb_port)
101
102
102 # Redirect input streams and set a display hook.
103 # Redirect input streams and set a display hook.
103 if out_stream_factory:
104 if out_stream_factory:
104 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
105 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
105 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
106 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
106 if display_hook_factory:
107 if display_hook_factory:
107 sys.displayhook = display_hook_factory(session, pub_socket)
108 sys.displayhook = display_hook_factory(session, pub_socket)
108
109
109 # Create the kernel.
110 # Create the kernel.
110 return kernel_factory(session=session, reply_socket=reply_socket,
111 kernel = kernel_factory(session=session, reply_socket=reply_socket,
111 pub_socket=pub_socket, req_socket=req_socket)
112 pub_socket=pub_socket, req_socket=req_socket)
113 kernel.record_ports(xrep_port=xrep_port, pub_port=pub_port,
114 req_port=req_port, hb_port=hb_port)
115 return kernel
112
116
113
117
114 def start_kernel(namespace, kernel):
118 def start_kernel(namespace, kernel):
115 """ Starts a kernel.
119 """ Starts a kernel.
116 """
120 """
117 # Configure this kernel/process to die on parent termination, if necessary.
121 # Configure this kernel/process to die on parent termination, if necessary.
118 if namespace.parent:
122 if namespace.parent:
119 if sys.platform == 'win32':
123 if sys.platform == 'win32':
120 poller = ExitPollerWindows(namespace.parent)
124 poller = ExitPollerWindows(namespace.parent)
121 else:
125 else:
122 poller = ExitPollerUnix()
126 poller = ExitPollerUnix()
123 poller.start()
127 poller.start()
124
128
125 # Start the kernel mainloop.
129 # Start the kernel mainloop.
126 kernel.start()
130 kernel.start()
127
131
128
132
129 def make_default_main(kernel_factory):
133 def make_default_main(kernel_factory):
130 """ Creates the simplest possible kernel entry point.
134 """ Creates the simplest possible kernel entry point.
131 """
135 """
132 def main():
136 def main():
133 namespace = make_argument_parser().parse_args()
137 namespace = make_argument_parser().parse_args()
134 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
138 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
135 start_kernel(namespace, kernel)
139 start_kernel(namespace, kernel)
136 return main
140 return main
137
141
138
142
139 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,
143 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,
140 independent=False, extra_arguments=[]):
144 independent=False, extra_arguments=[]):
141 """ Launches a localhost kernel, binding to the specified ports.
145 """ Launches a localhost kernel, binding to the specified ports.
142
146
143 Parameters
147 Parameters
144 ----------
148 ----------
145 code : str,
149 code : str,
146 A string of Python code that imports and executes a kernel entry point.
150 A string of Python code that imports and executes a kernel entry point.
147
151
148 xrep_port : int, optional
152 xrep_port : int, optional
149 The port to use for XREP channel.
153 The port to use for XREP channel.
150
154
151 pub_port : int, optional
155 pub_port : int, optional
152 The port to use for the SUB channel.
156 The port to use for the SUB channel.
153
157
154 req_port : int, optional
158 req_port : int, optional
155 The port to use for the REQ (raw input) channel.
159 The port to use for the REQ (raw input) channel.
156
160
157 hb_port : int, optional
161 hb_port : int, optional
158 The port to use for the hearbeat REP channel.
162 The port to use for the hearbeat REP channel.
159
163
160 independent : bool, optional (default False)
164 independent : bool, optional (default False)
161 If set, the kernel process is guaranteed to survive if this process
165 If set, the kernel process is guaranteed to survive if this process
162 dies. If not set, an effort is made to ensure that the kernel is killed
166 dies. If not set, an effort is made to ensure that the kernel is killed
163 when this process dies. Note that in this case it is still good practice
167 when this process dies. Note that in this case it is still good practice
164 to kill kernels manually before exiting.
168 to kill kernels manually before exiting.
165
169
166 extra_arguments = list, optional
170 extra_arguments = list, optional
167 A list of extra arguments to pass when executing the launch code.
171 A list of extra arguments to pass when executing the launch code.
168
172
169 Returns
173 Returns
170 -------
174 -------
171 A tuple of form:
175 A tuple of form:
172 (kernel_process, xrep_port, pub_port, req_port)
176 (kernel_process, xrep_port, pub_port, req_port)
173 where kernel_process is a Popen object and the ports are integers.
177 where kernel_process is a Popen object and the ports are integers.
174 """
178 """
175 # Find open ports as necessary.
179 # Find open ports as necessary.
176 ports = []
180 ports = []
177 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + \
181 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + \
178 int(req_port <= 0) + int(hb_port <= 0)
182 int(req_port <= 0) + int(hb_port <= 0)
179 for i in xrange(ports_needed):
183 for i in xrange(ports_needed):
180 sock = socket.socket()
184 sock = socket.socket()
181 sock.bind(('', 0))
185 sock.bind(('', 0))
182 ports.append(sock)
186 ports.append(sock)
183 for i, sock in enumerate(ports):
187 for i, sock in enumerate(ports):
184 port = sock.getsockname()[1]
188 port = sock.getsockname()[1]
185 sock.close()
189 sock.close()
186 ports[i] = port
190 ports[i] = port
187 if xrep_port <= 0:
191 if xrep_port <= 0:
188 xrep_port = ports.pop(0)
192 xrep_port = ports.pop(0)
189 if pub_port <= 0:
193 if pub_port <= 0:
190 pub_port = ports.pop(0)
194 pub_port = ports.pop(0)
191 if req_port <= 0:
195 if req_port <= 0:
192 req_port = ports.pop(0)
196 req_port = ports.pop(0)
193 if hb_port <= 0:
197 if hb_port <= 0:
194 hb_port = ports.pop(0)
198 hb_port = ports.pop(0)
195
199
196 # Build the kernel launch command.
200 # Build the kernel launch command.
197 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
201 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
198 '--pub', str(pub_port), '--req', str(req_port),
202 '--pub', str(pub_port), '--req', str(req_port),
199 '--hb', str(hb_port) ]
203 '--hb', str(hb_port) ]
200 arguments.extend(extra_arguments)
204 arguments.extend(extra_arguments)
201
205
202 # Spawn a kernel.
206 # Spawn a kernel.
203 if sys.platform == 'win32':
207 if sys.platform == 'win32':
204
208
205 # If using pythonw, stdin, stdout, and stderr are invalid. Popen will
209 # If using pythonw, stdin, stdout, and stderr are invalid. Popen will
206 # fail unless they are suitably redirected. We don't read from the
210 # fail unless they are suitably redirected. We don't read from the
207 # pipes, but they must exist.
211 # pipes, but they must exist.
208 redirect = PIPE if sys.executable.endswith('pythonw.exe') else None
212 redirect = PIPE if sys.executable.endswith('pythonw.exe') else None
209
213
210 if independent:
214 if independent:
211 proc = Popen(['start', '/b'] + arguments, shell=True,
215 proc = Popen(['start', '/b'] + arguments, shell=True,
212 stdout=redirect, stderr=redirect, stdin=redirect)
216 stdout=redirect, stderr=redirect, stdin=redirect)
213 else:
217 else:
214 from _subprocess import DuplicateHandle, GetCurrentProcess, \
218 from _subprocess import DuplicateHandle, GetCurrentProcess, \
215 DUPLICATE_SAME_ACCESS
219 DUPLICATE_SAME_ACCESS
216 pid = GetCurrentProcess()
220 pid = GetCurrentProcess()
217 handle = DuplicateHandle(pid, pid, pid, 0,
221 handle = DuplicateHandle(pid, pid, pid, 0,
218 True, # Inheritable by new processes.
222 True, # Inheritable by new processes.
219 DUPLICATE_SAME_ACCESS)
223 DUPLICATE_SAME_ACCESS)
220 proc = Popen(arguments + ['--parent', str(int(handle))],
224 proc = Popen(arguments + ['--parent', str(int(handle))],
221 stdout=redirect, stderr=redirect, stdin=redirect)
225 stdout=redirect, stderr=redirect, stdin=redirect)
222
226
223 # Clean up pipes created to work around Popen bug.
227 # Clean up pipes created to work around Popen bug.
224 if redirect is not None:
228 if redirect is not None:
225 proc.stdout.close()
229 proc.stdout.close()
226 proc.stderr.close()
230 proc.stderr.close()
227 proc.stdin.close()
231 proc.stdin.close()
228
232
229 else:
233 else:
230 if independent:
234 if independent:
231 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
235 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
232 else:
236 else:
233 proc = Popen(arguments + ['--parent'])
237 proc = Popen(arguments + ['--parent'])
234
238
235 return proc, xrep_port, pub_port, req_port, hb_port
239 return proc, xrep_port, pub_port, req_port, hb_port
@@ -1,586 +1,612 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24
24
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.utils import io
30 from IPython.utils import io
31 from IPython.utils.jsonutil import json_clean
31 from IPython.utils.jsonutil import json_clean
32 from IPython.lib import pylabtools
32 from IPython.lib import pylabtools
33 from IPython.utils.traitlets import Instance, Float
33 from IPython.utils.traitlets import Instance, Float
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
35 start_kernel)
35 start_kernel)
36 from iostream import OutStream
36 from iostream import OutStream
37 from session import Session, Message
37 from session import Session, Message
38 from zmqshell import ZMQInteractiveShell
38 from zmqshell import ZMQInteractiveShell
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Main kernel class
41 # Main kernel class
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class Kernel(Configurable):
44 class Kernel(Configurable):
45
45
46 #---------------------------------------------------------------------------
46 #---------------------------------------------------------------------------
47 # Kernel interface
47 # Kernel interface
48 #---------------------------------------------------------------------------
48 #---------------------------------------------------------------------------
49
49
50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
51 session = Instance(Session)
51 session = Instance(Session)
52 reply_socket = Instance('zmq.Socket')
52 reply_socket = Instance('zmq.Socket')
53 pub_socket = Instance('zmq.Socket')
53 pub_socket = Instance('zmq.Socket')
54 req_socket = Instance('zmq.Socket')
54 req_socket = Instance('zmq.Socket')
55
55
56 # Private interface
56 # Private interface
57
57
58 # Time to sleep after flushing the stdout/err buffers in each execute
58 # Time to sleep after flushing the stdout/err buffers in each execute
59 # cycle. While this introduces a hard limit on the minimal latency of the
59 # cycle. While this introduces a hard limit on the minimal latency of the
60 # execute cycle, it helps prevent output synchronization problems for
60 # execute cycle, it helps prevent output synchronization problems for
61 # clients.
61 # clients.
62 # Units are in seconds. The minimum zmq latency on local host is probably
62 # Units are in seconds. The minimum zmq latency on local host is probably
63 # ~150 microseconds, set this to 500us for now. We may need to increase it
63 # ~150 microseconds, set this to 500us for now. We may need to increase it
64 # a little if it's not enough after more interactive testing.
64 # a little if it's not enough after more interactive testing.
65 _execute_sleep = Float(0.0005, config=True)
65 _execute_sleep = Float(0.0005, config=True)
66
66
67 # Frequency of the kernel's event loop.
67 # Frequency of the kernel's event loop.
68 # Units are in seconds, kernel subclasses for GUI toolkits may need to
68 # Units are in seconds, kernel subclasses for GUI toolkits may need to
69 # adapt to milliseconds.
69 # adapt to milliseconds.
70 _poll_interval = Float(0.05, config=True)
70 _poll_interval = Float(0.05, config=True)
71
71
72 # If the shutdown was requested over the network, we leave here the
72 # If the shutdown was requested over the network, we leave here the
73 # necessary reply message so it can be sent by our registered atexit
73 # necessary reply message so it can be sent by our registered atexit
74 # handler. This ensures that the reply is only sent to clients truly at
74 # handler. This ensures that the reply is only sent to clients truly at
75 # the end of our shutdown process (which happens after the underlying
75 # the end of our shutdown process (which happens after the underlying
76 # IPython shell's own shutdown).
76 # IPython shell's own shutdown).
77 _shutdown_message = None
77 _shutdown_message = None
78
79 # This is a dict of port number that the kernel is listening on. It is set
80 # by record_ports and used by connect_request.
81 _recorded_ports = None
78
82
79 def __init__(self, **kwargs):
83 def __init__(self, **kwargs):
80 super(Kernel, self).__init__(**kwargs)
84 super(Kernel, self).__init__(**kwargs)
81
85
82 # Before we even start up the shell, register *first* our exit handlers
86 # Before we even start up the shell, register *first* our exit handlers
83 # so they come before the shell's
87 # so they come before the shell's
84 atexit.register(self._at_shutdown)
88 atexit.register(self._at_shutdown)
85
89
86 # Initialize the InteractiveShell subclass
90 # Initialize the InteractiveShell subclass
87 self.shell = ZMQInteractiveShell.instance()
91 self.shell = ZMQInteractiveShell.instance()
88 self.shell.displayhook.session = self.session
92 self.shell.displayhook.session = self.session
89 self.shell.displayhook.pub_socket = self.pub_socket
93 self.shell.displayhook.pub_socket = self.pub_socket
90
94
91 # TMP - hack while developing
95 # TMP - hack while developing
92 self.shell._reply_content = None
96 self.shell._reply_content = None
93
97
94 # Build dict of handlers for message types
98 # Build dict of handlers for message types
95 msg_types = [ 'execute_request', 'complete_request',
99 msg_types = [ 'execute_request', 'complete_request',
96 'object_info_request', 'history_request',
100 'object_info_request', 'history_request',
97 'shutdown_request']
101 'shutdown_request']
98 self.handlers = {}
102 self.handlers = {}
99 for msg_type in msg_types:
103 for msg_type in msg_types:
100 self.handlers[msg_type] = getattr(self, msg_type)
104 self.handlers[msg_type] = getattr(self, msg_type)
101
105
102 def do_one_iteration(self):
106 def do_one_iteration(self):
103 """Do one iteration of the kernel's evaluation loop.
107 """Do one iteration of the kernel's evaluation loop.
104 """
108 """
105 try:
109 try:
106 ident = self.reply_socket.recv(zmq.NOBLOCK)
110 ident = self.reply_socket.recv(zmq.NOBLOCK)
107 except zmq.ZMQError, e:
111 except zmq.ZMQError, e:
108 if e.errno == zmq.EAGAIN:
112 if e.errno == zmq.EAGAIN:
109 return
113 return
110 else:
114 else:
111 raise
115 raise
112 # FIXME: Bug in pyzmq/zmq?
116 # FIXME: Bug in pyzmq/zmq?
113 # assert self.reply_socket.rcvmore(), "Missing message part."
117 # assert self.reply_socket.rcvmore(), "Missing message part."
114 msg = self.reply_socket.recv_json()
118 msg = self.reply_socket.recv_json()
115
119
116 # Print some info about this message and leave a '--->' marker, so it's
120 # Print some info about this message and leave a '--->' marker, so it's
117 # easier to trace visually the message chain when debugging. Each
121 # easier to trace visually the message chain when debugging. Each
118 # handler prints its message at the end.
122 # handler prints its message at the end.
119 # Eventually we'll move these from stdout to a logger.
123 # Eventually we'll move these from stdout to a logger.
120 io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
124 io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
121 io.raw_print(' Content: ', msg['content'],
125 io.raw_print(' Content: ', msg['content'],
122 '\n --->\n ', sep='', end='')
126 '\n --->\n ', sep='', end='')
123
127
124 # Find and call actual handler for message
128 # Find and call actual handler for message
125 handler = self.handlers.get(msg['msg_type'], None)
129 handler = self.handlers.get(msg['msg_type'], None)
126 if handler is None:
130 if handler is None:
127 io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
131 io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
128 else:
132 else:
129 handler(ident, msg)
133 handler(ident, msg)
130
134
131 # Check whether we should exit, in case the incoming message set the
135 # Check whether we should exit, in case the incoming message set the
132 # exit flag on
136 # exit flag on
133 if self.shell.exit_now:
137 if self.shell.exit_now:
134 io.raw_print('\nExiting IPython kernel...')
138 io.raw_print('\nExiting IPython kernel...')
135 # We do a normal, clean exit, which allows any actions registered
139 # We do a normal, clean exit, which allows any actions registered
136 # via atexit (such as history saving) to take place.
140 # via atexit (such as history saving) to take place.
137 sys.exit(0)
141 sys.exit(0)
138
142
139
143
140 def start(self):
144 def start(self):
141 """ Start the kernel main loop.
145 """ Start the kernel main loop.
142 """
146 """
143 while True:
147 while True:
144 time.sleep(self._poll_interval)
148 time.sleep(self._poll_interval)
145 self.do_one_iteration()
149 self.do_one_iteration()
146
150
151 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
152 """Record the ports that this kernel is using.
153
154 The creator of the Kernel instance must call this methods if they
155 want the :meth:`connect_request` method to return the port numbers.
156 """
157 self._recorded_ports = {
158 'xrep_port' : xreq_port,
159 'pub_port' : pub_port,
160 'req_port' : req_port,
161 'hb_port' : hb_port
162 }
163
147 #---------------------------------------------------------------------------
164 #---------------------------------------------------------------------------
148 # Kernel request handlers
165 # Kernel request handlers
149 #---------------------------------------------------------------------------
166 #---------------------------------------------------------------------------
150
167
151 def _publish_pyin(self, code, parent):
168 def _publish_pyin(self, code, parent):
152 """Publish the code request on the pyin stream."""
169 """Publish the code request on the pyin stream."""
153
170
154 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
171 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
155 self.pub_socket.send_json(pyin_msg)
172 self.pub_socket.send_json(pyin_msg)
156
173
157 def execute_request(self, ident, parent):
174 def execute_request(self, ident, parent):
158 try:
175 try:
159 content = parent[u'content']
176 content = parent[u'content']
160 code = content[u'code']
177 code = content[u'code']
161 silent = content[u'silent']
178 silent = content[u'silent']
162 except:
179 except:
163 io.raw_print_err("Got bad msg: ")
180 io.raw_print_err("Got bad msg: ")
164 io.raw_print_err(Message(parent))
181 io.raw_print_err(Message(parent))
165 return
182 return
166
183
167 shell = self.shell # we'll need this a lot here
184 shell = self.shell # we'll need this a lot here
168
185
169 # Replace raw_input. Note that is not sufficient to replace
186 # Replace raw_input. Note that is not sufficient to replace
170 # raw_input in the user namespace.
187 # raw_input in the user namespace.
171 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
188 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
172 __builtin__.raw_input = raw_input
189 __builtin__.raw_input = raw_input
173
190
174 # Set the parent message of the display hook and out streams.
191 # Set the parent message of the display hook and out streams.
175 shell.displayhook.set_parent(parent)
192 shell.displayhook.set_parent(parent)
176 sys.stdout.set_parent(parent)
193 sys.stdout.set_parent(parent)
177 sys.stderr.set_parent(parent)
194 sys.stderr.set_parent(parent)
178
195
179 # Re-broadcast our input for the benefit of listening clients, and
196 # Re-broadcast our input for the benefit of listening clients, and
180 # start computing output
197 # start computing output
181 if not silent:
198 if not silent:
182 self._publish_pyin(code, parent)
199 self._publish_pyin(code, parent)
183
200
184 reply_content = {}
201 reply_content = {}
185 try:
202 try:
186 if silent:
203 if silent:
187 # runcode uses 'exec' mode, so no displayhook will fire, and it
204 # runcode uses 'exec' mode, so no displayhook will fire, and it
188 # doesn't call logging or history manipulations. Print
205 # doesn't call logging or history manipulations. Print
189 # statements in that code will obviously still execute.
206 # statements in that code will obviously still execute.
190 shell.runcode(code)
207 shell.runcode(code)
191 else:
208 else:
192 # FIXME: runlines calls the exception handler itself.
209 # FIXME: runlines calls the exception handler itself.
193 shell._reply_content = None
210 shell._reply_content = None
194
211
195 # For now leave this here until we're sure we can stop using it
212 # For now leave this here until we're sure we can stop using it
196 #shell.runlines(code)
213 #shell.runlines(code)
197
214
198 # Experimental: cell mode! Test more before turning into
215 # Experimental: cell mode! Test more before turning into
199 # default and removing the hacks around runlines.
216 # default and removing the hacks around runlines.
200 shell.run_cell(code)
217 shell.run_cell(code)
201 except:
218 except:
202 status = u'error'
219 status = u'error'
203 # FIXME: this code right now isn't being used yet by default,
220 # FIXME: this code right now isn't being used yet by default,
204 # because the runlines() call above directly fires off exception
221 # because the runlines() call above directly fires off exception
205 # reporting. This code, therefore, is only active in the scenario
222 # reporting. This code, therefore, is only active in the scenario
206 # where runlines itself has an unhandled exception. We need to
223 # where runlines itself has an unhandled exception. We need to
207 # uniformize this, for all exception construction to come from a
224 # uniformize this, for all exception construction to come from a
208 # single location in the codbase.
225 # single location in the codbase.
209 etype, evalue, tb = sys.exc_info()
226 etype, evalue, tb = sys.exc_info()
210 tb_list = traceback.format_exception(etype, evalue, tb)
227 tb_list = traceback.format_exception(etype, evalue, tb)
211 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
228 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
212 else:
229 else:
213 status = u'ok'
230 status = u'ok'
214
231
215 reply_content[u'status'] = status
232 reply_content[u'status'] = status
216 # Compute the execution counter so clients can display prompts
233 # Compute the execution counter so clients can display prompts
217 reply_content['execution_count'] = shell.displayhook.prompt_count
234 reply_content['execution_count'] = shell.displayhook.prompt_count
218
235
219 # FIXME - fish exception info out of shell, possibly left there by
236 # FIXME - fish exception info out of shell, possibly left there by
220 # runlines. We'll need to clean up this logic later.
237 # runlines. We'll need to clean up this logic later.
221 if shell._reply_content is not None:
238 if shell._reply_content is not None:
222 reply_content.update(shell._reply_content)
239 reply_content.update(shell._reply_content)
223
240
224 # At this point, we can tell whether the main code execution succeeded
241 # At this point, we can tell whether the main code execution succeeded
225 # or not. If it did, we proceed to evaluate user_variables/expressions
242 # or not. If it did, we proceed to evaluate user_variables/expressions
226 if reply_content['status'] == 'ok':
243 if reply_content['status'] == 'ok':
227 reply_content[u'user_variables'] = \
244 reply_content[u'user_variables'] = \
228 shell.get_user_variables(content[u'user_variables'])
245 shell.get_user_variables(content[u'user_variables'])
229 reply_content[u'user_expressions'] = \
246 reply_content[u'user_expressions'] = \
230 shell.eval_expressions(content[u'user_expressions'])
247 shell.eval_expressions(content[u'user_expressions'])
231 else:
248 else:
232 # If there was an error, don't even try to compute variables or
249 # If there was an error, don't even try to compute variables or
233 # expressions
250 # expressions
234 reply_content[u'user_variables'] = {}
251 reply_content[u'user_variables'] = {}
235 reply_content[u'user_expressions'] = {}
252 reply_content[u'user_expressions'] = {}
236
253
237 # Payloads should be retrieved regardless of outcome, so we can both
254 # Payloads should be retrieved regardless of outcome, so we can both
238 # recover partial output (that could have been generated early in a
255 # recover partial output (that could have been generated early in a
239 # block, before an error) and clear the payload system always.
256 # block, before an error) and clear the payload system always.
240 reply_content[u'payload'] = shell.payload_manager.read_payload()
257 reply_content[u'payload'] = shell.payload_manager.read_payload()
241 # Be agressive about clearing the payload because we don't want
258 # Be agressive about clearing the payload because we don't want
242 # it to sit in memory until the next execute_request comes in.
259 # it to sit in memory until the next execute_request comes in.
243 shell.payload_manager.clear_payload()
260 shell.payload_manager.clear_payload()
244
261
245 # Send the reply.
262 # Send the reply.
246 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
263 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
247 io.raw_print(reply_msg)
264 io.raw_print(reply_msg)
248
265
249 # Flush output before sending the reply.
266 # Flush output before sending the reply.
250 sys.stdout.flush()
267 sys.stdout.flush()
251 sys.stderr.flush()
268 sys.stderr.flush()
252 # FIXME: on rare occasions, the flush doesn't seem to make it to the
269 # FIXME: on rare occasions, the flush doesn't seem to make it to the
253 # clients... This seems to mitigate the problem, but we definitely need
270 # clients... This seems to mitigate the problem, but we definitely need
254 # to better understand what's going on.
271 # to better understand what's going on.
255 if self._execute_sleep:
272 if self._execute_sleep:
256 time.sleep(self._execute_sleep)
273 time.sleep(self._execute_sleep)
257
274
258 self.reply_socket.send(ident, zmq.SNDMORE)
275 self.reply_socket.send(ident, zmq.SNDMORE)
259 self.reply_socket.send_json(reply_msg)
276 self.reply_socket.send_json(reply_msg)
260 if reply_msg['content']['status'] == u'error':
277 if reply_msg['content']['status'] == u'error':
261 self._abort_queue()
278 self._abort_queue()
262
279
263 def complete_request(self, ident, parent):
280 def complete_request(self, ident, parent):
264 txt, matches = self._complete(parent)
281 txt, matches = self._complete(parent)
265 matches = {'matches' : matches,
282 matches = {'matches' : matches,
266 'matched_text' : txt,
283 'matched_text' : txt,
267 'status' : 'ok'}
284 'status' : 'ok'}
268 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
285 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
269 matches, parent, ident)
286 matches, parent, ident)
270 io.raw_print(completion_msg)
287 io.raw_print(completion_msg)
271
288
272 def object_info_request(self, ident, parent):
289 def object_info_request(self, ident, parent):
273 object_info = self.shell.object_inspect(parent['content']['oname'])
290 object_info = self.shell.object_inspect(parent['content']['oname'])
274 # Before we send this object over, we turn it into a dict and we scrub
291 # Before we send this object over, we turn it into a dict and we scrub
275 # it for JSON usage
292 # it for JSON usage
276 oinfo = json_clean(object_info._asdict())
293 oinfo = json_clean(object_info._asdict())
277 msg = self.session.send(self.reply_socket, 'object_info_reply',
294 msg = self.session.send(self.reply_socket, 'object_info_reply',
278 oinfo, parent, ident)
295 oinfo, parent, ident)
279 io.raw_print(msg)
296 io.raw_print(msg)
280
297
281 def history_request(self, ident, parent):
298 def history_request(self, ident, parent):
282 output = parent['content']['output']
299 output = parent['content']['output']
283 index = parent['content']['index']
300 index = parent['content']['index']
284 raw = parent['content']['raw']
301 raw = parent['content']['raw']
285 hist = self.shell.get_history(index=index, raw=raw, output=output)
302 hist = self.shell.get_history(index=index, raw=raw, output=output)
286 content = {'history' : hist}
303 content = {'history' : hist}
287 msg = self.session.send(self.reply_socket, 'history_reply',
304 msg = self.session.send(self.reply_socket, 'history_reply',
288 content, parent, ident)
305 content, parent, ident)
289 io.raw_print(msg)
306 io.raw_print(msg)
290
307
308 def connect_request(self, ident, parent):
309 if self._recorded_ports is not None:
310 content = self._recorded_ports.copy()
311 else:
312 content = {}
313 msg = self.session.send(self.reply_socket, 'connect_reply',
314 content, parent, ident)
315 io.raw_print(msg)
316
291 def shutdown_request(self, ident, parent):
317 def shutdown_request(self, ident, parent):
292 self.shell.exit_now = True
318 self.shell.exit_now = True
293 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
319 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
294 sys.exit(0)
320 sys.exit(0)
295
321
296 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
297 # Protected interface
323 # Protected interface
298 #---------------------------------------------------------------------------
324 #---------------------------------------------------------------------------
299
325
300 def _abort_queue(self):
326 def _abort_queue(self):
301 while True:
327 while True:
302 try:
328 try:
303 ident = self.reply_socket.recv(zmq.NOBLOCK)
329 ident = self.reply_socket.recv(zmq.NOBLOCK)
304 except zmq.ZMQError, e:
330 except zmq.ZMQError, e:
305 if e.errno == zmq.EAGAIN:
331 if e.errno == zmq.EAGAIN:
306 break
332 break
307 else:
333 else:
308 assert self.reply_socket.rcvmore(), \
334 assert self.reply_socket.rcvmore(), \
309 "Unexpected missing message part."
335 "Unexpected missing message part."
310 msg = self.reply_socket.recv_json()
336 msg = self.reply_socket.recv_json()
311 io.raw_print("Aborting:\n", Message(msg))
337 io.raw_print("Aborting:\n", Message(msg))
312 msg_type = msg['msg_type']
338 msg_type = msg['msg_type']
313 reply_type = msg_type.split('_')[0] + '_reply'
339 reply_type = msg_type.split('_')[0] + '_reply'
314 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
340 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
315 io.raw_print(reply_msg)
341 io.raw_print(reply_msg)
316 self.reply_socket.send(ident,zmq.SNDMORE)
342 self.reply_socket.send(ident,zmq.SNDMORE)
317 self.reply_socket.send_json(reply_msg)
343 self.reply_socket.send_json(reply_msg)
318 # We need to wait a bit for requests to come in. This can probably
344 # We need to wait a bit for requests to come in. This can probably
319 # be set shorter for true asynchronous clients.
345 # be set shorter for true asynchronous clients.
320 time.sleep(0.1)
346 time.sleep(0.1)
321
347
322 def _raw_input(self, prompt, ident, parent):
348 def _raw_input(self, prompt, ident, parent):
323 # Flush output before making the request.
349 # Flush output before making the request.
324 sys.stderr.flush()
350 sys.stderr.flush()
325 sys.stdout.flush()
351 sys.stdout.flush()
326
352
327 # Send the input request.
353 # Send the input request.
328 content = dict(prompt=prompt)
354 content = dict(prompt=prompt)
329 msg = self.session.msg(u'input_request', content, parent)
355 msg = self.session.msg(u'input_request', content, parent)
330 self.req_socket.send_json(msg)
356 self.req_socket.send_json(msg)
331
357
332 # Await a response.
358 # Await a response.
333 reply = self.req_socket.recv_json()
359 reply = self.req_socket.recv_json()
334 try:
360 try:
335 value = reply['content']['value']
361 value = reply['content']['value']
336 except:
362 except:
337 io.raw_print_err("Got bad raw_input reply: ")
363 io.raw_print_err("Got bad raw_input reply: ")
338 io.raw_print_err(Message(parent))
364 io.raw_print_err(Message(parent))
339 value = ''
365 value = ''
340 return value
366 return value
341
367
342 def _complete(self, msg):
368 def _complete(self, msg):
343 c = msg['content']
369 c = msg['content']
344 try:
370 try:
345 cpos = int(c['cursor_pos'])
371 cpos = int(c['cursor_pos'])
346 except:
372 except:
347 # If we don't get something that we can convert to an integer, at
373 # If we don't get something that we can convert to an integer, at
348 # least attempt the completion guessing the cursor is at the end of
374 # least attempt the completion guessing the cursor is at the end of
349 # the text, if there's any, and otherwise of the line
375 # the text, if there's any, and otherwise of the line
350 cpos = len(c['text'])
376 cpos = len(c['text'])
351 if cpos==0:
377 if cpos==0:
352 cpos = len(c['line'])
378 cpos = len(c['line'])
353 return self.shell.complete(c['text'], c['line'], cpos)
379 return self.shell.complete(c['text'], c['line'], cpos)
354
380
355 def _object_info(self, context):
381 def _object_info(self, context):
356 symbol, leftover = self._symbol_from_context(context)
382 symbol, leftover = self._symbol_from_context(context)
357 if symbol is not None and not leftover:
383 if symbol is not None and not leftover:
358 doc = getattr(symbol, '__doc__', '')
384 doc = getattr(symbol, '__doc__', '')
359 else:
385 else:
360 doc = ''
386 doc = ''
361 object_info = dict(docstring = doc)
387 object_info = dict(docstring = doc)
362 return object_info
388 return object_info
363
389
364 def _symbol_from_context(self, context):
390 def _symbol_from_context(self, context):
365 if not context:
391 if not context:
366 return None, context
392 return None, context
367
393
368 base_symbol_string = context[0]
394 base_symbol_string = context[0]
369 symbol = self.shell.user_ns.get(base_symbol_string, None)
395 symbol = self.shell.user_ns.get(base_symbol_string, None)
370 if symbol is None:
396 if symbol is None:
371 symbol = __builtin__.__dict__.get(base_symbol_string, None)
397 symbol = __builtin__.__dict__.get(base_symbol_string, None)
372 if symbol is None:
398 if symbol is None:
373 return None, context
399 return None, context
374
400
375 context = context[1:]
401 context = context[1:]
376 for i, name in enumerate(context):
402 for i, name in enumerate(context):
377 new_symbol = getattr(symbol, name, None)
403 new_symbol = getattr(symbol, name, None)
378 if new_symbol is None:
404 if new_symbol is None:
379 return symbol, context[i:]
405 return symbol, context[i:]
380 else:
406 else:
381 symbol = new_symbol
407 symbol = new_symbol
382
408
383 return symbol, []
409 return symbol, []
384
410
385 def _at_shutdown(self):
411 def _at_shutdown(self):
386 """Actions taken at shutdown by the kernel, called by python's atexit.
412 """Actions taken at shutdown by the kernel, called by python's atexit.
387 """
413 """
388 # io.rprint("Kernel at_shutdown") # dbg
414 # io.rprint("Kernel at_shutdown") # dbg
389 if self._shutdown_message is not None:
415 if self._shutdown_message is not None:
390 self.reply_socket.send_json(self._shutdown_message)
416 self.reply_socket.send_json(self._shutdown_message)
391 io.raw_print(self._shutdown_message)
417 io.raw_print(self._shutdown_message)
392 # A very short sleep to give zmq time to flush its message buffers
418 # A very short sleep to give zmq time to flush its message buffers
393 # before Python truly shuts down.
419 # before Python truly shuts down.
394 time.sleep(0.01)
420 time.sleep(0.01)
395
421
396
422
397 class QtKernel(Kernel):
423 class QtKernel(Kernel):
398 """A Kernel subclass with Qt support."""
424 """A Kernel subclass with Qt support."""
399
425
400 def start(self):
426 def start(self):
401 """Start a kernel with QtPy4 event loop integration."""
427 """Start a kernel with QtPy4 event loop integration."""
402
428
403 from PyQt4 import QtCore
429 from PyQt4 import QtCore
404 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
430 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
405
431
406 self.app = get_app_qt4([" "])
432 self.app = get_app_qt4([" "])
407 self.app.setQuitOnLastWindowClosed(False)
433 self.app.setQuitOnLastWindowClosed(False)
408 self.timer = QtCore.QTimer()
434 self.timer = QtCore.QTimer()
409 self.timer.timeout.connect(self.do_one_iteration)
435 self.timer.timeout.connect(self.do_one_iteration)
410 # Units for the timer are in milliseconds
436 # Units for the timer are in milliseconds
411 self.timer.start(1000*self._poll_interval)
437 self.timer.start(1000*self._poll_interval)
412 start_event_loop_qt4(self.app)
438 start_event_loop_qt4(self.app)
413
439
414
440
415 class WxKernel(Kernel):
441 class WxKernel(Kernel):
416 """A Kernel subclass with Wx support."""
442 """A Kernel subclass with Wx support."""
417
443
418 def start(self):
444 def start(self):
419 """Start a kernel with wx event loop support."""
445 """Start a kernel with wx event loop support."""
420
446
421 import wx
447 import wx
422 from IPython.lib.guisupport import start_event_loop_wx
448 from IPython.lib.guisupport import start_event_loop_wx
423
449
424 doi = self.do_one_iteration
450 doi = self.do_one_iteration
425 # Wx uses milliseconds
451 # Wx uses milliseconds
426 poll_interval = int(1000*self._poll_interval)
452 poll_interval = int(1000*self._poll_interval)
427
453
428 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
454 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
429 # We make the Frame hidden when we create it in the main app below.
455 # We make the Frame hidden when we create it in the main app below.
430 class TimerFrame(wx.Frame):
456 class TimerFrame(wx.Frame):
431 def __init__(self, func):
457 def __init__(self, func):
432 wx.Frame.__init__(self, None, -1)
458 wx.Frame.__init__(self, None, -1)
433 self.timer = wx.Timer(self)
459 self.timer = wx.Timer(self)
434 # Units for the timer are in milliseconds
460 # Units for the timer are in milliseconds
435 self.timer.Start(poll_interval)
461 self.timer.Start(poll_interval)
436 self.Bind(wx.EVT_TIMER, self.on_timer)
462 self.Bind(wx.EVT_TIMER, self.on_timer)
437 self.func = func
463 self.func = func
438
464
439 def on_timer(self, event):
465 def on_timer(self, event):
440 self.func()
466 self.func()
441
467
442 # We need a custom wx.App to create our Frame subclass that has the
468 # We need a custom wx.App to create our Frame subclass that has the
443 # wx.Timer to drive the ZMQ event loop.
469 # wx.Timer to drive the ZMQ event loop.
444 class IPWxApp(wx.App):
470 class IPWxApp(wx.App):
445 def OnInit(self):
471 def OnInit(self):
446 self.frame = TimerFrame(doi)
472 self.frame = TimerFrame(doi)
447 self.frame.Show(False)
473 self.frame.Show(False)
448 return True
474 return True
449
475
450 # The redirect=False here makes sure that wx doesn't replace
476 # The redirect=False here makes sure that wx doesn't replace
451 # sys.stdout/stderr with its own classes.
477 # sys.stdout/stderr with its own classes.
452 self.app = IPWxApp(redirect=False)
478 self.app = IPWxApp(redirect=False)
453 start_event_loop_wx(self.app)
479 start_event_loop_wx(self.app)
454
480
455
481
456 class TkKernel(Kernel):
482 class TkKernel(Kernel):
457 """A Kernel subclass with Tk support."""
483 """A Kernel subclass with Tk support."""
458
484
459 def start(self):
485 def start(self):
460 """Start a Tk enabled event loop."""
486 """Start a Tk enabled event loop."""
461
487
462 import Tkinter
488 import Tkinter
463 doi = self.do_one_iteration
489 doi = self.do_one_iteration
464 # Tk uses milliseconds
490 # Tk uses milliseconds
465 poll_interval = int(1000*self._poll_interval)
491 poll_interval = int(1000*self._poll_interval)
466 # For Tkinter, we create a Tk object and call its withdraw method.
492 # For Tkinter, we create a Tk object and call its withdraw method.
467 class Timer(object):
493 class Timer(object):
468 def __init__(self, func):
494 def __init__(self, func):
469 self.app = Tkinter.Tk()
495 self.app = Tkinter.Tk()
470 self.app.withdraw()
496 self.app.withdraw()
471 self.func = func
497 self.func = func
472
498
473 def on_timer(self):
499 def on_timer(self):
474 self.func()
500 self.func()
475 self.app.after(poll_interval, self.on_timer)
501 self.app.after(poll_interval, self.on_timer)
476
502
477 def start(self):
503 def start(self):
478 self.on_timer() # Call it once to get things going.
504 self.on_timer() # Call it once to get things going.
479 self.app.mainloop()
505 self.app.mainloop()
480
506
481 self.timer = Timer(doi)
507 self.timer = Timer(doi)
482 self.timer.start()
508 self.timer.start()
483
509
484
510
485 class GTKKernel(Kernel):
511 class GTKKernel(Kernel):
486 """A Kernel subclass with GTK support."""
512 """A Kernel subclass with GTK support."""
487
513
488 def start(self):
514 def start(self):
489 """Start the kernel, coordinating with the GTK event loop"""
515 """Start the kernel, coordinating with the GTK event loop"""
490 from .gui.gtkembed import GTKEmbed
516 from .gui.gtkembed import GTKEmbed
491
517
492 gtk_kernel = GTKEmbed(self)
518 gtk_kernel = GTKEmbed(self)
493 gtk_kernel.start()
519 gtk_kernel.start()
494
520
495
521
496 #-----------------------------------------------------------------------------
522 #-----------------------------------------------------------------------------
497 # Kernel main and launch functions
523 # Kernel main and launch functions
498 #-----------------------------------------------------------------------------
524 #-----------------------------------------------------------------------------
499
525
500 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,
526 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,
501 independent=False, pylab=False):
527 independent=False, pylab=False):
502 """Launches a localhost kernel, binding to the specified ports.
528 """Launches a localhost kernel, binding to the specified ports.
503
529
504 Parameters
530 Parameters
505 ----------
531 ----------
506 xrep_port : int, optional
532 xrep_port : int, optional
507 The port to use for XREP channel.
533 The port to use for XREP channel.
508
534
509 pub_port : int, optional
535 pub_port : int, optional
510 The port to use for the SUB channel.
536 The port to use for the SUB channel.
511
537
512 req_port : int, optional
538 req_port : int, optional
513 The port to use for the REQ (raw input) channel.
539 The port to use for the REQ (raw input) channel.
514
540
515 hb_port : int, optional
541 hb_port : int, optional
516 The port to use for the hearbeat REP channel.
542 The port to use for the hearbeat REP channel.
517
543
518 independent : bool, optional (default False)
544 independent : bool, optional (default False)
519 If set, the kernel process is guaranteed to survive if this process
545 If set, the kernel process is guaranteed to survive if this process
520 dies. If not set, an effort is made to ensure that the kernel is killed
546 dies. If not set, an effort is made to ensure that the kernel is killed
521 when this process dies. Note that in this case it is still good practice
547 when this process dies. Note that in this case it is still good practice
522 to kill kernels manually before exiting.
548 to kill kernels manually before exiting.
523
549
524 pylab : bool or string, optional (default False)
550 pylab : bool or string, optional (default False)
525 If not False, the kernel will be launched with pylab enabled. If a
551 If not False, the kernel will be launched with pylab enabled. If a
526 string is passed, matplotlib will use the specified backend. Otherwise,
552 string is passed, matplotlib will use the specified backend. Otherwise,
527 matplotlib's default backend will be used.
553 matplotlib's default backend will be used.
528
554
529 Returns
555 Returns
530 -------
556 -------
531 A tuple of form:
557 A tuple of form:
532 (kernel_process, xrep_port, pub_port, req_port)
558 (kernel_process, xrep_port, pub_port, req_port)
533 where kernel_process is a Popen object and the ports are integers.
559 where kernel_process is a Popen object and the ports are integers.
534 """
560 """
535 extra_arguments = []
561 extra_arguments = []
536 if pylab:
562 if pylab:
537 extra_arguments.append('--pylab')
563 extra_arguments.append('--pylab')
538 if isinstance(pylab, basestring):
564 if isinstance(pylab, basestring):
539 extra_arguments.append(pylab)
565 extra_arguments.append(pylab)
540 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
566 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
541 xrep_port, pub_port, req_port, hb_port,
567 xrep_port, pub_port, req_port, hb_port,
542 independent, extra_arguments)
568 independent, extra_arguments)
543
569
544
570
545 def main():
571 def main():
546 """ The IPython kernel main entry point.
572 """ The IPython kernel main entry point.
547 """
573 """
548 parser = make_argument_parser()
574 parser = make_argument_parser()
549 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
575 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
550 const='auto', help = \
576 const='auto', help = \
551 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
577 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
552 given, the GUI backend is matplotlib's, otherwise use one of: \
578 given, the GUI backend is matplotlib's, otherwise use one of: \
553 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
579 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
554 namespace = parser.parse_args()
580 namespace = parser.parse_args()
555
581
556 kernel_class = Kernel
582 kernel_class = Kernel
557
583
558 kernel_classes = {
584 kernel_classes = {
559 'qt' : QtKernel,
585 'qt' : QtKernel,
560 'qt4': QtKernel,
586 'qt4': QtKernel,
561 'inline': Kernel,
587 'inline': Kernel,
562 'wx' : WxKernel,
588 'wx' : WxKernel,
563 'tk' : TkKernel,
589 'tk' : TkKernel,
564 'gtk': GTKKernel,
590 'gtk': GTKKernel,
565 }
591 }
566 if namespace.pylab:
592 if namespace.pylab:
567 if namespace.pylab == 'auto':
593 if namespace.pylab == 'auto':
568 gui, backend = pylabtools.find_gui_and_backend()
594 gui, backend = pylabtools.find_gui_and_backend()
569 else:
595 else:
570 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
596 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
571 kernel_class = kernel_classes.get(gui)
597 kernel_class = kernel_classes.get(gui)
572 if kernel_class is None:
598 if kernel_class is None:
573 raise ValueError('GUI is not supported: %r' % gui)
599 raise ValueError('GUI is not supported: %r' % gui)
574 pylabtools.activate_matplotlib(backend)
600 pylabtools.activate_matplotlib(backend)
575
601
576 kernel = make_kernel(namespace, kernel_class, OutStream)
602 kernel = make_kernel(namespace, kernel_class, OutStream)
577
603
578 if namespace.pylab:
604 if namespace.pylab:
579 pylabtools.import_pylab(kernel.shell.user_ns, backend,
605 pylabtools.import_pylab(kernel.shell.user_ns, backend,
580 shell=kernel.shell)
606 shell=kernel.shell)
581
607
582 start_kernel(namespace, kernel)
608 start_kernel(namespace, kernel)
583
609
584
610
585 if __name__ == '__main__':
611 if __name__ == '__main__':
586 main()
612 main()
@@ -1,758 +1,782 b''
1 .. _messaging:
1 .. _messaging:
2
2
3 ======================
3 ======================
4 Messaging in IPython
4 Messaging in IPython
5 ======================
5 ======================
6
6
7
7
8 Introduction
8 Introduction
9 ============
9 ============
10
10
11 This document explains the basic communications design and messaging
11 This document explains the basic communications design and messaging
12 specification for how the various IPython objects interact over a network
12 specification for how the various IPython objects interact over a network
13 transport. The current implementation uses the ZeroMQ_ library for messaging
13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 within and between hosts.
14 within and between hosts.
15
15
16 .. Note::
16 .. Note::
17
17
18 This document should be considered the authoritative description of the
18 This document should be considered the authoritative description of the
19 IPython messaging protocol, and all developers are strongly encouraged to
19 IPython messaging protocol, and all developers are strongly encouraged to
20 keep it updated as the implementation evolves, so that we have a single
20 keep it updated as the implementation evolves, so that we have a single
21 common reference for all protocol details.
21 common reference for all protocol details.
22
22
23 The basic design is explained in the following diagram:
23 The basic design is explained in the following diagram:
24
24
25 .. image:: frontend-kernel.png
25 .. image:: frontend-kernel.png
26 :width: 450px
26 :width: 450px
27 :alt: IPython kernel/frontend messaging architecture.
27 :alt: IPython kernel/frontend messaging architecture.
28 :align: center
28 :align: center
29 :target: ../_images/frontend-kernel.png
29 :target: ../_images/frontend-kernel.png
30
30
31 A single kernel can be simultaneously connected to one or more frontends. The
31 A single kernel can be simultaneously connected to one or more frontends. The
32 kernel has three sockets that serve the following functions:
32 kernel has three sockets that serve the following functions:
33
33
34 1. REQ: this socket is connected to a *single* frontend at a time, and it allows
34 1. REQ: this socket is connected to a *single* frontend at a time, and it allows
35 the kernel to request input from a frontend when :func:`raw_input` is called.
35 the kernel to request input from a frontend when :func:`raw_input` is called.
36 The frontend holding the matching REP socket acts as a 'virtual keyboard'
36 The frontend holding the matching REP socket acts as a 'virtual keyboard'
37 for the kernel while this communication is happening (illustrated in the
37 for the kernel while this communication is happening (illustrated in the
38 figure by the black outline around the central keyboard). In practice,
38 figure by the black outline around the central keyboard). In practice,
39 frontends may display such kernel requests using a special input widget or
39 frontends may display such kernel requests using a special input widget or
40 otherwise indicating that the user is to type input for the kernel instead
40 otherwise indicating that the user is to type input for the kernel instead
41 of normal commands in the frontend.
41 of normal commands in the frontend.
42
42
43 2. XREP: this single sockets allows multiple incoming connections from
43 2. XREP: this single sockets allows multiple incoming connections from
44 frontends, and this is the socket where requests for code execution, object
44 frontends, and this is the socket where requests for code execution, object
45 information, prompts, etc. are made to the kernel by any frontend. The
45 information, prompts, etc. are made to the kernel by any frontend. The
46 communication on this socket is a sequence of request/reply actions from
46 communication on this socket is a sequence of request/reply actions from
47 each frontend and the kernel.
47 each frontend and the kernel.
48
48
49 3. PUB: this socket is the 'broadcast channel' where the kernel publishes all
49 3. PUB: this socket is the 'broadcast channel' where the kernel publishes all
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 client over the XREP socket and its own requests on the REP socket. There
51 client over the XREP socket and its own requests on the REP socket. There
52 are a number of actions in Python which generate side effects: :func:`print`
52 are a number of actions in Python which generate side effects: :func:`print`
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 a multi-client scenario, we want all frontends to be able to know what each
54 a multi-client scenario, we want all frontends to be able to know what each
55 other has sent to the kernel (this can be useful in collaborative scenarios,
55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 for example). This socket allows both side effects and the information
56 for example). This socket allows both side effects and the information
57 about communications taking place with one client over the XREQ/XREP channel
57 about communications taking place with one client over the XREQ/XREP channel
58 to be made available to all clients in a uniform manner.
58 to be made available to all clients in a uniform manner.
59
59
60 All messages are tagged with enough information (details below) for clients
60 All messages are tagged with enough information (details below) for clients
61 to know which messages come from their own interaction with the kernel and
61 to know which messages come from their own interaction with the kernel and
62 which ones are from other clients, so they can display each type
62 which ones are from other clients, so they can display each type
63 appropriately.
63 appropriately.
64
64
65 The actual format of the messages allowed on each of these channels is
65 The actual format of the messages allowed on each of these channels is
66 specified below. Messages are dicts of dicts with string keys and values that
66 specified below. Messages are dicts of dicts with string keys and values that
67 are reasonably representable in JSON. Our current implementation uses JSON
67 are reasonably representable in JSON. Our current implementation uses JSON
68 explicitly as its message format, but this shouldn't be considered a permanent
68 explicitly as its message format, but this shouldn't be considered a permanent
69 feature. As we've discovered that JSON has non-trivial performance issues due
69 feature. As we've discovered that JSON has non-trivial performance issues due
70 to excessive copying, we may in the future move to a pure pickle-based raw
70 to excessive copying, we may in the future move to a pure pickle-based raw
71 message format. However, it should be possible to easily convert from the raw
71 message format. However, it should be possible to easily convert from the raw
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 As long as it's easy to make a JSON version of the objects that is a faithful
73 As long as it's easy to make a JSON version of the objects that is a faithful
74 representation of all the data, we can communicate with such clients.
74 representation of all the data, we can communicate with such clients.
75
75
76 .. Note::
76 .. Note::
77
77
78 Not all of these have yet been fully fleshed out, but the key ones are, see
78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 kernel and frontend files for actual implementation details.
79 kernel and frontend files for actual implementation details.
80
80
81
81
82 Python functional API
82 Python functional API
83 =====================
83 =====================
84
84
85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
86 should develop, at a few key points, functional forms of all the requests that
86 should develop, at a few key points, functional forms of all the requests that
87 take arguments in this manner and automatically construct the necessary dict
87 take arguments in this manner and automatically construct the necessary dict
88 for sending.
88 for sending.
89
89
90
90
91 General Message Format
91 General Message Format
92 ======================
92 ======================
93
93
94 All messages send or received by any IPython process should have the following
94 All messages send or received by any IPython process should have the following
95 generic structure::
95 generic structure::
96
96
97 {
97 {
98 # The message header contains a pair of unique identifiers for the
98 # The message header contains a pair of unique identifiers for the
99 # originating session and the actual message id, in addition to the
99 # originating session and the actual message id, in addition to the
100 # username for the process that generated the message. This is useful in
100 # username for the process that generated the message. This is useful in
101 # collaborative settings where multiple users may be interacting with the
101 # collaborative settings where multiple users may be interacting with the
102 # same kernel simultaneously, so that frontends can label the various
102 # same kernel simultaneously, so that frontends can label the various
103 # messages in a meaningful way.
103 # messages in a meaningful way.
104 'header' : { 'msg_id' : uuid,
104 'header' : { 'msg_id' : uuid,
105 'username' : str,
105 'username' : str,
106 'session' : uuid
106 'session' : uuid
107 },
107 },
108
108
109 # In a chain of messages, the header from the parent is copied so that
109 # In a chain of messages, the header from the parent is copied so that
110 # clients can track where messages come from.
110 # clients can track where messages come from.
111 'parent_header' : dict,
111 'parent_header' : dict,
112
112
113 # All recognized message type strings are listed below.
113 # All recognized message type strings are listed below.
114 'msg_type' : str,
114 'msg_type' : str,
115
115
116 # The actual content of the message must be a dict, whose structure
116 # The actual content of the message must be a dict, whose structure
117 # depends on the message type.x
117 # depends on the message type.x
118 'content' : dict,
118 'content' : dict,
119 }
119 }
120
120
121 For each message type, the actual content will differ and all existing message
121 For each message type, the actual content will differ and all existing message
122 types are specified in what follows of this document.
122 types are specified in what follows of this document.
123
123
124
124
125 Messages on the XREP/XREQ socket
125 Messages on the XREP/XREQ socket
126 ================================
126 ================================
127
127
128 .. _execute:
128 .. _execute:
129
129
130 Execute
130 Execute
131 -------
131 -------
132
132
133 This message type is used by frontends to ask the kernel to execute code on
133 This message type is used by frontends to ask the kernel to execute code on
134 behalf of the user, in a namespace reserved to the user's variables (and thus
134 behalf of the user, in a namespace reserved to the user's variables (and thus
135 separate from the kernel's own internal code and variables).
135 separate from the kernel's own internal code and variables).
136
136
137 Message type: ``execute_request``::
137 Message type: ``execute_request``::
138
138
139 content = {
139 content = {
140 # Source code to be executed by the kernel, one or more lines.
140 # Source code to be executed by the kernel, one or more lines.
141 'code' : str,
141 'code' : str,
142
142
143 # A boolean flag which, if True, signals the kernel to execute this
143 # A boolean flag which, if True, signals the kernel to execute this
144 # code as quietly as possible. This means that the kernel will compile
144 # code as quietly as possible. This means that the kernel will compile
145 # the code witIPython/core/tests/h 'exec' instead of 'single' (so
145 # the code witIPython/core/tests/h 'exec' instead of 'single' (so
146 # sys.displayhook will not fire), and will *not*:
146 # sys.displayhook will not fire), and will *not*:
147 # - broadcast exceptions on the PUB socket
147 # - broadcast exceptions on the PUB socket
148 # - do any logging
148 # - do any logging
149 # - populate any history
149 # - populate any history
150 #
150 #
151 # The default is False.
151 # The default is False.
152 'silent' : bool,
152 'silent' : bool,
153
153
154 # A list of variable names from the user's namespace to be retrieved. What
154 # A list of variable names from the user's namespace to be retrieved. What
155 # returns is a JSON string of the variable's repr(), not a python object.
155 # returns is a JSON string of the variable's repr(), not a python object.
156 'user_variables' : list,
156 'user_variables' : list,
157
157
158 # Similarly, a dict mapping names to expressions to be evaluated in the
158 # Similarly, a dict mapping names to expressions to be evaluated in the
159 # user's dict.
159 # user's dict.
160 'user_expressions' : dict,
160 'user_expressions' : dict,
161 }
161 }
162
162
163 The ``code`` field contains a single string, but this may be a multiline
163 The ``code`` field contains a single string, but this may be a multiline
164 string. The kernel is responsible for splitting this into possibly more than
164 string. The kernel is responsible for splitting this into possibly more than
165 one block and deciding whether to compile these in 'single' or 'exec' mode.
165 one block and deciding whether to compile these in 'single' or 'exec' mode.
166 We're still sorting out this policy. The current inputsplitter is capable of
166 We're still sorting out this policy. The current inputsplitter is capable of
167 splitting the input for blocks that can all be run as 'single', but in the long
167 splitting the input for blocks that can all be run as 'single', but in the long
168 run it may prove cleaner to only use 'single' mode for truly single-line
168 run it may prove cleaner to only use 'single' mode for truly single-line
169 inputs, and run all multiline input in 'exec' mode. This would preserve the
169 inputs, and run all multiline input in 'exec' mode. This would preserve the
170 natural behavior of single-line inputs while allowing long cells to behave more
170 natural behavior of single-line inputs while allowing long cells to behave more
171 likea a script. This design will be refined as we complete the implementation.
171 likea a script. This design will be refined as we complete the implementation.
172
172
173 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
173 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
174 the notion of a prompt string that allowed arbitrary code to be evaluated, and
174 the notion of a prompt string that allowed arbitrary code to be evaluated, and
175 this was put to good use by many in creating prompts that displayed system
175 this was put to good use by many in creating prompts that displayed system
176 status, path information, and even more esoteric uses like remote instrument
176 status, path information, and even more esoteric uses like remote instrument
177 status aqcuired over the network. But now that IPython has a clean separation
177 status aqcuired over the network. But now that IPython has a clean separation
178 between the kernel and the clients, the notion of embedding 'prompt'
178 between the kernel and the clients, the notion of embedding 'prompt'
179 maninpulations into the kernel itself feels awkward. Prompts should be a
179 maninpulations into the kernel itself feels awkward. Prompts should be a
180 frontend-side feature, and it should be even possible for different frontends
180 frontend-side feature, and it should be even possible for different frontends
181 to display different prompts while interacting with the same kernel.
181 to display different prompts while interacting with the same kernel.
182
182
183 We have therefore abandoned the idea of a 'prompt string' to be evaluated by
183 We have therefore abandoned the idea of a 'prompt string' to be evaluated by
184 the kernel, and instead provide the ability to retrieve from the user's
184 the kernel, and instead provide the ability to retrieve from the user's
185 namespace information after the execution of the main ``code``, with two fields
185 namespace information after the execution of the main ``code``, with two fields
186 of the execution request:
186 of the execution request:
187
187
188 - ``user_variables``: If only variables from the user's namespace are needed, a
188 - ``user_variables``: If only variables from the user's namespace are needed, a
189 list of variable names can be passed and a dict with these names as keys and
189 list of variable names can be passed and a dict with these names as keys and
190 their :func:`repr()` as values will be returned.
190 their :func:`repr()` as values will be returned.
191
191
192 - ``user_expressions``: For more complex expressions that require function
192 - ``user_expressions``: For more complex expressions that require function
193 evaluations, a dict can be provided with string keys and arbitrary python
193 evaluations, a dict can be provided with string keys and arbitrary python
194 expressions as values. The return message will contain also a dict with the
194 expressions as values. The return message will contain also a dict with the
195 same keys and the :func:`repr()` of the evaluated expressions as value.
195 same keys and the :func:`repr()` of the evaluated expressions as value.
196
196
197 With this information, frontends can display any status information they wish
197 With this information, frontends can display any status information they wish
198 in the form that best suits each frontend (a status line, a popup, inline for a
198 in the form that best suits each frontend (a status line, a popup, inline for a
199 terminal, etc).
199 terminal, etc).
200
200
201 .. Note::
201 .. Note::
202
202
203 In order to obtain the current execution counter for the purposes of
203 In order to obtain the current execution counter for the purposes of
204 displaying input prompts, frontends simply make an execution request with an
204 displaying input prompts, frontends simply make an execution request with an
205 empty code string and ``silent=True``.
205 empty code string and ``silent=True``.
206
206
207 Execution semantics
207 Execution semantics
208 Upon completion of the execution request, the kernel *always* sends a
208 Upon completion of the execution request, the kernel *always* sends a
209 reply, with a status code indicating what happened and additional data
209 reply, with a status code indicating what happened and additional data
210 depending on the outcome.
210 depending on the outcome.
211
211
212 The ``code`` field is executed first, and then the ``user_variables`` and
212 The ``code`` field is executed first, and then the ``user_variables`` and
213 ``user_expressions`` are computed. This ensures that any error in the
213 ``user_expressions`` are computed. This ensures that any error in the
214 latter don't harm the main code execution.
214 latter don't harm the main code execution.
215
215
216 Any error in retrieving the ``user_variables`` or evaluating the
216 Any error in retrieving the ``user_variables`` or evaluating the
217 ``user_expressions`` will result in a simple error message in the return
217 ``user_expressions`` will result in a simple error message in the return
218 fields of the form::
218 fields of the form::
219
219
220 [ERROR] ExceptionType: Exception message
220 [ERROR] ExceptionType: Exception message
221
221
222 The user can simply send the same variable name or expression for
222 The user can simply send the same variable name or expression for
223 evaluation to see a regular traceback.
223 evaluation to see a regular traceback.
224
224
225 Execution counter (old prompt number)
225 Execution counter (old prompt number)
226 The kernel has a single, monotonically increasing counter of all execution
226 The kernel has a single, monotonically increasing counter of all execution
227 requests that are made with ``silent=False``. This counter is used to
227 requests that are made with ``silent=False``. This counter is used to
228 populate the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will
228 populate the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will
229 likely want to display it in some form to the user, which will typically
229 likely want to display it in some form to the user, which will typically
230 (but not necessarily) be done in the prompts. The value of this counter
230 (but not necessarily) be done in the prompts. The value of this counter
231 will be returned as the ``execution_count`` field of all ``execute_reply```
231 will be returned as the ``execution_count`` field of all ``execute_reply```
232 messages.
232 messages.
233
233
234 Message type: ``execute_reply``::
234 Message type: ``execute_reply``::
235
235
236 content = {
236 content = {
237 # One of: 'ok' OR 'error' OR 'abort'
237 # One of: 'ok' OR 'error' OR 'abort'
238 'status' : str,
238 'status' : str,
239
239
240 # The global kernel counter that increases by one with each non-silent
240 # The global kernel counter that increases by one with each non-silent
241 # executed request. This will typically be used by clients to display
241 # executed request. This will typically be used by clients to display
242 # prompt numbers to the user. If the request was a silent one, this will
242 # prompt numbers to the user. If the request was a silent one, this will
243 # be the current value of the counter in the kernel.
243 # be the current value of the counter in the kernel.
244 'execution_count' : int,
244 'execution_count' : int,
245 }
245 }
246
246
247 When status is 'ok', the following extra fields are present::
247 When status is 'ok', the following extra fields are present::
248
248
249 {
249 {
250 # The execution payload is a dict with string keys that may have been
250 # The execution payload is a dict with string keys that may have been
251 # produced by the code being executed. It is retrieved by the kernel at
251 # produced by the code being executed. It is retrieved by the kernel at
252 # the end of the execution and sent back to the front end, which can take
252 # the end of the execution and sent back to the front end, which can take
253 # action on it as needed. See main text for further details.
253 # action on it as needed. See main text for further details.
254 'payload' : dict,
254 'payload' : dict,
255
255
256 # Results for the user_variables and user_expressions.
256 # Results for the user_variables and user_expressions.
257 'user_variables' : dict,
257 'user_variables' : dict,
258 'user_expressions' : dict,
258 'user_expressions' : dict,
259
259
260 # The kernel will often transform the input provided to it. If the
260 # The kernel will often transform the input provided to it. If the
261 # '---->' transform had been applied, this is filled, otherwise it's the
261 # '---->' transform had been applied, this is filled, otherwise it's the
262 # empty string. So transformations like magics don't appear here, only
262 # empty string. So transformations like magics don't appear here, only
263 # autocall ones.
263 # autocall ones.
264 'transformed_code' : str,
264 'transformed_code' : str,
265 }
265 }
266
266
267 .. admonition:: Execution payloads
267 .. admonition:: Execution payloads
268
268
269 The notion of an 'execution payload' is different from a return value of a
269 The notion of an 'execution payload' is different from a return value of a
270 given set of code, which normally is just displayed on the pyout stream
270 given set of code, which normally is just displayed on the pyout stream
271 through the PUB socket. The idea of a payload is to allow special types of
271 through the PUB socket. The idea of a payload is to allow special types of
272 code, typically magics, to populate a data container in the IPython kernel
272 code, typically magics, to populate a data container in the IPython kernel
273 that will be shipped back to the caller via this channel. The kernel will
273 that will be shipped back to the caller via this channel. The kernel will
274 have an API for this, probably something along the lines of::
274 have an API for this, probably something along the lines of::
275
275
276 ip.exec_payload_add(key, value)
276 ip.exec_payload_add(key, value)
277
277
278 though this API is still in the design stages. The data returned in this
278 though this API is still in the design stages. The data returned in this
279 payload will allow frontends to present special views of what just happened.
279 payload will allow frontends to present special views of what just happened.
280
280
281
281
282 When status is 'error', the following extra fields are present::
282 When status is 'error', the following extra fields are present::
283
283
284 {
284 {
285 'exc_name' : str, # Exception name, as a string
285 'exc_name' : str, # Exception name, as a string
286 'exc_value' : str, # Exception value, as a string
286 'exc_value' : str, # Exception value, as a string
287
287
288 # The traceback will contain a list of frames, represented each as a
288 # The traceback will contain a list of frames, represented each as a
289 # string. For now we'll stick to the existing design of ultraTB, which
289 # string. For now we'll stick to the existing design of ultraTB, which
290 # controls exception level of detail statefully. But eventually we'll
290 # controls exception level of detail statefully. But eventually we'll
291 # want to grow into a model where more information is collected and
291 # want to grow into a model where more information is collected and
292 # packed into the traceback object, with clients deciding how little or
292 # packed into the traceback object, with clients deciding how little or
293 # how much of it to unpack. But for now, let's start with a simple list
293 # how much of it to unpack. But for now, let's start with a simple list
294 # of strings, since that requires only minimal changes to ultratb as
294 # of strings, since that requires only minimal changes to ultratb as
295 # written.
295 # written.
296 'traceback' : list,
296 'traceback' : list,
297 }
297 }
298
298
299
299
300 When status is 'abort', there are for now no additional data fields. This
300 When status is 'abort', there are for now no additional data fields. This
301 happens when the kernel was interrupted by a signal.
301 happens when the kernel was interrupted by a signal.
302
302
303 Kernel attribute access
303 Kernel attribute access
304 -----------------------
304 -----------------------
305
305
306 While this protocol does not specify full RPC access to arbitrary methods of
306 While this protocol does not specify full RPC access to arbitrary methods of
307 the kernel object, the kernel does allow read (and in some cases write) access
307 the kernel object, the kernel does allow read (and in some cases write) access
308 to certain attributes.
308 to certain attributes.
309
309
310 The policy for which attributes can be read is: any attribute of the kernel, or
310 The policy for which attributes can be read is: any attribute of the kernel, or
311 its sub-objects, that belongs to a :class:`Configurable` object and has been
311 its sub-objects, that belongs to a :class:`Configurable` object and has been
312 declared at the class-level with Traits validation, is in principle accessible
312 declared at the class-level with Traits validation, is in principle accessible
313 as long as its name does not begin with a leading underscore. The attribute
313 as long as its name does not begin with a leading underscore. The attribute
314 itself will have metadata indicating whether it allows remote read and/or write
314 itself will have metadata indicating whether it allows remote read and/or write
315 access. The message spec follows for attribute read and write requests.
315 access. The message spec follows for attribute read and write requests.
316
316
317 Message type: ``getattr_request``::
317 Message type: ``getattr_request``::
318
318
319 content = {
319 content = {
320 # The (possibly dotted) name of the attribute
320 # The (possibly dotted) name of the attribute
321 'name' : str,
321 'name' : str,
322 }
322 }
323
323
324 When a ``getattr_request`` fails, there are two possible error types:
324 When a ``getattr_request`` fails, there are two possible error types:
325
325
326 - AttributeError: this type of error was raised when trying to access the
326 - AttributeError: this type of error was raised when trying to access the
327 given name by the kernel itself. This means that the attribute likely
327 given name by the kernel itself. This means that the attribute likely
328 doesn't exist.
328 doesn't exist.
329
329
330 - AccessError: the attribute exists but its value is not readable remotely.
330 - AccessError: the attribute exists but its value is not readable remotely.
331
331
332
332
333 Message type: ``getattr_reply``::
333 Message type: ``getattr_reply``::
334
334
335 content = {
335 content = {
336 # One of ['ok', 'AttributeError', 'AccessError'].
336 # One of ['ok', 'AttributeError', 'AccessError'].
337 'status' : str,
337 'status' : str,
338 # If status is 'ok', a JSON object.
338 # If status is 'ok', a JSON object.
339 'value' : object,
339 'value' : object,
340 }
340 }
341
341
342 Message type: ``setattr_request``::
342 Message type: ``setattr_request``::
343
343
344 content = {
344 content = {
345 # The (possibly dotted) name of the attribute
345 # The (possibly dotted) name of the attribute
346 'name' : str,
346 'name' : str,
347
347
348 # A JSON-encoded object, that will be validated by the Traits
348 # A JSON-encoded object, that will be validated by the Traits
349 # information in the kernel
349 # information in the kernel
350 'value' : object,
350 'value' : object,
351 }
351 }
352
352
353 When a ``setattr_request`` fails, there are also two possible error types with
353 When a ``setattr_request`` fails, there are also two possible error types with
354 similar meanings as those of the ``getattr_request`` case, but for writing.
354 similar meanings as those of the ``getattr_request`` case, but for writing.
355
355
356 Message type: ``setattr_reply``::
356 Message type: ``setattr_reply``::
357
357
358 content = {
358 content = {
359 # One of ['ok', 'AttributeError', 'AccessError'].
359 # One of ['ok', 'AttributeError', 'AccessError'].
360 'status' : str,
360 'status' : str,
361 }
361 }
362
362
363
363
364 Object information
364 Object information
365 ------------------
365 ------------------
366
366
367 One of IPython's most used capabilities is the introspection of Python objects
367 One of IPython's most used capabilities is the introspection of Python objects
368 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
368 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
369 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
369 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
370 enough that it warrants an explicit message type, especially because frontends
370 enough that it warrants an explicit message type, especially because frontends
371 may want to get object information in response to user keystrokes (like Tab or
371 may want to get object information in response to user keystrokes (like Tab or
372 F1) besides from the user explicitly typing code like ``x??``.
372 F1) besides from the user explicitly typing code like ``x??``.
373
373
374 Message type: ``object_info_request``::
374 Message type: ``object_info_request``::
375
375
376 content = {
376 content = {
377 # The (possibly dotted) name of the object to be searched in all
377 # The (possibly dotted) name of the object to be searched in all
378 # relevant namespaces
378 # relevant namespaces
379 'name' : str,
379 'name' : str,
380
380
381 # The level of detail desired. The default (0) is equivalent to typing
381 # The level of detail desired. The default (0) is equivalent to typing
382 # 'x?' at the prompt, 1 is equivalent to 'x??'.
382 # 'x?' at the prompt, 1 is equivalent to 'x??'.
383 'detail_level' : int,
383 'detail_level' : int,
384 }
384 }
385
385
386 The returned information will be a dictionary with keys very similar to the
386 The returned information will be a dictionary with keys very similar to the
387 field names that IPython prints at the terminal.
387 field names that IPython prints at the terminal.
388
388
389 Message type: ``object_info_reply``::
389 Message type: ``object_info_reply``::
390
390
391 content = {
391 content = {
392 # Boolean flag indicating whether the named object was found or not. If
392 # Boolean flag indicating whether the named object was found or not. If
393 # it's false, all other fields will be empty.
393 # it's false, all other fields will be empty.
394 'found' : bool,
394 'found' : bool,
395
395
396 # Flags for magics and system aliases
396 # Flags for magics and system aliases
397 'ismagic' : bool,
397 'ismagic' : bool,
398 'isalias' : bool,
398 'isalias' : bool,
399
399
400 # The name of the namespace where the object was found ('builtin',
400 # The name of the namespace where the object was found ('builtin',
401 # 'magics', 'alias', 'interactive', etc.)
401 # 'magics', 'alias', 'interactive', etc.)
402 'namespace' : str,
402 'namespace' : str,
403
403
404 # The type name will be type.__name__ for normal Python objects, but it
404 # The type name will be type.__name__ for normal Python objects, but it
405 # can also be a string like 'Magic function' or 'System alias'
405 # can also be a string like 'Magic function' or 'System alias'
406 'type_name' : str,
406 'type_name' : str,
407
407
408 'string_form' : str,
408 'string_form' : str,
409
409
410 # For objects with a __class__ attribute this will be set
410 # For objects with a __class__ attribute this will be set
411 'base_class' : str,
411 'base_class' : str,
412
412
413 # For objects with a __len__ attribute this will be set
413 # For objects with a __len__ attribute this will be set
414 'length' : int,
414 'length' : int,
415
415
416 # If the object is a function, class or method whose file we can find,
416 # If the object is a function, class or method whose file we can find,
417 # we give its full path
417 # we give its full path
418 'file' : str,
418 'file' : str,
419
419
420 # For pure Python callable objects, we can reconstruct the object
420 # For pure Python callable objects, we can reconstruct the object
421 # definition line which provides its call signature. For convenience this
421 # definition line which provides its call signature. For convenience this
422 # is returned as a single 'definition' field, but below the raw parts that
422 # is returned as a single 'definition' field, but below the raw parts that
423 # compose it are also returned as the argspec field.
423 # compose it are also returned as the argspec field.
424 'definition' : str,
424 'definition' : str,
425
425
426 # The individual parts that together form the definition string. Clients
426 # The individual parts that together form the definition string. Clients
427 # with rich display capabilities may use this to provide a richer and more
427 # with rich display capabilities may use this to provide a richer and more
428 # precise representation of the definition line (e.g. by highlighting
428 # precise representation of the definition line (e.g. by highlighting
429 # arguments based on the user's cursor position). For non-callable
429 # arguments based on the user's cursor position). For non-callable
430 # objects, this field is empty.
430 # objects, this field is empty.
431 'argspec' : { # The names of all the arguments
431 'argspec' : { # The names of all the arguments
432 args : list,
432 args : list,
433 # The name of the varargs (*args), if any
433 # The name of the varargs (*args), if any
434 varargs : str,
434 varargs : str,
435 # The name of the varkw (**kw), if any
435 # The name of the varkw (**kw), if any
436 varkw : str,
436 varkw : str,
437 # The values (as strings) of all default arguments. Note
437 # The values (as strings) of all default arguments. Note
438 # that these must be matched *in reverse* with the 'args'
438 # that these must be matched *in reverse* with the 'args'
439 # list above, since the first positional args have no default
439 # list above, since the first positional args have no default
440 # value at all.
440 # value at all.
441 func_defaults : list,
441 func_defaults : list,
442 },
442 },
443
443
444 # For instances, provide the constructor signature (the definition of
444 # For instances, provide the constructor signature (the definition of
445 # the __init__ method):
445 # the __init__ method):
446 'init_definition' : str,
446 'init_definition' : str,
447
447
448 # Docstrings: for any object (function, method, module, package) with a
448 # Docstrings: for any object (function, method, module, package) with a
449 # docstring, we show it. But in addition, we may provide additional
449 # docstring, we show it. But in addition, we may provide additional
450 # docstrings. For example, for instances we will show the constructor
450 # docstrings. For example, for instances we will show the constructor
451 # and class docstrings as well, if available.
451 # and class docstrings as well, if available.
452 'docstring' : str,
452 'docstring' : str,
453
453
454 # For instances, provide the constructor and class docstrings
454 # For instances, provide the constructor and class docstrings
455 'init_docstring' : str,
455 'init_docstring' : str,
456 'class_docstring' : str,
456 'class_docstring' : str,
457
457
458 # If it's a callable object whose call method has a separate docstring and
458 # If it's a callable object whose call method has a separate docstring and
459 # definition line:
459 # definition line:
460 'call_def' : str,
460 'call_def' : str,
461 'call_docstring' : str,
461 'call_docstring' : str,
462
462
463 # If detail_level was 1, we also try to find the source code that
463 # If detail_level was 1, we also try to find the source code that
464 # defines the object, if possible. The string 'None' will indicate
464 # defines the object, if possible. The string 'None' will indicate
465 # that no source was found.
465 # that no source was found.
466 'source' : str,
466 'source' : str,
467 }
467 }
468 '
468 '
469
469
470 Complete
470 Complete
471 --------
471 --------
472
472
473 Message type: ``complete_request``::
473 Message type: ``complete_request``::
474
474
475 content = {
475 content = {
476 # The text to be completed, such as 'a.is'
476 # The text to be completed, such as 'a.is'
477 'text' : str,
477 'text' : str,
478
478
479 # The full line, such as 'print a.is'. This allows completers to
479 # The full line, such as 'print a.is'. This allows completers to
480 # make decisions that may require information about more than just the
480 # make decisions that may require information about more than just the
481 # current word.
481 # current word.
482 'line' : str,
482 'line' : str,
483
483
484 # The entire block of text where the line is. This may be useful in the
484 # The entire block of text where the line is. This may be useful in the
485 # case of multiline completions where more context may be needed. Note: if
485 # case of multiline completions where more context may be needed. Note: if
486 # in practice this field proves unnecessary, remove it to lighten the
486 # in practice this field proves unnecessary, remove it to lighten the
487 # messages.
487 # messages.
488
488
489 'block' : str,
489 'block' : str,
490
490
491 # The position of the cursor where the user hit 'TAB' on the line.
491 # The position of the cursor where the user hit 'TAB' on the line.
492 'cursor_pos' : int,
492 'cursor_pos' : int,
493 }
493 }
494
494
495 Message type: ``complete_reply``::
495 Message type: ``complete_reply``::
496
496
497 content = {
497 content = {
498 # The list of all matches to the completion request, such as
498 # The list of all matches to the completion request, such as
499 # ['a.isalnum', 'a.isalpha'] for the above example.
499 # ['a.isalnum', 'a.isalpha'] for the above example.
500 'matches' : list
500 'matches' : list
501 }
501 }
502
502
503
503
504 History
504 History
505 -------
505 -------
506
506
507 For clients to explicitly request history from a kernel. The kernel has all
507 For clients to explicitly request history from a kernel. The kernel has all
508 the actual execution history stored in a single location, so clients can
508 the actual execution history stored in a single location, so clients can
509 request it from the kernel when needed.
509 request it from the kernel when needed.
510
510
511 Message type: ``history_request``::
511 Message type: ``history_request``::
512
512
513 content = {
513 content = {
514
514
515 # If True, also return output history in the resulting dict.
515 # If True, also return output history in the resulting dict.
516 'output' : bool,
516 'output' : bool,
517
517
518 # If True, return the raw input history, else the transformed input.
518 # If True, return the raw input history, else the transformed input.
519 'raw' : bool,
519 'raw' : bool,
520
520
521 # This parameter can be one of: A number, a pair of numbers, None
521 # This parameter can be one of: A number, a pair of numbers, None
522 # If not given, last 40 are returned.
522 # If not given, last 40 are returned.
523 # - number n: return the last n entries.
523 # - number n: return the last n entries.
524 # - pair n1, n2: return entries in the range(n1, n2).
524 # - pair n1, n2: return entries in the range(n1, n2).
525 # - None: return all history
525 # - None: return all history
526 'index' : n or (n1, n2) or None,
526 'index' : n or (n1, n2) or None,
527 }
527 }
528
528
529 Message type: ``history_reply``::
529 Message type: ``history_reply``::
530
530
531 content = {
531 content = {
532 # A dict with prompt numbers as keys and either (input, output) or input
532 # A dict with prompt numbers as keys and either (input, output) or input
533 # as the value depending on whether output was True or False,
533 # as the value depending on whether output was True or False,
534 # respectively.
534 # respectively.
535 'history' : dict,
535 'history' : dict,
536 }
536 }
537
537
538
538
539 Connect
540 -------
541
542 When a client connects to the request/reply socket of the kernel, it can issue
543 a connect request to get basic information about the kernel, such as the ports
544 the other ZeroMQ sockets are listening on. This allows clients to only have
545 to know about a single port (the XREQ/XREP channel) to connect to a kernel.
546
547 Message type: ``connect_request``::
548
549 content = {
550 }
551
552 Message type: ``connect_reply``::
553
554 content = {
555 'xrep_port' : int # The port the XREP socket is listening on.
556 'pub_port' : int # The port the PUB socket is listening on.
557 'req_port' : int # The port the REQ socket is listening on.
558 'hb_port' : int # The port the heartbeat socket is listening on.
559 }
560
561
562
539 Kernel shutdown
563 Kernel shutdown
540 ---------------
564 ---------------
541
565
542 The clients can request the kernel to shut itself down; this is used in
566 The clients can request the kernel to shut itself down; this is used in
543 multiple cases:
567 multiple cases:
544
568
545 - when the user chooses to close the client application via a menu or window
569 - when the user chooses to close the client application via a menu or window
546 control.
570 control.
547 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
571 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
548 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
572 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
549 IPythonQt client) to force a kernel restart to get a clean kernel without
573 IPythonQt client) to force a kernel restart to get a clean kernel without
550 losing client-side state like history or inlined figures.
574 losing client-side state like history or inlined figures.
551
575
552 The client sends a shutdown request to the kernel, and once it receives the
576 The client sends a shutdown request to the kernel, and once it receives the
553 reply message (which is otherwise empty), it can assume that the kernel has
577 reply message (which is otherwise empty), it can assume that the kernel has
554 completed shutdown safely.
578 completed shutdown safely.
555
579
556 Upon their own shutdown, client applications will typically execute a last
580 Upon their own shutdown, client applications will typically execute a last
557 minute sanity check and forcefully terminate any kernel that is still alive, to
581 minute sanity check and forcefully terminate any kernel that is still alive, to
558 avoid leaving stray processes in the user's machine.
582 avoid leaving stray processes in the user's machine.
559
583
560 For both shutdown request and reply, there is no actual content that needs to
584 For both shutdown request and reply, there is no actual content that needs to
561 be sent, so the content dict is empty.
585 be sent, so the content dict is empty.
562
586
563 Message type: ``shutdown_request``::
587 Message type: ``shutdown_request``::
564
588
565 content = {
589 content = {
566 }
590 }
567
591
568 Message type: ``shutdown_reply``::
592 Message type: ``shutdown_reply``::
569
593
570 content = {
594 content = {
571 }
595 }
572
596
573 .. Note::
597 .. Note::
574
598
575 When the clients detect a dead kernel thanks to inactivity on the heartbeat
599 When the clients detect a dead kernel thanks to inactivity on the heartbeat
576 socket, they simply send a forceful process termination signal, since a dead
600 socket, they simply send a forceful process termination signal, since a dead
577 process is unlikely to respond in any useful way to messages.
601 process is unlikely to respond in any useful way to messages.
578
602
579
603
580 Messages on the PUB/SUB socket
604 Messages on the PUB/SUB socket
581 ==============================
605 ==============================
582
606
583 Streams (stdout, stderr, etc)
607 Streams (stdout, stderr, etc)
584 ------------------------------
608 ------------------------------
585
609
586 Message type: ``stream``::
610 Message type: ``stream``::
587
611
588 content = {
612 content = {
589 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
613 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
590 'name' : str,
614 'name' : str,
591
615
592 # The data is an arbitrary string to be written to that stream
616 # The data is an arbitrary string to be written to that stream
593 'data' : str,
617 'data' : str,
594 }
618 }
595
619
596 When a kernel receives a raw_input call, it should also broadcast it on the pub
620 When a kernel receives a raw_input call, it should also broadcast it on the pub
597 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
621 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
598 to monitor/display kernel interactions and possibly replay them to their user
622 to monitor/display kernel interactions and possibly replay them to their user
599 or otherwise expose them.
623 or otherwise expose them.
600
624
601 Python inputs
625 Python inputs
602 -------------
626 -------------
603
627
604 These messages are the re-broadcast of the ``execute_request``.
628 These messages are the re-broadcast of the ``execute_request``.
605
629
606 Message type: ``pyin``::
630 Message type: ``pyin``::
607
631
608 content = {
632 content = {
609 # Source code to be executed, one or more lines
633 # Source code to be executed, one or more lines
610 'code' : str
634 'code' : str
611 }
635 }
612
636
613 Python outputs
637 Python outputs
614 --------------
638 --------------
615
639
616 When Python produces output from code that has been compiled in with the
640 When Python produces output from code that has been compiled in with the
617 'single' flag to :func:`compile`, any expression that produces a value (such as
641 'single' flag to :func:`compile`, any expression that produces a value (such as
618 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
642 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
619 this value whatever it wants. The default behavior of ``sys.displayhook`` in
643 this value whatever it wants. The default behavior of ``sys.displayhook`` in
620 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
644 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
621 the value as long as it is not ``None`` (which isn't printed at all). In our
645 the value as long as it is not ``None`` (which isn't printed at all). In our
622 case, the kernel instantiates as ``sys.displayhook`` an object which has
646 case, the kernel instantiates as ``sys.displayhook`` an object which has
623 similar behavior, but which instead of printing to stdout, broadcasts these
647 similar behavior, but which instead of printing to stdout, broadcasts these
624 values as ``pyout`` messages for clients to display appropriately.
648 values as ``pyout`` messages for clients to display appropriately.
625
649
626 Message type: ``pyout``::
650 Message type: ``pyout``::
627
651
628 content = {
652 content = {
629 # The data is typically the repr() of the object.
653 # The data is typically the repr() of the object.
630 'data' : str,
654 'data' : str,
631
655
632 # The counter for this execution is also provided so that clients can
656 # The counter for this execution is also provided so that clients can
633 # display it, since IPython automatically creates variables called _N (for
657 # display it, since IPython automatically creates variables called _N (for
634 # prompt N).
658 # prompt N).
635 'execution_count' : int,
659 'execution_count' : int,
636 }
660 }
637
661
638 Python errors
662 Python errors
639 -------------
663 -------------
640
664
641 When an error occurs during code execution
665 When an error occurs during code execution
642
666
643 Message type: ``pyerr``::
667 Message type: ``pyerr``::
644
668
645 content = {
669 content = {
646 # Similar content to the execute_reply messages for the 'error' case,
670 # Similar content to the execute_reply messages for the 'error' case,
647 # except the 'status' field is omitted.
671 # except the 'status' field is omitted.
648 }
672 }
649
673
650 Kernel crashes
674 Kernel crashes
651 --------------
675 --------------
652
676
653 When the kernel has an unexpected exception, caught by the last-resort
677 When the kernel has an unexpected exception, caught by the last-resort
654 sys.excepthook, we should broadcast the crash handler's output before exiting.
678 sys.excepthook, we should broadcast the crash handler's output before exiting.
655 This will allow clients to notice that a kernel died, inform the user and
679 This will allow clients to notice that a kernel died, inform the user and
656 propose further actions.
680 propose further actions.
657
681
658 Message type: ``crash``::
682 Message type: ``crash``::
659
683
660 content = {
684 content = {
661 # Similarly to the 'error' case for execute_reply messages, this will
685 # Similarly to the 'error' case for execute_reply messages, this will
662 # contain exc_name, exc_type and traceback fields.
686 # contain exc_name, exc_type and traceback fields.
663
687
664 # An additional field with supplementary information such as where to
688 # An additional field with supplementary information such as where to
665 # send the crash message
689 # send the crash message
666 'info' : str,
690 'info' : str,
667 }
691 }
668
692
669
693
670 Future ideas
694 Future ideas
671 ------------
695 ------------
672
696
673 Other potential message types, currently unimplemented, listed below as ideas.
697 Other potential message types, currently unimplemented, listed below as ideas.
674
698
675 Message type: ``file``::
699 Message type: ``file``::
676
700
677 content = {
701 content = {
678 'path' : 'cool.jpg',
702 'path' : 'cool.jpg',
679 'mimetype' : str,
703 'mimetype' : str,
680 'data' : str,
704 'data' : str,
681 }
705 }
682
706
683
707
684 Messages on the REQ/REP socket
708 Messages on the REQ/REP socket
685 ==============================
709 ==============================
686
710
687 This is a socket that goes in the opposite direction: from the kernel to a
711 This is a socket that goes in the opposite direction: from the kernel to a
688 *single* frontend, and its purpose is to allow ``raw_input`` and similar
712 *single* frontend, and its purpose is to allow ``raw_input`` and similar
689 operations that read from ``sys.stdin`` on the kernel to be fulfilled by the
713 operations that read from ``sys.stdin`` on the kernel to be fulfilled by the
690 client. For now we will keep these messages as simple as possible, since they
714 client. For now we will keep these messages as simple as possible, since they
691 basically only mean to convey the ``raw_input(prompt)`` call.
715 basically only mean to convey the ``raw_input(prompt)`` call.
692
716
693 Message type: ``input_request``::
717 Message type: ``input_request``::
694
718
695 content = { 'prompt' : str }
719 content = { 'prompt' : str }
696
720
697 Message type: ``input_reply``::
721 Message type: ``input_reply``::
698
722
699 content = { 'value' : str }
723 content = { 'value' : str }
700
724
701 .. Note::
725 .. Note::
702
726
703 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
727 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
704 practice the kernel should behave like an interactive program. When a
728 practice the kernel should behave like an interactive program. When a
705 program is opened on the console, the keyboard effectively takes over the
729 program is opened on the console, the keyboard effectively takes over the
706 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
730 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
707 Since the IPython kernel effectively behaves like a console program (albeit
731 Since the IPython kernel effectively behaves like a console program (albeit
708 one whose "keyboard" is actually living in a separate process and
732 one whose "keyboard" is actually living in a separate process and
709 transported over the zmq connection), raw ``stdin`` isn't expected to be
733 transported over the zmq connection), raw ``stdin`` isn't expected to be
710 available.
734 available.
711
735
712
736
713 Heartbeat for kernels
737 Heartbeat for kernels
714 =====================
738 =====================
715
739
716 Initially we had considered using messages like those above over ZMQ for a
740 Initially we had considered using messages like those above over ZMQ for a
717 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
741 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
718 alive at all, even if it may be busy executing user code). But this has the
742 alive at all, even if it may be busy executing user code). But this has the
719 problem that if the kernel is locked inside extension code, it wouldn't execute
743 problem that if the kernel is locked inside extension code, it wouldn't execute
720 the python heartbeat code. But it turns out that we can implement a basic
744 the python heartbeat code. But it turns out that we can implement a basic
721 heartbeat with pure ZMQ, without using any Python messaging at all.
745 heartbeat with pure ZMQ, without using any Python messaging at all.
722
746
723 The monitor sends out a single zmq message (right now, it is a str of the
747 The monitor sends out a single zmq message (right now, it is a str of the
724 monitor's lifetime in seconds), and gets the same message right back, prefixed
748 monitor's lifetime in seconds), and gets the same message right back, prefixed
725 with the zmq identity of the XREQ socket in the heartbeat process. This can be
749 with the zmq identity of the XREQ socket in the heartbeat process. This can be
726 a uuid, or even a full message, but there doesn't seem to be a need for packing
750 a uuid, or even a full message, but there doesn't seem to be a need for packing
727 up a message when the sender and receiver are the exact same Python object.
751 up a message when the sender and receiver are the exact same Python object.
728
752
729 The model is this::
753 The model is this::
730
754
731 monitor.send(str(self.lifetime)) # '1.2345678910'
755 monitor.send(str(self.lifetime)) # '1.2345678910'
732
756
733 and the monitor receives some number of messages of the form::
757 and the monitor receives some number of messages of the form::
734
758
735 ['uuid-abcd-dead-beef', '1.2345678910']
759 ['uuid-abcd-dead-beef', '1.2345678910']
736
760
737 where the first part is the zmq.IDENTITY of the heart's XREQ on the engine, and
761 where the first part is the zmq.IDENTITY of the heart's XREQ on the engine, and
738 the rest is the message sent by the monitor. No Python code ever has any
762 the rest is the message sent by the monitor. No Python code ever has any
739 access to the message between the monitor's send, and the monitor's recv.
763 access to the message between the monitor's send, and the monitor's recv.
740
764
741
765
742 ToDo
766 ToDo
743 ====
767 ====
744
768
745 Missing things include:
769 Missing things include:
746
770
747 * Important: finish thinking through the payload concept and API.
771 * Important: finish thinking through the payload concept and API.
748
772
749 * Important: ensure that we have a good solution for magics like %edit. It's
773 * Important: ensure that we have a good solution for magics like %edit. It's
750 likely that with the payload concept we can build a full solution, but not
774 likely that with the payload concept we can build a full solution, but not
751 100% clear yet.
775 100% clear yet.
752
776
753 * Finishing the details of the heartbeat protocol.
777 * Finishing the details of the heartbeat protocol.
754
778
755 * Signal handling: specify what kind of information kernel should broadcast (or
779 * Signal handling: specify what kind of information kernel should broadcast (or
756 not) when it receives signals.
780 not) when it receives signals.
757
781
758 .. include:: ../links.rst
782 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now