##// END OF EJS Templates
Merge pull request #7005 from minrk/payloads-3.0...
Thomas Kluyver -
r19052:e38dcec4 merge
parent child Browse files
Show More
@@ -1,49 +1,48 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A payload based version of page."""
2 """A payload based version of page."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from IPython.core.getipython import get_ipython
7 from IPython.core.getipython import get_ipython
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Classes and functions
10 # Classes and functions
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 def page(strng, start=0, screen_lines=0, pager_cmd=None):
13 def page(strng, start=0, screen_lines=0, pager_cmd=None):
14 """Print a string, piping through a pager.
14 """Print a string, piping through a pager.
15
15
16 This version ignores the screen_lines and pager_cmd arguments and uses
16 This version ignores the screen_lines and pager_cmd arguments and uses
17 IPython's payload system instead.
17 IPython's payload system instead.
18
18
19 Parameters
19 Parameters
20 ----------
20 ----------
21 strng : str or mime-dict
21 strng : str or mime-dict
22 Text to page, or a mime-type keyed dict of already formatted data.
22 Text to page, or a mime-type keyed dict of already formatted data.
23
23
24 start : int
24 start : int
25 Starting line at which to place the display.
25 Starting line at which to place the display.
26 """
26 """
27
27
28 # Some routines may auto-compute start offsets incorrectly and pass a
28 # Some routines may auto-compute start offsets incorrectly and pass a
29 # negative value. Offset to 0 for robustness.
29 # negative value. Offset to 0 for robustness.
30 start = max(0, start)
30 start = max(0, start)
31 shell = get_ipython()
31 shell = get_ipython()
32
32
33 if isinstance(strng, dict):
33 if isinstance(strng, dict):
34 data = strng
34 data = strng
35 else:
35 else:
36 data = {'text/plain' : strng}
36 data = {'text/plain' : strng}
37 payload = dict(
37 payload = dict(
38 source='page',
38 source='page',
39 data=data,
39 data=data,
40 start=start,
40 start=start,
41 screen_lines=screen_lines,
42 )
41 )
43 shell.payload_manager.write_payload(payload)
42 shell.payload_manager.write_payload(payload)
44
43
45
44
46 def install_payload_page():
45 def install_payload_page():
47 """Install this version of page as IPython.core.page.page."""
46 """Install this version of page as IPython.core.page.page."""
48 from IPython.core import page as corepage
47 from IPython.core import page as corepage
49 corepage.page = page
48 corepage.page = page
@@ -1,567 +1,487 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17 from __future__ import print_function
17 from __future__ import print_function
18
18
19 import os
19 import os
20 import sys
20 import sys
21 import time
21 import time
22
22
23 from zmq.eventloop import ioloop
23 from zmq.eventloop import ioloop
24
24
25 from IPython.core.interactiveshell import (
25 from IPython.core.interactiveshell import (
26 InteractiveShell, InteractiveShellABC
26 InteractiveShell, InteractiveShellABC
27 )
27 )
28 from IPython.core import page
28 from IPython.core import page
29 from IPython.core.autocall import ZMQExitAutocall
29 from IPython.core.autocall import ZMQExitAutocall
30 from IPython.core.displaypub import DisplayPublisher
30 from IPython.core.displaypub import DisplayPublisher
31 from IPython.core.error import UsageError
31 from IPython.core.error import UsageError
32 from IPython.core.magics import MacroToEdit, CodeMagics
32 from IPython.core.magics import MacroToEdit, CodeMagics
33 from IPython.core.magic import magics_class, line_magic, Magics
33 from IPython.core.magic import magics_class, line_magic, Magics
34 from IPython.core.payloadpage import install_payload_page
34 from IPython.core.payloadpage import install_payload_page
35 from IPython.core.usage import default_gui_banner
35 from IPython.core.usage import default_gui_banner
36 from IPython.display import display, Javascript
36 from IPython.display import display, Javascript
37 from IPython.kernel.inprocess.socket import SocketABC
37 from IPython.kernel.inprocess.socket import SocketABC
38 from IPython.kernel import (
38 from IPython.kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
39 get_connection_file, get_connection_info, connect_qtconsole
40 )
40 )
41 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import openpy
42 from IPython.utils import openpy
43 from IPython.utils.jsonutil import json_clean, encode_images
43 from IPython.utils.jsonutil import json_clean, encode_images
44 from IPython.utils.process import arg_split
44 from IPython.utils.process import arg_split
45 from IPython.utils import py3compat
45 from IPython.utils import py3compat
46 from IPython.utils.py3compat import unicode_type
46 from IPython.utils.py3compat import unicode_type
47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
48 from IPython.utils.warn import error
48 from IPython.utils.warn import error
49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
51 from IPython.kernel.zmq.session import extract_header
51 from IPython.kernel.zmq.session import extract_header
52 from .session import Session
52 from .session import Session
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Functions and classes
55 # Functions and classes
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 class ZMQDisplayPublisher(DisplayPublisher):
58 class ZMQDisplayPublisher(DisplayPublisher):
59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
60
60
61 session = Instance(Session)
61 session = Instance(Session)
62 pub_socket = Instance(SocketABC)
62 pub_socket = Instance(SocketABC)
63 parent_header = Dict({})
63 parent_header = Dict({})
64 topic = CBytes(b'display_data')
64 topic = CBytes(b'display_data')
65
65
66 def set_parent(self, parent):
66 def set_parent(self, parent):
67 """Set the parent for outbound messages."""
67 """Set the parent for outbound messages."""
68 self.parent_header = extract_header(parent)
68 self.parent_header = extract_header(parent)
69
69
70 def _flush_streams(self):
70 def _flush_streams(self):
71 """flush IO Streams prior to display"""
71 """flush IO Streams prior to display"""
72 sys.stdout.flush()
72 sys.stdout.flush()
73 sys.stderr.flush()
73 sys.stderr.flush()
74
74
75 def publish(self, data, metadata=None, source=None):
75 def publish(self, data, metadata=None, source=None):
76 self._flush_streams()
76 self._flush_streams()
77 if metadata is None:
77 if metadata is None:
78 metadata = {}
78 metadata = {}
79 self._validate_data(data, metadata)
79 self._validate_data(data, metadata)
80 content = {}
80 content = {}
81 content['data'] = encode_images(data)
81 content['data'] = encode_images(data)
82 content['metadata'] = metadata
82 content['metadata'] = metadata
83 self.session.send(
83 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
84 self.pub_socket, u'display_data', json_clean(content),
85 parent=self.parent_header, ident=self.topic,
85 parent=self.parent_header, ident=self.topic,
86 )
86 )
87
87
88 def clear_output(self, wait=False):
88 def clear_output(self, wait=False):
89 content = dict(wait=wait)
89 content = dict(wait=wait)
90 self._flush_streams()
90 self._flush_streams()
91 self.session.send(
91 self.session.send(
92 self.pub_socket, u'clear_output', content,
92 self.pub_socket, u'clear_output', content,
93 parent=self.parent_header, ident=self.topic,
93 parent=self.parent_header, ident=self.topic,
94 )
94 )
95
95
96 @magics_class
96 @magics_class
97 class KernelMagics(Magics):
97 class KernelMagics(Magics):
98 #------------------------------------------------------------------------
98 #------------------------------------------------------------------------
99 # Magic overrides
99 # Magic overrides
100 #------------------------------------------------------------------------
100 #------------------------------------------------------------------------
101 # Once the base class stops inheriting from magic, this code needs to be
101 # Once the base class stops inheriting from magic, this code needs to be
102 # moved into a separate machinery as well. For now, at least isolate here
102 # moved into a separate machinery as well. For now, at least isolate here
103 # the magics which this class needs to implement differently from the base
103 # the magics which this class needs to implement differently from the base
104 # class, or that are unique to it.
104 # class, or that are unique to it.
105
106 @line_magic
107 def doctest_mode(self, parameter_s=''):
108 """Toggle doctest mode on and off.
109
110 This mode is intended to make IPython behave as much as possible like a
111 plain Python shell, from the perspective of how its prompts, exceptions
112 and output look. This makes it easy to copy and paste parts of a
113 session into doctests. It does so by:
114
115 - Changing the prompts to the classic ``>>>`` ones.
116 - Changing the exception reporting mode to 'Plain'.
117 - Disabling pretty-printing of output.
118
119 Note that IPython also supports the pasting of code snippets that have
120 leading '>>>' and '...' prompts in them. This means that you can paste
121 doctests from files or docstrings (even if they have leading
122 whitespace), and the code will execute correctly. You can then use
123 '%history -t' to see the translated history; this will give you the
124 input after removal of all the leading prompts and whitespace, which
125 can be pasted back into an editor.
126
127 With these features, you can switch into this mode easily whenever you
128 need to do testing and changes to doctests, without having to leave
129 your existing IPython session.
130 """
131
132 from IPython.utils.ipstruct import Struct
133
134 # Shorthands
135 shell = self.shell
136 disp_formatter = self.shell.display_formatter
137 ptformatter = disp_formatter.formatters['text/plain']
138 # dstore is a data store kept in the instance metadata bag to track any
139 # changes we make, so we can undo them later.
140 dstore = shell.meta.setdefault('doctest_mode', Struct())
141 save_dstore = dstore.setdefault
142
143 # save a few values we'll need to recover later
144 mode = save_dstore('mode', False)
145 save_dstore('rc_pprint', ptformatter.pprint)
146 save_dstore('rc_active_types',disp_formatter.active_types)
147 save_dstore('xmode', shell.InteractiveTB.mode)
148
149 if mode == False:
150 # turn on
151 ptformatter.pprint = False
152 disp_formatter.active_types = ['text/plain']
153 shell.magic('xmode Plain')
154 else:
155 # turn off
156 ptformatter.pprint = dstore.rc_pprint
157 disp_formatter.active_types = dstore.rc_active_types
158 shell.magic("xmode " + dstore.xmode)
159
160 # Store new mode and inform on console
161 dstore.mode = bool(1-int(mode))
162 mode_label = ['OFF','ON'][dstore.mode]
163 print('Doctest mode is:', mode_label)
164
165 # Send the payload back so that clients can modify their prompt display
166 payload = dict(
167 source='doctest_mode',
168 mode=dstore.mode)
169 shell.payload_manager.write_payload(payload)
170
171
105
172 _find_edit_target = CodeMagics._find_edit_target
106 _find_edit_target = CodeMagics._find_edit_target
173
107
174 @skip_doctest
108 @skip_doctest
175 @line_magic
109 @line_magic
176 def edit(self, parameter_s='', last_call=['','']):
110 def edit(self, parameter_s='', last_call=['','']):
177 """Bring up an editor and execute the resulting code.
111 """Bring up an editor and execute the resulting code.
178
112
179 Usage:
113 Usage:
180 %edit [options] [args]
114 %edit [options] [args]
181
115
182 %edit runs an external text editor. You will need to set the command for
116 %edit runs an external text editor. You will need to set the command for
183 this editor via the ``TerminalInteractiveShell.editor`` option in your
117 this editor via the ``TerminalInteractiveShell.editor`` option in your
184 configuration file before it will work.
118 configuration file before it will work.
185
119
186 This command allows you to conveniently edit multi-line code right in
120 This command allows you to conveniently edit multi-line code right in
187 your IPython session.
121 your IPython session.
188
122
189 If called without arguments, %edit opens up an empty editor with a
123 If called without arguments, %edit opens up an empty editor with a
190 temporary file and will execute the contents of this file when you
124 temporary file and will execute the contents of this file when you
191 close it (don't forget to save it!).
125 close it (don't forget to save it!).
192
126
193 Options:
127 Options:
194
128
195 -n <number>
129 -n <number>
196 Open the editor at a specified line number. By default, the IPython
130 Open the editor at a specified line number. By default, the IPython
197 editor hook uses the unix syntax 'editor +N filename', but you can
131 editor hook uses the unix syntax 'editor +N filename', but you can
198 configure this by providing your own modified hook if your favorite
132 configure this by providing your own modified hook if your favorite
199 editor supports line-number specifications with a different syntax.
133 editor supports line-number specifications with a different syntax.
200
134
201 -p
135 -p
202 Call the editor with the same data as the previous time it was used,
136 Call the editor with the same data as the previous time it was used,
203 regardless of how long ago (in your current session) it was.
137 regardless of how long ago (in your current session) it was.
204
138
205 -r
139 -r
206 Use 'raw' input. This option only applies to input taken from the
140 Use 'raw' input. This option only applies to input taken from the
207 user's history. By default, the 'processed' history is used, so that
141 user's history. By default, the 'processed' history is used, so that
208 magics are loaded in their transformed version to valid Python. If
142 magics are loaded in their transformed version to valid Python. If
209 this option is given, the raw input as typed as the command line is
143 this option is given, the raw input as typed as the command line is
210 used instead. When you exit the editor, it will be executed by
144 used instead. When you exit the editor, it will be executed by
211 IPython's own processor.
145 IPython's own processor.
212
146
213 Arguments:
147 Arguments:
214
148
215 If arguments are given, the following possibilites exist:
149 If arguments are given, the following possibilites exist:
216
150
217 - The arguments are numbers or pairs of colon-separated numbers (like
151 - The arguments are numbers or pairs of colon-separated numbers (like
218 1 4:8 9). These are interpreted as lines of previous input to be
152 1 4:8 9). These are interpreted as lines of previous input to be
219 loaded into the editor. The syntax is the same of the %macro command.
153 loaded into the editor. The syntax is the same of the %macro command.
220
154
221 - If the argument doesn't start with a number, it is evaluated as a
155 - If the argument doesn't start with a number, it is evaluated as a
222 variable and its contents loaded into the editor. You can thus edit
156 variable and its contents loaded into the editor. You can thus edit
223 any string which contains python code (including the result of
157 any string which contains python code (including the result of
224 previous edits).
158 previous edits).
225
159
226 - If the argument is the name of an object (other than a string),
160 - If the argument is the name of an object (other than a string),
227 IPython will try to locate the file where it was defined and open the
161 IPython will try to locate the file where it was defined and open the
228 editor at the point where it is defined. You can use ``%edit function``
162 editor at the point where it is defined. You can use ``%edit function``
229 to load an editor exactly at the point where 'function' is defined,
163 to load an editor exactly at the point where 'function' is defined,
230 edit it and have the file be executed automatically.
164 edit it and have the file be executed automatically.
231
165
232 If the object is a macro (see %macro for details), this opens up your
166 If the object is a macro (see %macro for details), this opens up your
233 specified editor with a temporary file containing the macro's data.
167 specified editor with a temporary file containing the macro's data.
234 Upon exit, the macro is reloaded with the contents of the file.
168 Upon exit, the macro is reloaded with the contents of the file.
235
169
236 Note: opening at an exact line is only supported under Unix, and some
170 Note: opening at an exact line is only supported under Unix, and some
237 editors (like kedit and gedit up to Gnome 2.8) do not understand the
171 editors (like kedit and gedit up to Gnome 2.8) do not understand the
238 '+NUMBER' parameter necessary for this feature. Good editors like
172 '+NUMBER' parameter necessary for this feature. Good editors like
239 (X)Emacs, vi, jed, pico and joe all do.
173 (X)Emacs, vi, jed, pico and joe all do.
240
174
241 - If the argument is not found as a variable, IPython will look for a
175 - If the argument is not found as a variable, IPython will look for a
242 file with that name (adding .py if necessary) and load it into the
176 file with that name (adding .py if necessary) and load it into the
243 editor. It will execute its contents with execfile() when you exit,
177 editor. It will execute its contents with execfile() when you exit,
244 loading any code in the file into your interactive namespace.
178 loading any code in the file into your interactive namespace.
245
179
246 Unlike in the terminal, this is designed to use a GUI editor, and we do
180 Unlike in the terminal, this is designed to use a GUI editor, and we do
247 not know when it has closed. So the file you edit will not be
181 not know when it has closed. So the file you edit will not be
248 automatically executed or printed.
182 automatically executed or printed.
249
183
250 Note that %edit is also available through the alias %ed.
184 Note that %edit is also available through the alias %ed.
251 """
185 """
252
186
253 opts,args = self.parse_options(parameter_s,'prn:')
187 opts,args = self.parse_options(parameter_s,'prn:')
254
188
255 try:
189 try:
256 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
190 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
257 except MacroToEdit as e:
191 except MacroToEdit as e:
258 # TODO: Implement macro editing over 2 processes.
192 # TODO: Implement macro editing over 2 processes.
259 print("Macro editing not yet implemented in 2-process model.")
193 print("Macro editing not yet implemented in 2-process model.")
260 return
194 return
261
195
262 # Make sure we send to the client an absolute path, in case the working
196 # Make sure we send to the client an absolute path, in case the working
263 # directory of client and kernel don't match
197 # directory of client and kernel don't match
264 filename = os.path.abspath(filename)
198 filename = os.path.abspath(filename)
265
199
266 payload = {
200 payload = {
267 'source' : 'edit_magic',
201 'source' : 'edit_magic',
268 'filename' : filename,
202 'filename' : filename,
269 'line_number' : lineno
203 'line_number' : lineno
270 }
204 }
271 self.shell.payload_manager.write_payload(payload)
205 self.shell.payload_manager.write_payload(payload)
272
206
273 # A few magics that are adapted to the specifics of using pexpect and a
207 # A few magics that are adapted to the specifics of using pexpect and a
274 # remote terminal
208 # remote terminal
275
209
276 @line_magic
210 @line_magic
277 def clear(self, arg_s):
211 def clear(self, arg_s):
278 """Clear the terminal."""
212 """Clear the terminal."""
279 if os.name == 'posix':
213 if os.name == 'posix':
280 self.shell.system("clear")
214 self.shell.system("clear")
281 else:
215 else:
282 self.shell.system("cls")
216 self.shell.system("cls")
283
217
284 if os.name == 'nt':
218 if os.name == 'nt':
285 # This is the usual name in windows
219 # This is the usual name in windows
286 cls = line_magic('cls')(clear)
220 cls = line_magic('cls')(clear)
287
221
288 # Terminal pagers won't work over pexpect, but we do have our own pager
222 # Terminal pagers won't work over pexpect, but we do have our own pager
289
223
290 @line_magic
224 @line_magic
291 def less(self, arg_s):
225 def less(self, arg_s):
292 """Show a file through the pager.
226 """Show a file through the pager.
293
227
294 Files ending in .py are syntax-highlighted."""
228 Files ending in .py are syntax-highlighted."""
295 if not arg_s:
229 if not arg_s:
296 raise UsageError('Missing filename.')
230 raise UsageError('Missing filename.')
297
231
298 cont = open(arg_s).read()
232 cont = open(arg_s).read()
299 if arg_s.endswith('.py'):
233 if arg_s.endswith('.py'):
300 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
234 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
301 else:
235 else:
302 cont = open(arg_s).read()
236 cont = open(arg_s).read()
303 page.page(cont)
237 page.page(cont)
304
238
305 more = line_magic('more')(less)
239 more = line_magic('more')(less)
306
240
307 # Man calls a pager, so we also need to redefine it
241 # Man calls a pager, so we also need to redefine it
308 if os.name == 'posix':
242 if os.name == 'posix':
309 @line_magic
243 @line_magic
310 def man(self, arg_s):
244 def man(self, arg_s):
311 """Find the man page for the given command and display in pager."""
245 """Find the man page for the given command and display in pager."""
312 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
246 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
313 split=False))
247 split=False))
314
248
315 @line_magic
249 @line_magic
316 def connect_info(self, arg_s):
250 def connect_info(self, arg_s):
317 """Print information for connecting other clients to this kernel
251 """Print information for connecting other clients to this kernel
318
252
319 It will print the contents of this session's connection file, as well as
253 It will print the contents of this session's connection file, as well as
320 shortcuts for local clients.
254 shortcuts for local clients.
321
255
322 In the simplest case, when called from the most recently launched kernel,
256 In the simplest case, when called from the most recently launched kernel,
323 secondary clients can be connected, simply with:
257 secondary clients can be connected, simply with:
324
258
325 $> ipython <app> --existing
259 $> ipython <app> --existing
326
260
327 """
261 """
328
262
329 from IPython.core.application import BaseIPythonApplication as BaseIPApp
263 from IPython.core.application import BaseIPythonApplication as BaseIPApp
330
264
331 if BaseIPApp.initialized():
265 if BaseIPApp.initialized():
332 app = BaseIPApp.instance()
266 app = BaseIPApp.instance()
333 security_dir = app.profile_dir.security_dir
267 security_dir = app.profile_dir.security_dir
334 profile = app.profile
268 profile = app.profile
335 else:
269 else:
336 profile = 'default'
270 profile = 'default'
337 security_dir = ''
271 security_dir = ''
338
272
339 try:
273 try:
340 connection_file = get_connection_file()
274 connection_file = get_connection_file()
341 info = get_connection_info(unpack=False)
275 info = get_connection_info(unpack=False)
342 except Exception as e:
276 except Exception as e:
343 error("Could not get connection info: %r" % e)
277 error("Could not get connection info: %r" % e)
344 return
278 return
345
279
346 # add profile flag for non-default profile
280 # add profile flag for non-default profile
347 profile_flag = "--profile %s" % profile if profile != 'default' else ""
281 profile_flag = "--profile %s" % profile if profile != 'default' else ""
348
282
349 # if it's in the security dir, truncate to basename
283 # if it's in the security dir, truncate to basename
350 if security_dir == os.path.dirname(connection_file):
284 if security_dir == os.path.dirname(connection_file):
351 connection_file = os.path.basename(connection_file)
285 connection_file = os.path.basename(connection_file)
352
286
353
287
354 print (info + '\n')
288 print (info + '\n')
355 print ("Paste the above JSON into a file, and connect with:\n"
289 print ("Paste the above JSON into a file, and connect with:\n"
356 " $> ipython <app> --existing <file>\n"
290 " $> ipython <app> --existing <file>\n"
357 "or, if you are local, you can connect with just:\n"
291 "or, if you are local, you can connect with just:\n"
358 " $> ipython <app> --existing {0} {1}\n"
292 " $> ipython <app> --existing {0} {1}\n"
359 "or even just:\n"
293 "or even just:\n"
360 " $> ipython <app> --existing {1}\n"
294 " $> ipython <app> --existing {1}\n"
361 "if this is the most recent IPython session you have started.".format(
295 "if this is the most recent IPython session you have started.".format(
362 connection_file, profile_flag
296 connection_file, profile_flag
363 )
297 )
364 )
298 )
365
299
366 @line_magic
300 @line_magic
367 def qtconsole(self, arg_s):
301 def qtconsole(self, arg_s):
368 """Open a qtconsole connected to this kernel.
302 """Open a qtconsole connected to this kernel.
369
303
370 Useful for connecting a qtconsole to running notebooks, for better
304 Useful for connecting a qtconsole to running notebooks, for better
371 debugging.
305 debugging.
372 """
306 """
373
307
374 # %qtconsole should imply bind_kernel for engines:
308 # %qtconsole should imply bind_kernel for engines:
375 try:
309 try:
376 from IPython.parallel import bind_kernel
310 from IPython.parallel import bind_kernel
377 except ImportError:
311 except ImportError:
378 # technically possible, because parallel has higher pyzmq min-version
312 # technically possible, because parallel has higher pyzmq min-version
379 pass
313 pass
380 else:
314 else:
381 bind_kernel()
315 bind_kernel()
382
316
383 try:
317 try:
384 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
318 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
385 except Exception as e:
319 except Exception as e:
386 error("Could not start qtconsole: %r" % e)
320 error("Could not start qtconsole: %r" % e)
387 return
321 return
388
322
389 @line_magic
323 @line_magic
390 def autosave(self, arg_s):
324 def autosave(self, arg_s):
391 """Set the autosave interval in the notebook (in seconds).
325 """Set the autosave interval in the notebook (in seconds).
392
326
393 The default value is 120, or two minutes.
327 The default value is 120, or two minutes.
394 ``%autosave 0`` will disable autosave.
328 ``%autosave 0`` will disable autosave.
395
329
396 This magic only has an effect when called from the notebook interface.
330 This magic only has an effect when called from the notebook interface.
397 It has no effect when called in a startup file.
331 It has no effect when called in a startup file.
398 """
332 """
399
333
400 try:
334 try:
401 interval = int(arg_s)
335 interval = int(arg_s)
402 except ValueError:
336 except ValueError:
403 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
337 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
404
338
405 # javascript wants milliseconds
339 # javascript wants milliseconds
406 milliseconds = 1000 * interval
340 milliseconds = 1000 * interval
407 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
341 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
408 include=['application/javascript']
342 include=['application/javascript']
409 )
343 )
410 if interval:
344 if interval:
411 print("Autosaving every %i seconds" % interval)
345 print("Autosaving every %i seconds" % interval)
412 else:
346 else:
413 print("Autosave disabled")
347 print("Autosave disabled")
414
348
415
349
416 class ZMQInteractiveShell(InteractiveShell):
350 class ZMQInteractiveShell(InteractiveShell):
417 """A subclass of InteractiveShell for ZMQ."""
351 """A subclass of InteractiveShell for ZMQ."""
418
352
419 displayhook_class = Type(ZMQShellDisplayHook)
353 displayhook_class = Type(ZMQShellDisplayHook)
420 display_pub_class = Type(ZMQDisplayPublisher)
354 display_pub_class = Type(ZMQDisplayPublisher)
421 data_pub_class = Type(ZMQDataPublisher)
355 data_pub_class = Type(ZMQDataPublisher)
422 kernel = Any()
356 kernel = Any()
423 parent_header = Any()
357 parent_header = Any()
424
358
425 def _banner1_default(self):
359 def _banner1_default(self):
426 return default_gui_banner
360 return default_gui_banner
427
361
428 # Override the traitlet in the parent class, because there's no point using
362 # Override the traitlet in the parent class, because there's no point using
429 # readline for the kernel. Can be removed when the readline code is moved
363 # readline for the kernel. Can be removed when the readline code is moved
430 # to the terminal frontend.
364 # to the terminal frontend.
431 colors_force = CBool(True)
365 colors_force = CBool(True)
432 readline_use = CBool(False)
366 readline_use = CBool(False)
433 # autoindent has no meaning in a zmqshell, and attempting to enable it
367 # autoindent has no meaning in a zmqshell, and attempting to enable it
434 # will print a warning in the absence of readline.
368 # will print a warning in the absence of readline.
435 autoindent = CBool(False)
369 autoindent = CBool(False)
436
370
437 exiter = Instance(ZMQExitAutocall)
371 exiter = Instance(ZMQExitAutocall)
438 def _exiter_default(self):
372 def _exiter_default(self):
439 return ZMQExitAutocall(self)
373 return ZMQExitAutocall(self)
440
374
441 def _exit_now_changed(self, name, old, new):
375 def _exit_now_changed(self, name, old, new):
442 """stop eventloop when exit_now fires"""
376 """stop eventloop when exit_now fires"""
443 if new:
377 if new:
444 loop = ioloop.IOLoop.instance()
378 loop = ioloop.IOLoop.instance()
445 loop.add_timeout(time.time()+0.1, loop.stop)
379 loop.add_timeout(time.time()+0.1, loop.stop)
446
380
447 keepkernel_on_exit = None
381 keepkernel_on_exit = None
448
382
449 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
383 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
450 # interactive input being read; we provide event loop support in ipkernel
384 # interactive input being read; we provide event loop support in ipkernel
451 @staticmethod
385 @staticmethod
452 def enable_gui(gui):
386 def enable_gui(gui):
453 from .eventloops import enable_gui as real_enable_gui
387 from .eventloops import enable_gui as real_enable_gui
454 try:
388 try:
455 real_enable_gui(gui)
389 real_enable_gui(gui)
456 except ValueError as e:
390 except ValueError as e:
457 raise UsageError("%s" % e)
391 raise UsageError("%s" % e)
458
392
459 def init_environment(self):
393 def init_environment(self):
460 """Configure the user's environment.
394 """Configure the user's environment.
461
395
462 """
396 """
463 env = os.environ
397 env = os.environ
464 # These two ensure 'ls' produces nice coloring on BSD-derived systems
398 # These two ensure 'ls' produces nice coloring on BSD-derived systems
465 env['TERM'] = 'xterm-color'
399 env['TERM'] = 'xterm-color'
466 env['CLICOLOR'] = '1'
400 env['CLICOLOR'] = '1'
467 # Since normal pagers don't work at all (over pexpect we don't have
401 # Since normal pagers don't work at all (over pexpect we don't have
468 # single-key control of the subprocess), try to disable paging in
402 # single-key control of the subprocess), try to disable paging in
469 # subprocesses as much as possible.
403 # subprocesses as much as possible.
470 env['PAGER'] = 'cat'
404 env['PAGER'] = 'cat'
471 env['GIT_PAGER'] = 'cat'
405 env['GIT_PAGER'] = 'cat'
472
406
473 # And install the payload version of page.
407 # And install the payload version of page.
474 install_payload_page()
408 install_payload_page()
475
409
476 def auto_rewrite_input(self, cmd):
477 """Called to show the auto-rewritten input for autocall and friends.
478
479 FIXME: this payload is currently not correctly processed by the
480 frontend.
481 """
482 new = self.prompt_manager.render('rewrite') + cmd
483 payload = dict(
484 source='auto_rewrite_input',
485 transformed_input=new,
486 )
487 self.payload_manager.write_payload(payload)
488
489 def ask_exit(self):
410 def ask_exit(self):
490 """Engage the exit actions."""
411 """Engage the exit actions."""
491 self.exit_now = (not self.keepkernel_on_exit)
412 self.exit_now = (not self.keepkernel_on_exit)
492 payload = dict(
413 payload = dict(
493 source='ask_exit',
414 source='ask_exit',
494 exit=True,
495 keepkernel=self.keepkernel_on_exit,
415 keepkernel=self.keepkernel_on_exit,
496 )
416 )
497 self.payload_manager.write_payload(payload)
417 self.payload_manager.write_payload(payload)
498
418
499 def _showtraceback(self, etype, evalue, stb):
419 def _showtraceback(self, etype, evalue, stb):
500 # try to preserve ordering of tracebacks and print statements
420 # try to preserve ordering of tracebacks and print statements
501 sys.stdout.flush()
421 sys.stdout.flush()
502 sys.stderr.flush()
422 sys.stderr.flush()
503
423
504 exc_content = {
424 exc_content = {
505 u'traceback' : stb,
425 u'traceback' : stb,
506 u'ename' : unicode_type(etype.__name__),
426 u'ename' : unicode_type(etype.__name__),
507 u'evalue' : py3compat.safe_unicode(evalue),
427 u'evalue' : py3compat.safe_unicode(evalue),
508 }
428 }
509
429
510 dh = self.displayhook
430 dh = self.displayhook
511 # Send exception info over pub socket for other clients than the caller
431 # Send exception info over pub socket for other clients than the caller
512 # to pick up
432 # to pick up
513 topic = None
433 topic = None
514 if dh.topic:
434 if dh.topic:
515 topic = dh.topic.replace(b'execute_result', b'error')
435 topic = dh.topic.replace(b'execute_result', b'error')
516
436
517 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
437 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
518
438
519 # FIXME - Hack: store exception info in shell object. Right now, the
439 # FIXME - Hack: store exception info in shell object. Right now, the
520 # caller is reading this info after the fact, we need to fix this logic
440 # caller is reading this info after the fact, we need to fix this logic
521 # to remove this hack. Even uglier, we need to store the error status
441 # to remove this hack. Even uglier, we need to store the error status
522 # here, because in the main loop, the logic that sets it is being
442 # here, because in the main loop, the logic that sets it is being
523 # skipped because runlines swallows the exceptions.
443 # skipped because runlines swallows the exceptions.
524 exc_content[u'status'] = u'error'
444 exc_content[u'status'] = u'error'
525 self._reply_content = exc_content
445 self._reply_content = exc_content
526 # /FIXME
446 # /FIXME
527
447
528 return exc_content
448 return exc_content
529
449
530 def set_next_input(self, text):
450 def set_next_input(self, text):
531 """Send the specified text to the frontend to be presented at the next
451 """Send the specified text to the frontend to be presented at the next
532 input cell."""
452 input cell."""
533 payload = dict(
453 payload = dict(
534 source='set_next_input',
454 source='set_next_input',
535 text=text
455 text=text
536 )
456 )
537 self.payload_manager.write_payload(payload)
457 self.payload_manager.write_payload(payload)
538
458
539 def set_parent(self, parent):
459 def set_parent(self, parent):
540 """Set the parent header for associating output with its triggering input"""
460 """Set the parent header for associating output with its triggering input"""
541 self.parent_header = parent
461 self.parent_header = parent
542 self.displayhook.set_parent(parent)
462 self.displayhook.set_parent(parent)
543 self.display_pub.set_parent(parent)
463 self.display_pub.set_parent(parent)
544 self.data_pub.set_parent(parent)
464 self.data_pub.set_parent(parent)
545 try:
465 try:
546 sys.stdout.set_parent(parent)
466 sys.stdout.set_parent(parent)
547 except AttributeError:
467 except AttributeError:
548 pass
468 pass
549 try:
469 try:
550 sys.stderr.set_parent(parent)
470 sys.stderr.set_parent(parent)
551 except AttributeError:
471 except AttributeError:
552 pass
472 pass
553
473
554 def get_parent(self):
474 def get_parent(self):
555 return self.parent_header
475 return self.parent_header
556
476
557 #-------------------------------------------------------------------------
477 #-------------------------------------------------------------------------
558 # Things related to magics
478 # Things related to magics
559 #-------------------------------------------------------------------------
479 #-------------------------------------------------------------------------
560
480
561 def init_magics(self):
481 def init_magics(self):
562 super(ZMQInteractiveShell, self).init_magics()
482 super(ZMQInteractiveShell, self).init_magics()
563 self.register_magics(KernelMagics)
483 self.register_magics(KernelMagics)
564 self.magics_manager.register_alias('ed', 'edit')
484 self.magics_manager.register_alias('ed', 'edit')
565
485
566
486
567 InteractiveShellABC.register(ZMQInteractiveShell)
487 InteractiveShellABC.register(ZMQInteractiveShell)
@@ -1,599 +1,599 b''
1 """A FrontendWidget that emulates the interface of the console IPython.
1 """A FrontendWidget that emulates the interface of the console IPython.
2
2
3 This supports the additional functionality provided by the IPython kernel.
3 This supports the additional functionality provided by the IPython kernel.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 from collections import namedtuple
9 from collections import namedtuple
10 import os.path
10 import os.path
11 import re
11 import re
12 from subprocess import Popen
12 from subprocess import Popen
13 import sys
13 import sys
14 import time
14 import time
15 from textwrap import dedent
15 from textwrap import dedent
16
16
17 from IPython.external.qt import QtCore, QtGui
17 from IPython.external.qt import QtCore, QtGui
18
18
19 from IPython.core.inputsplitter import IPythonInputSplitter
19 from IPython.core.inputsplitter import IPythonInputSplitter
20 from IPython.core.release import version
20 from IPython.core.release import version
21 from IPython.core.inputtransformer import ipy_prompt
21 from IPython.core.inputtransformer import ipy_prompt
22 from IPython.utils.traitlets import Bool, Unicode
22 from IPython.utils.traitlets import Bool, Unicode
23 from .frontend_widget import FrontendWidget
23 from .frontend_widget import FrontendWidget
24 from . import styles
24 from . import styles
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Constants
27 # Constants
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # Default strings to build and display input and output prompts (and separators
30 # Default strings to build and display input and output prompts (and separators
31 # in between)
31 # in between)
32 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
32 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
33 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
33 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
34 default_input_sep = '\n'
34 default_input_sep = '\n'
35 default_output_sep = ''
35 default_output_sep = ''
36 default_output_sep2 = ''
36 default_output_sep2 = ''
37
37
38 # Base path for most payload sources.
38 # Base path for most payload sources.
39 zmq_shell_source = 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell'
39 zmq_shell_source = 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell'
40
40
41 if sys.platform.startswith('win'):
41 if sys.platform.startswith('win'):
42 default_editor = 'notepad'
42 default_editor = 'notepad'
43 else:
43 else:
44 default_editor = ''
44 default_editor = ''
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # IPythonWidget class
47 # IPythonWidget class
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 class IPythonWidget(FrontendWidget):
50 class IPythonWidget(FrontendWidget):
51 """ A FrontendWidget for an IPython kernel.
51 """ A FrontendWidget for an IPython kernel.
52 """
52 """
53
53
54 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
54 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
55 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
55 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
56 # settings.
56 # settings.
57 custom_edit = Bool(False)
57 custom_edit = Bool(False)
58 custom_edit_requested = QtCore.Signal(object, object)
58 custom_edit_requested = QtCore.Signal(object, object)
59
59
60 editor = Unicode(default_editor, config=True,
60 editor = Unicode(default_editor, config=True,
61 help="""
61 help="""
62 A command for invoking a system text editor. If the string contains a
62 A command for invoking a system text editor. If the string contains a
63 {filename} format specifier, it will be used. Otherwise, the filename
63 {filename} format specifier, it will be used. Otherwise, the filename
64 will be appended to the end the command.
64 will be appended to the end the command.
65 """)
65 """)
66
66
67 editor_line = Unicode(config=True,
67 editor_line = Unicode(config=True,
68 help="""
68 help="""
69 The editor command to use when a specific line number is requested. The
69 The editor command to use when a specific line number is requested. The
70 string should contain two format specifiers: {line} and {filename}. If
70 string should contain two format specifiers: {line} and {filename}. If
71 this parameter is not specified, the line number option to the %edit
71 this parameter is not specified, the line number option to the %edit
72 magic will be ignored.
72 magic will be ignored.
73 """)
73 """)
74
74
75 style_sheet = Unicode(config=True,
75 style_sheet = Unicode(config=True,
76 help="""
76 help="""
77 A CSS stylesheet. The stylesheet can contain classes for:
77 A CSS stylesheet. The stylesheet can contain classes for:
78 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
78 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
79 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
79 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
80 3. IPython: .error, .in-prompt, .out-prompt, etc
80 3. IPython: .error, .in-prompt, .out-prompt, etc
81 """)
81 """)
82
82
83 syntax_style = Unicode(config=True,
83 syntax_style = Unicode(config=True,
84 help="""
84 help="""
85 If not empty, use this Pygments style for syntax highlighting.
85 If not empty, use this Pygments style for syntax highlighting.
86 Otherwise, the style sheet is queried for Pygments style
86 Otherwise, the style sheet is queried for Pygments style
87 information.
87 information.
88 """)
88 """)
89
89
90 # Prompts.
90 # Prompts.
91 in_prompt = Unicode(default_in_prompt, config=True)
91 in_prompt = Unicode(default_in_prompt, config=True)
92 out_prompt = Unicode(default_out_prompt, config=True)
92 out_prompt = Unicode(default_out_prompt, config=True)
93 input_sep = Unicode(default_input_sep, config=True)
93 input_sep = Unicode(default_input_sep, config=True)
94 output_sep = Unicode(default_output_sep, config=True)
94 output_sep = Unicode(default_output_sep, config=True)
95 output_sep2 = Unicode(default_output_sep2, config=True)
95 output_sep2 = Unicode(default_output_sep2, config=True)
96
96
97 # FrontendWidget protected class variables.
97 # FrontendWidget protected class variables.
98 _input_splitter_class = IPythonInputSplitter
98 _input_splitter_class = IPythonInputSplitter
99 _prompt_transformer = IPythonInputSplitter(physical_line_transforms=[ipy_prompt()],
99 _prompt_transformer = IPythonInputSplitter(physical_line_transforms=[ipy_prompt()],
100 logical_line_transforms=[],
100 logical_line_transforms=[],
101 python_line_transforms=[],
101 python_line_transforms=[],
102 )
102 )
103
103
104 # IPythonWidget protected class variables.
104 # IPythonWidget protected class variables.
105 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
105 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
106 _payload_source_edit = 'edit_magic'
106 _payload_source_edit = 'edit'
107 _payload_source_exit = 'ask_exit'
107 _payload_source_exit = 'ask_exit'
108 _payload_source_next_input = 'set_next_input'
108 _payload_source_next_input = 'set_next_input'
109 _payload_source_page = 'page'
109 _payload_source_page = 'page'
110 _retrying_history_request = False
110 _retrying_history_request = False
111 _starting = False
111 _starting = False
112
112
113 #---------------------------------------------------------------------------
113 #---------------------------------------------------------------------------
114 # 'object' interface
114 # 'object' interface
115 #---------------------------------------------------------------------------
115 #---------------------------------------------------------------------------
116
116
117 def __init__(self, *args, **kw):
117 def __init__(self, *args, **kw):
118 super(IPythonWidget, self).__init__(*args, **kw)
118 super(IPythonWidget, self).__init__(*args, **kw)
119
119
120 # IPythonWidget protected variables.
120 # IPythonWidget protected variables.
121 self._payload_handlers = {
121 self._payload_handlers = {
122 self._payload_source_edit : self._handle_payload_edit,
122 self._payload_source_edit : self._handle_payload_edit,
123 self._payload_source_exit : self._handle_payload_exit,
123 self._payload_source_exit : self._handle_payload_exit,
124 self._payload_source_page : self._handle_payload_page,
124 self._payload_source_page : self._handle_payload_page,
125 self._payload_source_next_input : self._handle_payload_next_input }
125 self._payload_source_next_input : self._handle_payload_next_input }
126 self._previous_prompt_obj = None
126 self._previous_prompt_obj = None
127 self._keep_kernel_on_exit = None
127 self._keep_kernel_on_exit = None
128
128
129 # Initialize widget styling.
129 # Initialize widget styling.
130 if self.style_sheet:
130 if self.style_sheet:
131 self._style_sheet_changed()
131 self._style_sheet_changed()
132 self._syntax_style_changed()
132 self._syntax_style_changed()
133 else:
133 else:
134 self.set_default_style()
134 self.set_default_style()
135
135
136 self._guiref_loaded = False
136 self._guiref_loaded = False
137
137
138 #---------------------------------------------------------------------------
138 #---------------------------------------------------------------------------
139 # 'BaseFrontendMixin' abstract interface
139 # 'BaseFrontendMixin' abstract interface
140 #---------------------------------------------------------------------------
140 #---------------------------------------------------------------------------
141 def _handle_complete_reply(self, rep):
141 def _handle_complete_reply(self, rep):
142 """ Reimplemented to support IPython's improved completion machinery.
142 """ Reimplemented to support IPython's improved completion machinery.
143 """
143 """
144 self.log.debug("complete: %s", rep.get('content', ''))
144 self.log.debug("complete: %s", rep.get('content', ''))
145 cursor = self._get_cursor()
145 cursor = self._get_cursor()
146 info = self._request_info.get('complete')
146 info = self._request_info.get('complete')
147 if info and info.id == rep['parent_header']['msg_id'] and \
147 if info and info.id == rep['parent_header']['msg_id'] and \
148 info.pos == cursor.position():
148 info.pos == cursor.position():
149 content = rep['content']
149 content = rep['content']
150 matches = content['matches']
150 matches = content['matches']
151 start = content['cursor_start']
151 start = content['cursor_start']
152 end = content['cursor_end']
152 end = content['cursor_end']
153
153
154 start = max(start, 0)
154 start = max(start, 0)
155 end = max(end, start)
155 end = max(end, start)
156
156
157 # Move the control's cursor to the desired end point
157 # Move the control's cursor to the desired end point
158 cursor_pos = self._get_input_buffer_cursor_pos()
158 cursor_pos = self._get_input_buffer_cursor_pos()
159 if end < cursor_pos:
159 if end < cursor_pos:
160 cursor.movePosition(QtGui.QTextCursor.Left,
160 cursor.movePosition(QtGui.QTextCursor.Left,
161 n=(cursor_pos - end))
161 n=(cursor_pos - end))
162 elif end > cursor_pos:
162 elif end > cursor_pos:
163 cursor.movePosition(QtGui.QTextCursor.Right,
163 cursor.movePosition(QtGui.QTextCursor.Right,
164 n=(end - cursor_pos))
164 n=(end - cursor_pos))
165 # This line actually applies the move to control's cursor
165 # This line actually applies the move to control's cursor
166 self._control.setTextCursor(cursor)
166 self._control.setTextCursor(cursor)
167
167
168 offset = end - start
168 offset = end - start
169 # Move the local cursor object to the start of the match and
169 # Move the local cursor object to the start of the match and
170 # complete.
170 # complete.
171 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
171 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
172 self._complete_with_items(cursor, matches)
172 self._complete_with_items(cursor, matches)
173
173
174 def _handle_execute_reply(self, msg):
174 def _handle_execute_reply(self, msg):
175 """ Reimplemented to support prompt requests.
175 """ Reimplemented to support prompt requests.
176 """
176 """
177 msg_id = msg['parent_header'].get('msg_id')
177 msg_id = msg['parent_header'].get('msg_id')
178 info = self._request_info['execute'].get(msg_id)
178 info = self._request_info['execute'].get(msg_id)
179 if info and info.kind == 'prompt':
179 if info and info.kind == 'prompt':
180 content = msg['content']
180 content = msg['content']
181 if content['status'] == 'aborted':
181 if content['status'] == 'aborted':
182 self._show_interpreter_prompt()
182 self._show_interpreter_prompt()
183 else:
183 else:
184 number = content['execution_count'] + 1
184 number = content['execution_count'] + 1
185 self._show_interpreter_prompt(number)
185 self._show_interpreter_prompt(number)
186 self._request_info['execute'].pop(msg_id)
186 self._request_info['execute'].pop(msg_id)
187 else:
187 else:
188 super(IPythonWidget, self)._handle_execute_reply(msg)
188 super(IPythonWidget, self)._handle_execute_reply(msg)
189
189
190 def _handle_history_reply(self, msg):
190 def _handle_history_reply(self, msg):
191 """ Implemented to handle history tail replies, which are only supported
191 """ Implemented to handle history tail replies, which are only supported
192 by the IPython kernel.
192 by the IPython kernel.
193 """
193 """
194 content = msg['content']
194 content = msg['content']
195 if 'history' not in content:
195 if 'history' not in content:
196 self.log.error("History request failed: %r"%content)
196 self.log.error("History request failed: %r"%content)
197 if content.get('status', '') == 'aborted' and \
197 if content.get('status', '') == 'aborted' and \
198 not self._retrying_history_request:
198 not self._retrying_history_request:
199 # a *different* action caused this request to be aborted, so
199 # a *different* action caused this request to be aborted, so
200 # we should try again.
200 # we should try again.
201 self.log.error("Retrying aborted history request")
201 self.log.error("Retrying aborted history request")
202 # prevent multiple retries of aborted requests:
202 # prevent multiple retries of aborted requests:
203 self._retrying_history_request = True
203 self._retrying_history_request = True
204 # wait out the kernel's queue flush, which is currently timed at 0.1s
204 # wait out the kernel's queue flush, which is currently timed at 0.1s
205 time.sleep(0.25)
205 time.sleep(0.25)
206 self.kernel_client.shell_channel.history(hist_access_type='tail',n=1000)
206 self.kernel_client.shell_channel.history(hist_access_type='tail',n=1000)
207 else:
207 else:
208 self._retrying_history_request = False
208 self._retrying_history_request = False
209 return
209 return
210 # reset retry flag
210 # reset retry flag
211 self._retrying_history_request = False
211 self._retrying_history_request = False
212 history_items = content['history']
212 history_items = content['history']
213 self.log.debug("Received history reply with %i entries", len(history_items))
213 self.log.debug("Received history reply with %i entries", len(history_items))
214 items = []
214 items = []
215 last_cell = u""
215 last_cell = u""
216 for _, _, cell in history_items:
216 for _, _, cell in history_items:
217 cell = cell.rstrip()
217 cell = cell.rstrip()
218 if cell != last_cell:
218 if cell != last_cell:
219 items.append(cell)
219 items.append(cell)
220 last_cell = cell
220 last_cell = cell
221 self._set_history(items)
221 self._set_history(items)
222
222
223 def _insert_other_input(self, cursor, content):
223 def _insert_other_input(self, cursor, content):
224 """Insert function for input from other frontends"""
224 """Insert function for input from other frontends"""
225 cursor.beginEditBlock()
225 cursor.beginEditBlock()
226 start = cursor.position()
226 start = cursor.position()
227 n = content.get('execution_count', 0)
227 n = content.get('execution_count', 0)
228 cursor.insertText('\n')
228 cursor.insertText('\n')
229 self._insert_html(cursor, self._make_in_prompt(n))
229 self._insert_html(cursor, self._make_in_prompt(n))
230 cursor.insertText(content['code'])
230 cursor.insertText(content['code'])
231 self._highlighter.rehighlightBlock(cursor.block())
231 self._highlighter.rehighlightBlock(cursor.block())
232 cursor.endEditBlock()
232 cursor.endEditBlock()
233
233
234 def _handle_execute_input(self, msg):
234 def _handle_execute_input(self, msg):
235 """Handle an execute_input message"""
235 """Handle an execute_input message"""
236 self.log.debug("execute_input: %s", msg.get('content', ''))
236 self.log.debug("execute_input: %s", msg.get('content', ''))
237 if self.include_output(msg):
237 if self.include_output(msg):
238 self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
238 self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
239
239
240
240
241 def _handle_execute_result(self, msg):
241 def _handle_execute_result(self, msg):
242 """ Reimplemented for IPython-style "display hook".
242 """ Reimplemented for IPython-style "display hook".
243 """
243 """
244 self.log.debug("execute_result: %s", msg.get('content', ''))
244 self.log.debug("execute_result: %s", msg.get('content', ''))
245 if self.include_output(msg):
245 if self.include_output(msg):
246 self.flush_clearoutput()
246 self.flush_clearoutput()
247 content = msg['content']
247 content = msg['content']
248 prompt_number = content.get('execution_count', 0)
248 prompt_number = content.get('execution_count', 0)
249 data = content['data']
249 data = content['data']
250 if 'text/plain' in data:
250 if 'text/plain' in data:
251 self._append_plain_text(self.output_sep, True)
251 self._append_plain_text(self.output_sep, True)
252 self._append_html(self._make_out_prompt(prompt_number), True)
252 self._append_html(self._make_out_prompt(prompt_number), True)
253 text = data['text/plain']
253 text = data['text/plain']
254 # If the repr is multiline, make sure we start on a new line,
254 # If the repr is multiline, make sure we start on a new line,
255 # so that its lines are aligned.
255 # so that its lines are aligned.
256 if "\n" in text and not self.output_sep.endswith("\n"):
256 if "\n" in text and not self.output_sep.endswith("\n"):
257 self._append_plain_text('\n', True)
257 self._append_plain_text('\n', True)
258 self._append_plain_text(text + self.output_sep2, True)
258 self._append_plain_text(text + self.output_sep2, True)
259
259
260 def _handle_display_data(self, msg):
260 def _handle_display_data(self, msg):
261 """ The base handler for the ``display_data`` message.
261 """ The base handler for the ``display_data`` message.
262 """
262 """
263 self.log.debug("display: %s", msg.get('content', ''))
263 self.log.debug("display: %s", msg.get('content', ''))
264 # For now, we don't display data from other frontends, but we
264 # For now, we don't display data from other frontends, but we
265 # eventually will as this allows all frontends to monitor the display
265 # eventually will as this allows all frontends to monitor the display
266 # data. But we need to figure out how to handle this in the GUI.
266 # data. But we need to figure out how to handle this in the GUI.
267 if self.include_output(msg):
267 if self.include_output(msg):
268 self.flush_clearoutput()
268 self.flush_clearoutput()
269 data = msg['content']['data']
269 data = msg['content']['data']
270 metadata = msg['content']['metadata']
270 metadata = msg['content']['metadata']
271 # In the regular IPythonWidget, we simply print the plain text
271 # In the regular IPythonWidget, we simply print the plain text
272 # representation.
272 # representation.
273 if 'text/plain' in data:
273 if 'text/plain' in data:
274 text = data['text/plain']
274 text = data['text/plain']
275 self._append_plain_text(text, True)
275 self._append_plain_text(text, True)
276 # This newline seems to be needed for text and html output.
276 # This newline seems to be needed for text and html output.
277 self._append_plain_text(u'\n', True)
277 self._append_plain_text(u'\n', True)
278
278
279 def _handle_kernel_info_reply(self, rep):
279 def _handle_kernel_info_reply(self, rep):
280 """Handle kernel info replies."""
280 """Handle kernel info replies."""
281 content = rep['content']
281 content = rep['content']
282 if not self._guiref_loaded:
282 if not self._guiref_loaded:
283 if content.get('language') == 'python':
283 if content.get('language') == 'python':
284 self._load_guiref_magic()
284 self._load_guiref_magic()
285 self._guiref_loaded = True
285 self._guiref_loaded = True
286
286
287 self.kernel_banner = content.get('banner', '')
287 self.kernel_banner = content.get('banner', '')
288 if self._starting:
288 if self._starting:
289 # finish handling started channels
289 # finish handling started channels
290 self._starting = False
290 self._starting = False
291 super(IPythonWidget, self)._started_channels()
291 super(IPythonWidget, self)._started_channels()
292
292
293 def _started_channels(self):
293 def _started_channels(self):
294 """Reimplemented to make a history request and load %guiref."""
294 """Reimplemented to make a history request and load %guiref."""
295 self._starting = True
295 self._starting = True
296 # The reply will trigger %guiref load provided language=='python'
296 # The reply will trigger %guiref load provided language=='python'
297 self.kernel_client.kernel_info()
297 self.kernel_client.kernel_info()
298
298
299 self.kernel_client.shell_channel.history(hist_access_type='tail',
299 self.kernel_client.shell_channel.history(hist_access_type='tail',
300 n=1000)
300 n=1000)
301
301
302 def _load_guiref_magic(self):
302 def _load_guiref_magic(self):
303 """Load %guiref magic."""
303 """Load %guiref magic."""
304 self.kernel_client.shell_channel.execute('\n'.join([
304 self.kernel_client.shell_channel.execute('\n'.join([
305 "try:",
305 "try:",
306 " _usage",
306 " _usage",
307 "except:",
307 "except:",
308 " from IPython.core import usage as _usage",
308 " from IPython.core import usage as _usage",
309 " get_ipython().register_magic_function(_usage.page_guiref, 'line', 'guiref')",
309 " get_ipython().register_magic_function(_usage.page_guiref, 'line', 'guiref')",
310 " del _usage",
310 " del _usage",
311 ]), silent=True)
311 ]), silent=True)
312
312
313 #---------------------------------------------------------------------------
313 #---------------------------------------------------------------------------
314 # 'ConsoleWidget' public interface
314 # 'ConsoleWidget' public interface
315 #---------------------------------------------------------------------------
315 #---------------------------------------------------------------------------
316
316
317 #---------------------------------------------------------------------------
317 #---------------------------------------------------------------------------
318 # 'FrontendWidget' public interface
318 # 'FrontendWidget' public interface
319 #---------------------------------------------------------------------------
319 #---------------------------------------------------------------------------
320
320
321 def execute_file(self, path, hidden=False):
321 def execute_file(self, path, hidden=False):
322 """ Reimplemented to use the 'run' magic.
322 """ Reimplemented to use the 'run' magic.
323 """
323 """
324 # Use forward slashes on Windows to avoid escaping each separator.
324 # Use forward slashes on Windows to avoid escaping each separator.
325 if sys.platform == 'win32':
325 if sys.platform == 'win32':
326 path = os.path.normpath(path).replace('\\', '/')
326 path = os.path.normpath(path).replace('\\', '/')
327
327
328 # Perhaps we should not be using %run directly, but while we
328 # Perhaps we should not be using %run directly, but while we
329 # are, it is necessary to quote or escape filenames containing spaces
329 # are, it is necessary to quote or escape filenames containing spaces
330 # or quotes.
330 # or quotes.
331
331
332 # In earlier code here, to minimize escaping, we sometimes quoted the
332 # In earlier code here, to minimize escaping, we sometimes quoted the
333 # filename with single quotes. But to do this, this code must be
333 # filename with single quotes. But to do this, this code must be
334 # platform-aware, because run uses shlex rather than python string
334 # platform-aware, because run uses shlex rather than python string
335 # parsing, so that:
335 # parsing, so that:
336 # * In Win: single quotes can be used in the filename without quoting,
336 # * In Win: single quotes can be used in the filename without quoting,
337 # and we cannot use single quotes to quote the filename.
337 # and we cannot use single quotes to quote the filename.
338 # * In *nix: we can escape double quotes in a double quoted filename,
338 # * In *nix: we can escape double quotes in a double quoted filename,
339 # but can't escape single quotes in a single quoted filename.
339 # but can't escape single quotes in a single quoted filename.
340
340
341 # So to keep this code non-platform-specific and simple, we now only
341 # So to keep this code non-platform-specific and simple, we now only
342 # use double quotes to quote filenames, and escape when needed:
342 # use double quotes to quote filenames, and escape when needed:
343 if ' ' in path or "'" in path or '"' in path:
343 if ' ' in path or "'" in path or '"' in path:
344 path = '"%s"' % path.replace('"', '\\"')
344 path = '"%s"' % path.replace('"', '\\"')
345 self.execute('%%run %s' % path, hidden=hidden)
345 self.execute('%%run %s' % path, hidden=hidden)
346
346
347 #---------------------------------------------------------------------------
347 #---------------------------------------------------------------------------
348 # 'FrontendWidget' protected interface
348 # 'FrontendWidget' protected interface
349 #---------------------------------------------------------------------------
349 #---------------------------------------------------------------------------
350
350
351 def _process_execute_error(self, msg):
351 def _process_execute_error(self, msg):
352 """ Reimplemented for IPython-style traceback formatting.
352 """ Reimplemented for IPython-style traceback formatting.
353 """
353 """
354 content = msg['content']
354 content = msg['content']
355 traceback = '\n'.join(content['traceback']) + '\n'
355 traceback = '\n'.join(content['traceback']) + '\n'
356 if False:
356 if False:
357 # FIXME: For now, tracebacks come as plain text, so we can't use
357 # FIXME: For now, tracebacks come as plain text, so we can't use
358 # the html renderer yet. Once we refactor ultratb to produce
358 # the html renderer yet. Once we refactor ultratb to produce
359 # properly styled tracebacks, this branch should be the default
359 # properly styled tracebacks, this branch should be the default
360 traceback = traceback.replace(' ', '&nbsp;')
360 traceback = traceback.replace(' ', '&nbsp;')
361 traceback = traceback.replace('\n', '<br/>')
361 traceback = traceback.replace('\n', '<br/>')
362
362
363 ename = content['ename']
363 ename = content['ename']
364 ename_styled = '<span class="error">%s</span>' % ename
364 ename_styled = '<span class="error">%s</span>' % ename
365 traceback = traceback.replace(ename, ename_styled)
365 traceback = traceback.replace(ename, ename_styled)
366
366
367 self._append_html(traceback)
367 self._append_html(traceback)
368 else:
368 else:
369 # This is the fallback for now, using plain text with ansi escapes
369 # This is the fallback for now, using plain text with ansi escapes
370 self._append_plain_text(traceback)
370 self._append_plain_text(traceback)
371
371
372 def _process_execute_payload(self, item):
372 def _process_execute_payload(self, item):
373 """ Reimplemented to dispatch payloads to handler methods.
373 """ Reimplemented to dispatch payloads to handler methods.
374 """
374 """
375 handler = self._payload_handlers.get(item['source'])
375 handler = self._payload_handlers.get(item['source'])
376 if handler is None:
376 if handler is None:
377 # We have no handler for this type of payload, simply ignore it
377 # We have no handler for this type of payload, simply ignore it
378 return False
378 return False
379 else:
379 else:
380 handler(item)
380 handler(item)
381 return True
381 return True
382
382
383 def _show_interpreter_prompt(self, number=None):
383 def _show_interpreter_prompt(self, number=None):
384 """ Reimplemented for IPython-style prompts.
384 """ Reimplemented for IPython-style prompts.
385 """
385 """
386 # If a number was not specified, make a prompt number request.
386 # If a number was not specified, make a prompt number request.
387 if number is None:
387 if number is None:
388 msg_id = self.kernel_client.shell_channel.execute('', silent=True)
388 msg_id = self.kernel_client.shell_channel.execute('', silent=True)
389 info = self._ExecutionRequest(msg_id, 'prompt')
389 info = self._ExecutionRequest(msg_id, 'prompt')
390 self._request_info['execute'][msg_id] = info
390 self._request_info['execute'][msg_id] = info
391 return
391 return
392
392
393 # Show a new prompt and save information about it so that it can be
393 # Show a new prompt and save information about it so that it can be
394 # updated later if the prompt number turns out to be wrong.
394 # updated later if the prompt number turns out to be wrong.
395 self._prompt_sep = self.input_sep
395 self._prompt_sep = self.input_sep
396 self._show_prompt(self._make_in_prompt(number), html=True)
396 self._show_prompt(self._make_in_prompt(number), html=True)
397 block = self._control.document().lastBlock()
397 block = self._control.document().lastBlock()
398 length = len(self._prompt)
398 length = len(self._prompt)
399 self._previous_prompt_obj = self._PromptBlock(block, length, number)
399 self._previous_prompt_obj = self._PromptBlock(block, length, number)
400
400
401 # Update continuation prompt to reflect (possibly) new prompt length.
401 # Update continuation prompt to reflect (possibly) new prompt length.
402 self._set_continuation_prompt(
402 self._set_continuation_prompt(
403 self._make_continuation_prompt(self._prompt), html=True)
403 self._make_continuation_prompt(self._prompt), html=True)
404
404
405 def _show_interpreter_prompt_for_reply(self, msg):
405 def _show_interpreter_prompt_for_reply(self, msg):
406 """ Reimplemented for IPython-style prompts.
406 """ Reimplemented for IPython-style prompts.
407 """
407 """
408 # Update the old prompt number if necessary.
408 # Update the old prompt number if necessary.
409 content = msg['content']
409 content = msg['content']
410 # abort replies do not have any keys:
410 # abort replies do not have any keys:
411 if content['status'] == 'aborted':
411 if content['status'] == 'aborted':
412 if self._previous_prompt_obj:
412 if self._previous_prompt_obj:
413 previous_prompt_number = self._previous_prompt_obj.number
413 previous_prompt_number = self._previous_prompt_obj.number
414 else:
414 else:
415 previous_prompt_number = 0
415 previous_prompt_number = 0
416 else:
416 else:
417 previous_prompt_number = content['execution_count']
417 previous_prompt_number = content['execution_count']
418 if self._previous_prompt_obj and \
418 if self._previous_prompt_obj and \
419 self._previous_prompt_obj.number != previous_prompt_number:
419 self._previous_prompt_obj.number != previous_prompt_number:
420 block = self._previous_prompt_obj.block
420 block = self._previous_prompt_obj.block
421
421
422 # Make sure the prompt block has not been erased.
422 # Make sure the prompt block has not been erased.
423 if block.isValid() and block.text():
423 if block.isValid() and block.text():
424
424
425 # Remove the old prompt and insert a new prompt.
425 # Remove the old prompt and insert a new prompt.
426 cursor = QtGui.QTextCursor(block)
426 cursor = QtGui.QTextCursor(block)
427 cursor.movePosition(QtGui.QTextCursor.Right,
427 cursor.movePosition(QtGui.QTextCursor.Right,
428 QtGui.QTextCursor.KeepAnchor,
428 QtGui.QTextCursor.KeepAnchor,
429 self._previous_prompt_obj.length)
429 self._previous_prompt_obj.length)
430 prompt = self._make_in_prompt(previous_prompt_number)
430 prompt = self._make_in_prompt(previous_prompt_number)
431 self._prompt = self._insert_html_fetching_plain_text(
431 self._prompt = self._insert_html_fetching_plain_text(
432 cursor, prompt)
432 cursor, prompt)
433
433
434 # When the HTML is inserted, Qt blows away the syntax
434 # When the HTML is inserted, Qt blows away the syntax
435 # highlighting for the line, so we need to rehighlight it.
435 # highlighting for the line, so we need to rehighlight it.
436 self._highlighter.rehighlightBlock(cursor.block())
436 self._highlighter.rehighlightBlock(cursor.block())
437
437
438 self._previous_prompt_obj = None
438 self._previous_prompt_obj = None
439
439
440 # Show a new prompt with the kernel's estimated prompt number.
440 # Show a new prompt with the kernel's estimated prompt number.
441 self._show_interpreter_prompt(previous_prompt_number + 1)
441 self._show_interpreter_prompt(previous_prompt_number + 1)
442
442
443 #---------------------------------------------------------------------------
443 #---------------------------------------------------------------------------
444 # 'IPythonWidget' interface
444 # 'IPythonWidget' interface
445 #---------------------------------------------------------------------------
445 #---------------------------------------------------------------------------
446
446
447 def set_default_style(self, colors='lightbg'):
447 def set_default_style(self, colors='lightbg'):
448 """ Sets the widget style to the class defaults.
448 """ Sets the widget style to the class defaults.
449
449
450 Parameters
450 Parameters
451 ----------
451 ----------
452 colors : str, optional (default lightbg)
452 colors : str, optional (default lightbg)
453 Whether to use the default IPython light background or dark
453 Whether to use the default IPython light background or dark
454 background or B&W style.
454 background or B&W style.
455 """
455 """
456 colors = colors.lower()
456 colors = colors.lower()
457 if colors=='lightbg':
457 if colors=='lightbg':
458 self.style_sheet = styles.default_light_style_sheet
458 self.style_sheet = styles.default_light_style_sheet
459 self.syntax_style = styles.default_light_syntax_style
459 self.syntax_style = styles.default_light_syntax_style
460 elif colors=='linux':
460 elif colors=='linux':
461 self.style_sheet = styles.default_dark_style_sheet
461 self.style_sheet = styles.default_dark_style_sheet
462 self.syntax_style = styles.default_dark_syntax_style
462 self.syntax_style = styles.default_dark_syntax_style
463 elif colors=='nocolor':
463 elif colors=='nocolor':
464 self.style_sheet = styles.default_bw_style_sheet
464 self.style_sheet = styles.default_bw_style_sheet
465 self.syntax_style = styles.default_bw_syntax_style
465 self.syntax_style = styles.default_bw_syntax_style
466 else:
466 else:
467 raise KeyError("No such color scheme: %s"%colors)
467 raise KeyError("No such color scheme: %s"%colors)
468
468
469 #---------------------------------------------------------------------------
469 #---------------------------------------------------------------------------
470 # 'IPythonWidget' protected interface
470 # 'IPythonWidget' protected interface
471 #---------------------------------------------------------------------------
471 #---------------------------------------------------------------------------
472
472
473 def _edit(self, filename, line=None):
473 def _edit(self, filename, line=None):
474 """ Opens a Python script for editing.
474 """ Opens a Python script for editing.
475
475
476 Parameters
476 Parameters
477 ----------
477 ----------
478 filename : str
478 filename : str
479 A path to a local system file.
479 A path to a local system file.
480
480
481 line : int, optional
481 line : int, optional
482 A line of interest in the file.
482 A line of interest in the file.
483 """
483 """
484 if self.custom_edit:
484 if self.custom_edit:
485 self.custom_edit_requested.emit(filename, line)
485 self.custom_edit_requested.emit(filename, line)
486 elif not self.editor:
486 elif not self.editor:
487 self._append_plain_text('No default editor available.\n'
487 self._append_plain_text('No default editor available.\n'
488 'Specify a GUI text editor in the `IPythonWidget.editor` '
488 'Specify a GUI text editor in the `IPythonWidget.editor` '
489 'configurable to enable the %edit magic')
489 'configurable to enable the %edit magic')
490 else:
490 else:
491 try:
491 try:
492 filename = '"%s"' % filename
492 filename = '"%s"' % filename
493 if line and self.editor_line:
493 if line and self.editor_line:
494 command = self.editor_line.format(filename=filename,
494 command = self.editor_line.format(filename=filename,
495 line=line)
495 line=line)
496 else:
496 else:
497 try:
497 try:
498 command = self.editor.format()
498 command = self.editor.format()
499 except KeyError:
499 except KeyError:
500 command = self.editor.format(filename=filename)
500 command = self.editor.format(filename=filename)
501 else:
501 else:
502 command += ' ' + filename
502 command += ' ' + filename
503 except KeyError:
503 except KeyError:
504 self._append_plain_text('Invalid editor command.\n')
504 self._append_plain_text('Invalid editor command.\n')
505 else:
505 else:
506 try:
506 try:
507 Popen(command, shell=True)
507 Popen(command, shell=True)
508 except OSError:
508 except OSError:
509 msg = 'Opening editor with command "%s" failed.\n'
509 msg = 'Opening editor with command "%s" failed.\n'
510 self._append_plain_text(msg % command)
510 self._append_plain_text(msg % command)
511
511
512 def _make_in_prompt(self, number):
512 def _make_in_prompt(self, number):
513 """ Given a prompt number, returns an HTML In prompt.
513 """ Given a prompt number, returns an HTML In prompt.
514 """
514 """
515 try:
515 try:
516 body = self.in_prompt % number
516 body = self.in_prompt % number
517 except TypeError:
517 except TypeError:
518 # allow in_prompt to leave out number, e.g. '>>> '
518 # allow in_prompt to leave out number, e.g. '>>> '
519 from xml.sax.saxutils import escape
519 from xml.sax.saxutils import escape
520 body = escape(self.in_prompt)
520 body = escape(self.in_prompt)
521 return '<span class="in-prompt">%s</span>' % body
521 return '<span class="in-prompt">%s</span>' % body
522
522
523 def _make_continuation_prompt(self, prompt):
523 def _make_continuation_prompt(self, prompt):
524 """ Given a plain text version of an In prompt, returns an HTML
524 """ Given a plain text version of an In prompt, returns an HTML
525 continuation prompt.
525 continuation prompt.
526 """
526 """
527 end_chars = '...: '
527 end_chars = '...: '
528 space_count = len(prompt.lstrip('\n')) - len(end_chars)
528 space_count = len(prompt.lstrip('\n')) - len(end_chars)
529 body = '&nbsp;' * space_count + end_chars
529 body = '&nbsp;' * space_count + end_chars
530 return '<span class="in-prompt">%s</span>' % body
530 return '<span class="in-prompt">%s</span>' % body
531
531
532 def _make_out_prompt(self, number):
532 def _make_out_prompt(self, number):
533 """ Given a prompt number, returns an HTML Out prompt.
533 """ Given a prompt number, returns an HTML Out prompt.
534 """
534 """
535 try:
535 try:
536 body = self.out_prompt % number
536 body = self.out_prompt % number
537 except TypeError:
537 except TypeError:
538 # allow out_prompt to leave out number, e.g. '<<< '
538 # allow out_prompt to leave out number, e.g. '<<< '
539 from xml.sax.saxutils import escape
539 from xml.sax.saxutils import escape
540 body = escape(self.out_prompt)
540 body = escape(self.out_prompt)
541 return '<span class="out-prompt">%s</span>' % body
541 return '<span class="out-prompt">%s</span>' % body
542
542
543 #------ Payload handlers --------------------------------------------------
543 #------ Payload handlers --------------------------------------------------
544
544
545 # Payload handlers with a generic interface: each takes the opaque payload
545 # Payload handlers with a generic interface: each takes the opaque payload
546 # dict, unpacks it and calls the underlying functions with the necessary
546 # dict, unpacks it and calls the underlying functions with the necessary
547 # arguments.
547 # arguments.
548
548
549 def _handle_payload_edit(self, item):
549 def _handle_payload_edit(self, item):
550 self._edit(item['filename'], item['line_number'])
550 self._edit(item['filename'], item['line_number'])
551
551
552 def _handle_payload_exit(self, item):
552 def _handle_payload_exit(self, item):
553 self._keep_kernel_on_exit = item['keepkernel']
553 self._keep_kernel_on_exit = item['keepkernel']
554 self.exit_requested.emit(self)
554 self.exit_requested.emit(self)
555
555
556 def _handle_payload_next_input(self, item):
556 def _handle_payload_next_input(self, item):
557 self.input_buffer = item['text']
557 self.input_buffer = item['text']
558
558
559 def _handle_payload_page(self, item):
559 def _handle_payload_page(self, item):
560 # Since the plain text widget supports only a very small subset of HTML
560 # Since the plain text widget supports only a very small subset of HTML
561 # and we have no control over the HTML source, we only page HTML
561 # and we have no control over the HTML source, we only page HTML
562 # payloads in the rich text widget.
562 # payloads in the rich text widget.
563 data = item['data']
563 data = item['data']
564 if 'text/html' in data and self.kind == 'rich':
564 if 'text/html' in data and self.kind == 'rich':
565 self._page(data['text/html'], html=True)
565 self._page(data['text/html'], html=True)
566 else:
566 else:
567 self._page(data['text/plain'], html=False)
567 self._page(data['text/plain'], html=False)
568
568
569 #------ Trait change handlers --------------------------------------------
569 #------ Trait change handlers --------------------------------------------
570
570
571 def _style_sheet_changed(self):
571 def _style_sheet_changed(self):
572 """ Set the style sheets of the underlying widgets.
572 """ Set the style sheets of the underlying widgets.
573 """
573 """
574 self.setStyleSheet(self.style_sheet)
574 self.setStyleSheet(self.style_sheet)
575 if self._control is not None:
575 if self._control is not None:
576 self._control.document().setDefaultStyleSheet(self.style_sheet)
576 self._control.document().setDefaultStyleSheet(self.style_sheet)
577 bg_color = self._control.palette().window().color()
577 bg_color = self._control.palette().window().color()
578 self._ansi_processor.set_background_color(bg_color)
578 self._ansi_processor.set_background_color(bg_color)
579
579
580 if self._page_control is not None:
580 if self._page_control is not None:
581 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
581 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
582
582
583
583
584
584
585 def _syntax_style_changed(self):
585 def _syntax_style_changed(self):
586 """ Set the style for the syntax highlighter.
586 """ Set the style for the syntax highlighter.
587 """
587 """
588 if self._highlighter is None:
588 if self._highlighter is None:
589 # ignore premature calls
589 # ignore premature calls
590 return
590 return
591 if self.syntax_style:
591 if self.syntax_style:
592 self._highlighter.set_style(self.syntax_style)
592 self._highlighter.set_style(self.syntax_style)
593 else:
593 else:
594 self._highlighter.set_style_sheet(self.style_sheet)
594 self._highlighter.set_style_sheet(self.style_sheet)
595
595
596 #------ Trait default initializers -----------------------------------------
596 #------ Trait default initializers -----------------------------------------
597
597
598 def _banner_default(self):
598 def _banner_default(self):
599 return "IPython QtConsole {version}\n".format(version=version)
599 return "IPython QtConsole {version}\n".format(version=version)
@@ -1,1138 +1,1184 b''
1 .. _messaging:
1 .. _messaging:
2
2
3 ======================
3 ======================
4 Messaging in IPython
4 Messaging in IPython
5 ======================
5 ======================
6
6
7
7
8 Versioning
8 Versioning
9 ==========
9 ==========
10
10
11 The IPython message specification is versioned independently of IPython.
11 The IPython message specification is versioned independently of IPython.
12 The current version of the specification is 5.0.
12 The current version of the specification is 5.0.
13
13
14
14
15 Introduction
15 Introduction
16 ============
16 ============
17
17
18 This document explains the basic communications design and messaging
18 This document explains the basic communications design and messaging
19 specification for how the various IPython objects interact over a network
19 specification for how the various IPython objects interact over a network
20 transport. The current implementation uses the ZeroMQ_ library for messaging
20 transport. The current implementation uses the ZeroMQ_ library for messaging
21 within and between hosts.
21 within and between hosts.
22
22
23 .. Note::
23 .. Note::
24
24
25 This document should be considered the authoritative description of the
25 This document should be considered the authoritative description of the
26 IPython messaging protocol, and all developers are strongly encouraged to
26 IPython messaging protocol, and all developers are strongly encouraged to
27 keep it updated as the implementation evolves, so that we have a single
27 keep it updated as the implementation evolves, so that we have a single
28 common reference for all protocol details.
28 common reference for all protocol details.
29
29
30 The basic design is explained in the following diagram:
30 The basic design is explained in the following diagram:
31
31
32 .. image:: figs/frontend-kernel.png
32 .. image:: figs/frontend-kernel.png
33 :width: 450px
33 :width: 450px
34 :alt: IPython kernel/frontend messaging architecture.
34 :alt: IPython kernel/frontend messaging architecture.
35 :align: center
35 :align: center
36 :target: ../_images/frontend-kernel.png
36 :target: ../_images/frontend-kernel.png
37
37
38 A single kernel can be simultaneously connected to one or more frontends. The
38 A single kernel can be simultaneously connected to one or more frontends. The
39 kernel has three sockets that serve the following functions:
39 kernel has three sockets that serve the following functions:
40
40
41 1. Shell: this single ROUTER socket allows multiple incoming connections from
41 1. Shell: this single ROUTER socket allows multiple incoming connections from
42 frontends, and this is the socket where requests for code execution, object
42 frontends, and this is the socket where requests for code execution, object
43 information, prompts, etc. are made to the kernel by any frontend. The
43 information, prompts, etc. are made to the kernel by any frontend. The
44 communication on this socket is a sequence of request/reply actions from
44 communication on this socket is a sequence of request/reply actions from
45 each frontend and the kernel.
45 each frontend and the kernel.
46
46
47 2. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
47 2. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
48 side effects (stdout, stderr, etc.) as well as the requests coming from any
48 side effects (stdout, stderr, etc.) as well as the requests coming from any
49 client over the shell socket and its own requests on the stdin socket. There
49 client over the shell socket and its own requests on the stdin socket. There
50 are a number of actions in Python which generate side effects: :func:`print`
50 are a number of actions in Python which generate side effects: :func:`print`
51 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
51 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
52 a multi-client scenario, we want all frontends to be able to know what each
52 a multi-client scenario, we want all frontends to be able to know what each
53 other has sent to the kernel (this can be useful in collaborative scenarios,
53 other has sent to the kernel (this can be useful in collaborative scenarios,
54 for example). This socket allows both side effects and the information
54 for example). This socket allows both side effects and the information
55 about communications taking place with one client over the shell channel
55 about communications taking place with one client over the shell channel
56 to be made available to all clients in a uniform manner.
56 to be made available to all clients in a uniform manner.
57
57
58 3. stdin: this ROUTER socket is connected to all frontends, and it allows
58 3. stdin: this ROUTER socket is connected to all frontends, and it allows
59 the kernel to request input from the active frontend when :func:`raw_input` is called.
59 the kernel to request input from the active frontend when :func:`raw_input` is called.
60 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
60 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
61 for the kernel while this communication is happening (illustrated in the
61 for the kernel while this communication is happening (illustrated in the
62 figure by the black outline around the central keyboard). In practice,
62 figure by the black outline around the central keyboard). In practice,
63 frontends may display such kernel requests using a special input widget or
63 frontends may display such kernel requests using a special input widget or
64 otherwise indicating that the user is to type input for the kernel instead
64 otherwise indicating that the user is to type input for the kernel instead
65 of normal commands in the frontend.
65 of normal commands in the frontend.
66
66
67 All messages are tagged with enough information (details below) for clients
67 All messages are tagged with enough information (details below) for clients
68 to know which messages come from their own interaction with the kernel and
68 to know which messages come from their own interaction with the kernel and
69 which ones are from other clients, so they can display each type
69 which ones are from other clients, so they can display each type
70 appropriately.
70 appropriately.
71
71
72 4. Control: This channel is identical to Shell, but operates on a separate socket,
72 4. Control: This channel is identical to Shell, but operates on a separate socket,
73 to allow important messages to avoid queueing behind execution requests (e.g. shutdown or abort).
73 to allow important messages to avoid queueing behind execution requests (e.g. shutdown or abort).
74
74
75 The actual format of the messages allowed on each of these channels is
75 The actual format of the messages allowed on each of these channels is
76 specified below. Messages are dicts of dicts with string keys and values that
76 specified below. Messages are dicts of dicts with string keys and values that
77 are reasonably representable in JSON. Our current implementation uses JSON
77 are reasonably representable in JSON. Our current implementation uses JSON
78 explicitly as its message format, but this shouldn't be considered a permanent
78 explicitly as its message format, but this shouldn't be considered a permanent
79 feature. As we've discovered that JSON has non-trivial performance issues due
79 feature. As we've discovered that JSON has non-trivial performance issues due
80 to excessive copying, we may in the future move to a pure pickle-based raw
80 to excessive copying, we may in the future move to a pure pickle-based raw
81 message format. However, it should be possible to easily convert from the raw
81 message format. However, it should be possible to easily convert from the raw
82 objects to JSON, since we may have non-python clients (e.g. a web frontend).
82 objects to JSON, since we may have non-python clients (e.g. a web frontend).
83 As long as it's easy to make a JSON version of the objects that is a faithful
83 As long as it's easy to make a JSON version of the objects that is a faithful
84 representation of all the data, we can communicate with such clients.
84 representation of all the data, we can communicate with such clients.
85
85
86 .. Note::
86 .. Note::
87
87
88 Not all of these have yet been fully fleshed out, but the key ones are, see
88 Not all of these have yet been fully fleshed out, but the key ones are, see
89 kernel and frontend files for actual implementation details.
89 kernel and frontend files for actual implementation details.
90
90
91 General Message Format
91 General Message Format
92 ======================
92 ======================
93
93
94 A message is defined by the following four-dictionary structure::
94 A message is defined by the following four-dictionary structure::
95
95
96 {
96 {
97 # The message header contains a pair of unique identifiers for the
97 # The message header contains a pair of unique identifiers for the
98 # originating session and the actual message id, in addition to the
98 # originating session and the actual message id, in addition to the
99 # username for the process that generated the message. This is useful in
99 # username for the process that generated the message. This is useful in
100 # collaborative settings where multiple users may be interacting with the
100 # collaborative settings where multiple users may be interacting with the
101 # same kernel simultaneously, so that frontends can label the various
101 # same kernel simultaneously, so that frontends can label the various
102 # messages in a meaningful way.
102 # messages in a meaningful way.
103 'header' : {
103 'header' : {
104 'msg_id' : uuid,
104 'msg_id' : uuid,
105 'username' : str,
105 'username' : str,
106 'session' : uuid,
106 'session' : uuid,
107 # All recognized message type strings are listed below.
107 # All recognized message type strings are listed below.
108 'msg_type' : str,
108 'msg_type' : str,
109 # the message protocol version
109 # the message protocol version
110 'version' : '5.0',
110 'version' : '5.0',
111 },
111 },
112
112
113 # In a chain of messages, the header from the parent is copied so that
113 # In a chain of messages, the header from the parent is copied so that
114 # clients can track where messages come from.
114 # clients can track where messages come from.
115 'parent_header' : dict,
115 'parent_header' : dict,
116
116
117 # Any metadata associated with the message.
117 # Any metadata associated with the message.
118 'metadata' : dict,
118 'metadata' : dict,
119
119
120 # The actual content of the message must be a dict, whose structure
120 # The actual content of the message must be a dict, whose structure
121 # depends on the message type.
121 # depends on the message type.
122 'content' : dict,
122 'content' : dict,
123 }
123 }
124
124
125 .. versionchanged:: 5.0
125 .. versionchanged:: 5.0
126
126
127 ``version`` key added to the header.
127 ``version`` key added to the header.
128
128
129 .. _wire_protocol:
129 .. _wire_protocol:
130
130
131 The Wire Protocol
131 The Wire Protocol
132 =================
132 =================
133
133
134
134
135 This message format exists at a high level,
135 This message format exists at a high level,
136 but does not describe the actual *implementation* at the wire level in zeromq.
136 but does not describe the actual *implementation* at the wire level in zeromq.
137 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
137 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
138
138
139 .. note::
139 .. note::
140
140
141 This section should only be relevant to non-Python consumers of the protocol.
141 This section should only be relevant to non-Python consumers of the protocol.
142 Python consumers should simply import and use IPython's own implementation of the wire protocol
142 Python consumers should simply import and use IPython's own implementation of the wire protocol
143 in the :class:`IPython.kernel.zmq.session.Session` object.
143 in the :class:`IPython.kernel.zmq.session.Session` object.
144
144
145 Every message is serialized to a sequence of at least six blobs of bytes:
145 Every message is serialized to a sequence of at least six blobs of bytes:
146
146
147 .. sourcecode:: python
147 .. sourcecode:: python
148
148
149 [
149 [
150 b'u-u-i-d', # zmq identity(ies)
150 b'u-u-i-d', # zmq identity(ies)
151 b'<IDS|MSG>', # delimiter
151 b'<IDS|MSG>', # delimiter
152 b'baddad42', # HMAC signature
152 b'baddad42', # HMAC signature
153 b'{header}', # serialized header dict
153 b'{header}', # serialized header dict
154 b'{parent_header}', # serialized parent header dict
154 b'{parent_header}', # serialized parent header dict
155 b'{metadata}', # serialized metadata dict
155 b'{metadata}', # serialized metadata dict
156 b'{content}, # serialized content dict
156 b'{content}, # serialized content dict
157 b'blob', # extra raw data buffer(s)
157 b'blob', # extra raw data buffer(s)
158 ...
158 ...
159 ]
159 ]
160
160
161 The front of the message is the ZeroMQ routing prefix,
161 The front of the message is the ZeroMQ routing prefix,
162 which can be zero or more socket identities.
162 which can be zero or more socket identities.
163 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
163 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
164 In the case of IOPub, there should be just one prefix component,
164 In the case of IOPub, there should be just one prefix component,
165 which is the topic for IOPub subscribers, e.g. ``execute_result``, ``display_data``.
165 which is the topic for IOPub subscribers, e.g. ``execute_result``, ``display_data``.
166
166
167 .. note::
167 .. note::
168
168
169 In most cases, the IOPub topics are irrelevant and completely ignored,
169 In most cases, the IOPub topics are irrelevant and completely ignored,
170 because frontends just subscribe to all topics.
170 because frontends just subscribe to all topics.
171 The convention used in the IPython kernel is to use the msg_type as the topic,
171 The convention used in the IPython kernel is to use the msg_type as the topic,
172 and possibly extra information about the message, e.g. ``execute_result`` or ``stream.stdout``
172 and possibly extra information about the message, e.g. ``execute_result`` or ``stream.stdout``
173
173
174 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
174 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
175 If authentication is disabled, this should be an empty string.
175 If authentication is disabled, this should be an empty string.
176 By default, the hashing function used for computing these signatures is sha256.
176 By default, the hashing function used for computing these signatures is sha256.
177
177
178 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
178 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
179
179
180 .. note::
180 .. note::
181
181
182 To disable authentication and signature checking,
182 To disable authentication and signature checking,
183 set the `key` field of a connection file to an empty string.
183 set the `key` field of a connection file to an empty string.
184
184
185 The signature is the HMAC hex digest of the concatenation of:
185 The signature is the HMAC hex digest of the concatenation of:
186
186
187 - A shared key (typically the ``key`` field of a connection file)
187 - A shared key (typically the ``key`` field of a connection file)
188 - The serialized header dict
188 - The serialized header dict
189 - The serialized parent header dict
189 - The serialized parent header dict
190 - The serialized metadata dict
190 - The serialized metadata dict
191 - The serialized content dict
191 - The serialized content dict
192
192
193 In Python, this is implemented via:
193 In Python, this is implemented via:
194
194
195 .. sourcecode:: python
195 .. sourcecode:: python
196
196
197 # once:
197 # once:
198 digester = HMAC(key, digestmod=hashlib.sha256)
198 digester = HMAC(key, digestmod=hashlib.sha256)
199
199
200 # for each message
200 # for each message
201 d = digester.copy()
201 d = digester.copy()
202 for serialized_dict in (header, parent, metadata, content):
202 for serialized_dict in (header, parent, metadata, content):
203 d.update(serialized_dict)
203 d.update(serialized_dict)
204 signature = d.hexdigest()
204 signature = d.hexdigest()
205
205
206 After the signature is the actual message, always in four frames of bytes.
206 After the signature is the actual message, always in four frames of bytes.
207 The four dictionaries that compose a message are serialized separately,
207 The four dictionaries that compose a message are serialized separately,
208 in the order of header, parent header, metadata, and content.
208 in the order of header, parent header, metadata, and content.
209 These can be serialized by any function that turns a dict into bytes.
209 These can be serialized by any function that turns a dict into bytes.
210 The default and most common serialization is JSON, but msgpack and pickle
210 The default and most common serialization is JSON, but msgpack and pickle
211 are common alternatives.
211 are common alternatives.
212
212
213 After the serialized dicts are zero to many raw data buffers,
213 After the serialized dicts are zero to many raw data buffers,
214 which can be used by message types that support binary data (mainly apply and data_pub).
214 which can be used by message types that support binary data (mainly apply and data_pub).
215
215
216
216
217 Python functional API
217 Python functional API
218 =====================
218 =====================
219
219
220 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
220 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
221 should develop, at a few key points, functional forms of all the requests that
221 should develop, at a few key points, functional forms of all the requests that
222 take arguments in this manner and automatically construct the necessary dict
222 take arguments in this manner and automatically construct the necessary dict
223 for sending.
223 for sending.
224
224
225 In addition, the Python implementation of the message specification extends
225 In addition, the Python implementation of the message specification extends
226 messages upon deserialization to the following form for convenience::
226 messages upon deserialization to the following form for convenience::
227
227
228 {
228 {
229 'header' : dict,
229 'header' : dict,
230 # The msg's unique identifier and type are always stored in the header,
230 # The msg's unique identifier and type are always stored in the header,
231 # but the Python implementation copies them to the top level.
231 # but the Python implementation copies them to the top level.
232 'msg_id' : uuid,
232 'msg_id' : uuid,
233 'msg_type' : str,
233 'msg_type' : str,
234 'parent_header' : dict,
234 'parent_header' : dict,
235 'content' : dict,
235 'content' : dict,
236 'metadata' : dict,
236 'metadata' : dict,
237 }
237 }
238
238
239 All messages sent to or received by any IPython process should have this
239 All messages sent to or received by any IPython process should have this
240 extended structure.
240 extended structure.
241
241
242
242
243 Messages on the shell ROUTER/DEALER sockets
243 Messages on the shell ROUTER/DEALER sockets
244 ===========================================
244 ===========================================
245
245
246 .. _execute:
246 .. _execute:
247
247
248 Execute
248 Execute
249 -------
249 -------
250
250
251 This message type is used by frontends to ask the kernel to execute code on
251 This message type is used by frontends to ask the kernel to execute code on
252 behalf of the user, in a namespace reserved to the user's variables (and thus
252 behalf of the user, in a namespace reserved to the user's variables (and thus
253 separate from the kernel's own internal code and variables).
253 separate from the kernel's own internal code and variables).
254
254
255 Message type: ``execute_request``::
255 Message type: ``execute_request``::
256
256
257 content = {
257 content = {
258 # Source code to be executed by the kernel, one or more lines.
258 # Source code to be executed by the kernel, one or more lines.
259 'code' : str,
259 'code' : str,
260
260
261 # A boolean flag which, if True, signals the kernel to execute
261 # A boolean flag which, if True, signals the kernel to execute
262 # this code as quietly as possible.
262 # this code as quietly as possible.
263 # silent=True forces store_history to be False,
263 # silent=True forces store_history to be False,
264 # and will *not*:
264 # and will *not*:
265 # - broadcast output on the IOPUB channel
265 # - broadcast output on the IOPUB channel
266 # - have an execute_result
266 # - have an execute_result
267 # The default is False.
267 # The default is False.
268 'silent' : bool,
268 'silent' : bool,
269
269
270 # A boolean flag which, if True, signals the kernel to populate history
270 # A boolean flag which, if True, signals the kernel to populate history
271 # The default is True if silent is False. If silent is True, store_history
271 # The default is True if silent is False. If silent is True, store_history
272 # is forced to be False.
272 # is forced to be False.
273 'store_history' : bool,
273 'store_history' : bool,
274
274
275 # A dict mapping names to expressions to be evaluated in the
275 # A dict mapping names to expressions to be evaluated in the
276 # user's dict. The rich display-data representation of each will be evaluated after execution.
276 # user's dict. The rich display-data representation of each will be evaluated after execution.
277 # See the display_data content for the structure of the representation data.
277 # See the display_data content for the structure of the representation data.
278 'user_expressions' : dict,
278 'user_expressions' : dict,
279
279
280 # Some frontends do not support stdin requests.
280 # Some frontends do not support stdin requests.
281 # If raw_input is called from code executed from such a frontend,
281 # If raw_input is called from code executed from such a frontend,
282 # a StdinNotImplementedError will be raised.
282 # a StdinNotImplementedError will be raised.
283 'allow_stdin' : True,
283 'allow_stdin' : True,
284 }
284 }
285
285
286 .. versionchanged:: 5.0
286 .. versionchanged:: 5.0
287
287
288 ``user_variables`` removed, because it is redundant with user_expressions.
288 ``user_variables`` removed, because it is redundant with user_expressions.
289
289
290 The ``code`` field contains a single string (possibly multiline) to be executed.
290 The ``code`` field contains a single string (possibly multiline) to be executed.
291
291
292 The ``user_expressions`` field deserves a detailed explanation. In the past, IPython had
292 The ``user_expressions`` field deserves a detailed explanation. In the past, IPython had
293 the notion of a prompt string that allowed arbitrary code to be evaluated, and
293 the notion of a prompt string that allowed arbitrary code to be evaluated, and
294 this was put to good use by many in creating prompts that displayed system
294 this was put to good use by many in creating prompts that displayed system
295 status, path information, and even more esoteric uses like remote instrument
295 status, path information, and even more esoteric uses like remote instrument
296 status acquired over the network. But now that IPython has a clean separation
296 status acquired over the network. But now that IPython has a clean separation
297 between the kernel and the clients, the kernel has no prompt knowledge; prompts
297 between the kernel and the clients, the kernel has no prompt knowledge; prompts
298 are a frontend feature, and it should be even possible for different
298 are a frontend feature, and it should be even possible for different
299 frontends to display different prompts while interacting with the same kernel.
299 frontends to display different prompts while interacting with the same kernel.
300 ``user_expressions`` can be used to retrieve this information.
300 ``user_expressions`` can be used to retrieve this information.
301
301
302 Any error in evaluating any expression in ``user_expressions`` will result in
302 Any error in evaluating any expression in ``user_expressions`` will result in
303 only that key containing a standard error message, of the form::
303 only that key containing a standard error message, of the form::
304
304
305 {
305 {
306 'status' : 'error',
306 'status' : 'error',
307 'ename' : 'NameError',
307 'ename' : 'NameError',
308 'evalue' : 'foo',
308 'evalue' : 'foo',
309 'traceback' : ...
309 'traceback' : ...
310 }
310 }
311
311
312 .. Note::
312 .. Note::
313
313
314 In order to obtain the current execution counter for the purposes of
314 In order to obtain the current execution counter for the purposes of
315 displaying input prompts, frontends may make an execution request with an
315 displaying input prompts, frontends may make an execution request with an
316 empty code string and ``silent=True``.
316 empty code string and ``silent=True``.
317
317
318 Upon completion of the execution request, the kernel *always* sends a reply,
318 Upon completion of the execution request, the kernel *always* sends a reply,
319 with a status code indicating what happened and additional data depending on
319 with a status code indicating what happened and additional data depending on
320 the outcome. See :ref:`below <execution_results>` for the possible return
320 the outcome. See :ref:`below <execution_results>` for the possible return
321 codes and associated data.
321 codes and associated data.
322
322
323 .. seealso::
323 .. seealso::
324
324
325 :ref:`execution_semantics`
325 :ref:`execution_semantics`
326
326
327 .. _execution_counter:
327 .. _execution_counter:
328
328
329 Execution counter (prompt number)
329 Execution counter (prompt number)
330 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
330 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
331
331
332 The kernel should have a single, monotonically increasing counter of all execution
332 The kernel should have a single, monotonically increasing counter of all execution
333 requests that are made with ``store_history=True``. This counter is used to populate
333 requests that are made with ``store_history=True``. This counter is used to populate
334 the ``In[n]`` and ``Out[n]`` prompts. The value of this counter will be returned as the
334 the ``In[n]`` and ``Out[n]`` prompts. The value of this counter will be returned as the
335 ``execution_count`` field of all ``execute_reply`` and ``execute_input`` messages.
335 ``execution_count`` field of all ``execute_reply`` and ``execute_input`` messages.
336
336
337 .. _execution_results:
337 .. _execution_results:
338
338
339 Execution results
339 Execution results
340 ~~~~~~~~~~~~~~~~~
340 ~~~~~~~~~~~~~~~~~
341
341
342 Message type: ``execute_reply``::
342 Message type: ``execute_reply``::
343
343
344 content = {
344 content = {
345 # One of: 'ok' OR 'error' OR 'abort'
345 # One of: 'ok' OR 'error' OR 'abort'
346 'status' : str,
346 'status' : str,
347
347
348 # The global kernel counter that increases by one with each request that
348 # The global kernel counter that increases by one with each request that
349 # stores history. This will typically be used by clients to display
349 # stores history. This will typically be used by clients to display
350 # prompt numbers to the user. If the request did not store history, this will
350 # prompt numbers to the user. If the request did not store history, this will
351 # be the current value of the counter in the kernel.
351 # be the current value of the counter in the kernel.
352 'execution_count' : int,
352 'execution_count' : int,
353 }
353 }
354
354
355 When status is 'ok', the following extra fields are present::
355 When status is 'ok', the following extra fields are present::
356
356
357 {
357 {
358 # 'payload' will be a list of payload dicts.
358 # 'payload' will be a list of payload dicts, and is optional.
359 # Each execution payload is a dict with string keys that may have been
359 # payloads are considered deprecated.
360 # produced by the code being executed. It is retrieved by the kernel at
361 # the end of the execution and sent back to the front end, which can take
362 # action on it as needed.
363 # The only requirement of each payload dict is that it have a 'source' key,
360 # The only requirement of each payload dict is that it have a 'source' key,
364 # which is a string classifying the payload (e.g. 'pager').
361 # which is a string classifying the payload (e.g. 'page').
362
365 'payload' : list(dict),
363 'payload' : list(dict),
366
364
367 # Results for the user_expressions.
365 # Results for the user_expressions.
368 'user_expressions' : dict,
366 'user_expressions' : dict,
369 }
367 }
370
368
371 .. versionchanged:: 5.0
369 .. versionchanged:: 5.0
372
370
373 ``user_variables`` is removed, use user_expressions instead.
371 ``user_variables`` is removed, use user_expressions instead.
374
372
375 .. admonition:: Execution payloads
376
377 The notion of an 'execution payload' is different from a return value of a
378 given set of code, which normally is just displayed on the execute_result stream
379 through the PUB socket. The idea of a payload is to allow special types of
380 code, typically magics, to populate a data container in the IPython kernel
381 that will be shipped back to the caller via this channel. The kernel
382 has an API for this in the PayloadManager::
383
384 ip.payload_manager.write_payload(payload_dict)
385
386 which appends a dictionary to the list of payloads.
387
388 The payload API is not yet stabilized,
389 and should probably not be supported by non-Python kernels at this time.
390 In such cases, the payload list should always be empty.
391
392
393 When status is 'error', the following extra fields are present::
373 When status is 'error', the following extra fields are present::
394
374
395 {
375 {
396 'ename' : str, # Exception name, as a string
376 'ename' : str, # Exception name, as a string
397 'evalue' : str, # Exception value, as a string
377 'evalue' : str, # Exception value, as a string
398
378
399 # The traceback will contain a list of frames, represented each as a
379 # The traceback will contain a list of frames, represented each as a
400 # string. For now we'll stick to the existing design of ultraTB, which
380 # string. For now we'll stick to the existing design of ultraTB, which
401 # controls exception level of detail statefully. But eventually we'll
381 # controls exception level of detail statefully. But eventually we'll
402 # want to grow into a model where more information is collected and
382 # want to grow into a model where more information is collected and
403 # packed into the traceback object, with clients deciding how little or
383 # packed into the traceback object, with clients deciding how little or
404 # how much of it to unpack. But for now, let's start with a simple list
384 # how much of it to unpack. But for now, let's start with a simple list
405 # of strings, since that requires only minimal changes to ultratb as
385 # of strings, since that requires only minimal changes to ultratb as
406 # written.
386 # written.
407 'traceback' : list,
387 'traceback' : list,
408 }
388 }
409
389
410
390
411 When status is 'abort', there are for now no additional data fields. This
391 When status is 'abort', there are for now no additional data fields. This
412 happens when the kernel was interrupted by a signal.
392 happens when the kernel was interrupted by a signal.
413
393
394 Payloads
395 ********
396
397 .. admonition:: Execution payloads
398
399 Payloads are considered deprecated, though their replacement is not yet implemented.
400
401 Payloads are a way to trigger frontend actions from the kernel. Current payloads:
402
403 **page**: display data in a pager.
404
405 Pager output is used for introspection, or other displayed information that's not considered output.
406 Pager payloads are generally displayed in a separate pane, that can be viewed alongside code,
407 and are not included in notebook documents.
408
409 .. sourcecode:: python
410
411 {
412 "source": "page",
413 # mime-bundle of data to display in the pager.
414 # Must include text/plain.
415 "data": mimebundle,
416 # line offset to start from
417 "start": int,
418 }
419
420 **set_next_input**: create a new output
421
422 used to create new cells in the notebook,
423 or set the next input in a console interface.
424 The main example being ``%load``.
425
426 .. sourcecode:: python
427
428 {
429 "source": "set_next_input",
430 # the text contents of the cell to create
431 "text": "some cell content",
432 }
433
434 **edit**: open a file for editing.
435
436 Triggered by `%edit`. Only the QtConsole currently supports edit payloads.
437
438 .. sourcecode:: python
439
440 {
441 "source": "edit",
442 "filename": "/path/to/file.py", # the file to edit
443 "line_number": int, # the line number to start with
444 }
445
446 **ask_exit**: instruct the frontend to prompt the user for exit
447
448 Allows the kernel to request exit, e.g. via ``%exit`` in IPython.
449 Only for console frontends.
450
451 .. sourcecode:: python
452
453 {
454 "source": "ask_exit",
455 # whether the kernel should be left running, only closing the client
456 "keepkernel": bool,
457 }
458
459
414 .. _msging_inspection:
460 .. _msging_inspection:
415
461
416 Introspection
462 Introspection
417 -------------
463 -------------
418
464
419 Code can be inspected to show useful information to the user.
465 Code can be inspected to show useful information to the user.
420 It is up to the Kernel to decide what information should be displayed, and its formatting.
466 It is up to the Kernel to decide what information should be displayed, and its formatting.
421
467
422 Message type: ``inspect_request``::
468 Message type: ``inspect_request``::
423
469
424 content = {
470 content = {
425 # The code context in which introspection is requested
471 # The code context in which introspection is requested
426 # this may be up to an entire multiline cell.
472 # this may be up to an entire multiline cell.
427 'code' : str,
473 'code' : str,
428
474
429 # The cursor position within 'code' (in unicode characters) where inspection is requested
475 # The cursor position within 'code' (in unicode characters) where inspection is requested
430 'cursor_pos' : int,
476 'cursor_pos' : int,
431
477
432 # The level of detail desired. In IPython, the default (0) is equivalent to typing
478 # The level of detail desired. In IPython, the default (0) is equivalent to typing
433 # 'x?' at the prompt, 1 is equivalent to 'x??'.
479 # 'x?' at the prompt, 1 is equivalent to 'x??'.
434 # The difference is up to kernels, but in IPython level 1 includes the source code
480 # The difference is up to kernels, but in IPython level 1 includes the source code
435 # if available.
481 # if available.
436 'detail_level' : 0 or 1,
482 'detail_level' : 0 or 1,
437 }
483 }
438
484
439 .. versionchanged:: 5.0
485 .. versionchanged:: 5.0
440
486
441 ``object_info_request`` renamed to ``inspect_request``.
487 ``object_info_request`` renamed to ``inspect_request``.
442
488
443 .. versionchanged:: 5.0
489 .. versionchanged:: 5.0
444
490
445 ``name`` key replaced with ``code`` and ``cursor_pos``,
491 ``name`` key replaced with ``code`` and ``cursor_pos``,
446 moving the lexing responsibility to the kernel.
492 moving the lexing responsibility to the kernel.
447
493
448 The reply is a mime-bundle, like a `display_data`_ message,
494 The reply is a mime-bundle, like a `display_data`_ message,
449 which should be a formatted representation of information about the context.
495 which should be a formatted representation of information about the context.
450 In the notebook, this is used to show tooltips over function calls, etc.
496 In the notebook, this is used to show tooltips over function calls, etc.
451
497
452 Message type: ``inspect_reply``::
498 Message type: ``inspect_reply``::
453
499
454 content = {
500 content = {
455 # 'ok' if the request succeeded or 'error', with error information as in all other replies.
501 # 'ok' if the request succeeded or 'error', with error information as in all other replies.
456 'status' : 'ok',
502 'status' : 'ok',
457
503
458 # data can be empty if nothing is found
504 # data can be empty if nothing is found
459 'data' : dict,
505 'data' : dict,
460 'metadata' : dict,
506 'metadata' : dict,
461 }
507 }
462
508
463 .. versionchanged:: 5.0
509 .. versionchanged:: 5.0
464
510
465 ``object_info_reply`` renamed to ``inspect_reply``.
511 ``object_info_reply`` renamed to ``inspect_reply``.
466
512
467 .. versionchanged:: 5.0
513 .. versionchanged:: 5.0
468
514
469 Reply is changed from structured data to a mime bundle, allowing formatting decisions to be made by the kernel.
515 Reply is changed from structured data to a mime bundle, allowing formatting decisions to be made by the kernel.
470
516
471 .. _msging_completion:
517 .. _msging_completion:
472
518
473 Completion
519 Completion
474 ----------
520 ----------
475
521
476 Message type: ``complete_request``::
522 Message type: ``complete_request``::
477
523
478 content = {
524 content = {
479 # The code context in which completion is requested
525 # The code context in which completion is requested
480 # this may be up to an entire multiline cell, such as
526 # this may be up to an entire multiline cell, such as
481 # 'foo = a.isal'
527 # 'foo = a.isal'
482 'code' : str,
528 'code' : str,
483
529
484 # The cursor position within 'code' (in unicode characters) where completion is requested
530 # The cursor position within 'code' (in unicode characters) where completion is requested
485 'cursor_pos' : int,
531 'cursor_pos' : int,
486 }
532 }
487
533
488 .. versionchanged:: 5.0
534 .. versionchanged:: 5.0
489
535
490 ``line``, ``block``, and ``text`` keys are removed in favor of a single ``code`` for context.
536 ``line``, ``block``, and ``text`` keys are removed in favor of a single ``code`` for context.
491 Lexing is up to the kernel.
537 Lexing is up to the kernel.
492
538
493
539
494 Message type: ``complete_reply``::
540 Message type: ``complete_reply``::
495
541
496 content = {
542 content = {
497 # The list of all matches to the completion request, such as
543 # The list of all matches to the completion request, such as
498 # ['a.isalnum', 'a.isalpha'] for the above example.
544 # ['a.isalnum', 'a.isalpha'] for the above example.
499 'matches' : list,
545 'matches' : list,
500
546
501 # The range of text that should be replaced by the above matches when a completion is accepted.
547 # The range of text that should be replaced by the above matches when a completion is accepted.
502 # typically cursor_end is the same as cursor_pos in the request.
548 # typically cursor_end is the same as cursor_pos in the request.
503 'cursor_start' : int,
549 'cursor_start' : int,
504 'cursor_end' : int,
550 'cursor_end' : int,
505
551
506 # Information that frontend plugins might use for extra display information about completions.
552 # Information that frontend plugins might use for extra display information about completions.
507 'metadata' : dict,
553 'metadata' : dict,
508
554
509 # status should be 'ok' unless an exception was raised during the request,
555 # status should be 'ok' unless an exception was raised during the request,
510 # in which case it should be 'error', along with the usual error message content
556 # in which case it should be 'error', along with the usual error message content
511 # in other messages.
557 # in other messages.
512 'status' : 'ok'
558 'status' : 'ok'
513 }
559 }
514
560
515 .. versionchanged:: 5.0
561 .. versionchanged:: 5.0
516
562
517 - ``matched_text`` is removed in favor of ``cursor_start`` and ``cursor_end``.
563 - ``matched_text`` is removed in favor of ``cursor_start`` and ``cursor_end``.
518 - ``metadata`` is added for extended information.
564 - ``metadata`` is added for extended information.
519
565
520 .. _msging_history:
566 .. _msging_history:
521
567
522 History
568 History
523 -------
569 -------
524
570
525 For clients to explicitly request history from a kernel. The kernel has all
571 For clients to explicitly request history from a kernel. The kernel has all
526 the actual execution history stored in a single location, so clients can
572 the actual execution history stored in a single location, so clients can
527 request it from the kernel when needed.
573 request it from the kernel when needed.
528
574
529 Message type: ``history_request``::
575 Message type: ``history_request``::
530
576
531 content = {
577 content = {
532
578
533 # If True, also return output history in the resulting dict.
579 # If True, also return output history in the resulting dict.
534 'output' : bool,
580 'output' : bool,
535
581
536 # If True, return the raw input history, else the transformed input.
582 # If True, return the raw input history, else the transformed input.
537 'raw' : bool,
583 'raw' : bool,
538
584
539 # So far, this can be 'range', 'tail' or 'search'.
585 # So far, this can be 'range', 'tail' or 'search'.
540 'hist_access_type' : str,
586 'hist_access_type' : str,
541
587
542 # If hist_access_type is 'range', get a range of input cells. session can
588 # If hist_access_type is 'range', get a range of input cells. session can
543 # be a positive session number, or a negative number to count back from
589 # be a positive session number, or a negative number to count back from
544 # the current session.
590 # the current session.
545 'session' : int,
591 'session' : int,
546 # start and stop are line numbers within that session.
592 # start and stop are line numbers within that session.
547 'start' : int,
593 'start' : int,
548 'stop' : int,
594 'stop' : int,
549
595
550 # If hist_access_type is 'tail' or 'search', get the last n cells.
596 # If hist_access_type is 'tail' or 'search', get the last n cells.
551 'n' : int,
597 'n' : int,
552
598
553 # If hist_access_type is 'search', get cells matching the specified glob
599 # If hist_access_type is 'search', get cells matching the specified glob
554 # pattern (with * and ? as wildcards).
600 # pattern (with * and ? as wildcards).
555 'pattern' : str,
601 'pattern' : str,
556
602
557 # If hist_access_type is 'search' and unique is true, do not
603 # If hist_access_type is 'search' and unique is true, do not
558 # include duplicated history. Default is false.
604 # include duplicated history. Default is false.
559 'unique' : bool,
605 'unique' : bool,
560
606
561 }
607 }
562
608
563 .. versionadded:: 4.0
609 .. versionadded:: 4.0
564 The key ``unique`` for ``history_request``.
610 The key ``unique`` for ``history_request``.
565
611
566 Message type: ``history_reply``::
612 Message type: ``history_reply``::
567
613
568 content = {
614 content = {
569 # A list of 3 tuples, either:
615 # A list of 3 tuples, either:
570 # (session, line_number, input) or
616 # (session, line_number, input) or
571 # (session, line_number, (input, output)),
617 # (session, line_number, (input, output)),
572 # depending on whether output was False or True, respectively.
618 # depending on whether output was False or True, respectively.
573 'history' : list,
619 'history' : list,
574 }
620 }
575
621
576 .. _msging_is_complete:
622 .. _msging_is_complete:
577
623
578 Code completeness
624 Code completeness
579 -----------------
625 -----------------
580
626
581 .. versionadded:: 5.0
627 .. versionadded:: 5.0
582
628
583 When the user enters a line in a console style interface, the console must
629 When the user enters a line in a console style interface, the console must
584 decide whether to immediately execute the current code, or whether to show a
630 decide whether to immediately execute the current code, or whether to show a
585 continuation prompt for further input. For instance, in Python ``a = 5`` would
631 continuation prompt for further input. For instance, in Python ``a = 5`` would
586 be executed immediately, while ``for i in range(5):`` would expect further input.
632 be executed immediately, while ``for i in range(5):`` would expect further input.
587
633
588 There are four possible replies:
634 There are four possible replies:
589
635
590 - *complete* code is ready to be executed
636 - *complete* code is ready to be executed
591 - *incomplete* code should prompt for another line
637 - *incomplete* code should prompt for another line
592 - *invalid* code will typically be sent for execution, so that the user sees the
638 - *invalid* code will typically be sent for execution, so that the user sees the
593 error soonest.
639 error soonest.
594 - *unknown* - if the kernel is not able to determine this. The frontend should
640 - *unknown* - if the kernel is not able to determine this. The frontend should
595 also handle the kernel not replying promptly. It may default to sending the
641 also handle the kernel not replying promptly. It may default to sending the
596 code for execution, or it may implement simple fallback heuristics for whether
642 code for execution, or it may implement simple fallback heuristics for whether
597 to execute the code (e.g. execute after a blank line).
643 to execute the code (e.g. execute after a blank line).
598
644
599 Frontends may have ways to override this, forcing the code to be sent for
645 Frontends may have ways to override this, forcing the code to be sent for
600 execution or forcing a continuation prompt.
646 execution or forcing a continuation prompt.
601
647
602 Message type: ``is_complete_request``::
648 Message type: ``is_complete_request``::
603
649
604 content = {
650 content = {
605 # The code entered so far as a multiline string
651 # The code entered so far as a multiline string
606 'code' : str,
652 'code' : str,
607 }
653 }
608
654
609 Message type: ``is_complete_reply``::
655 Message type: ``is_complete_reply``::
610
656
611 content = {
657 content = {
612 # One of 'complete', 'incomplete', 'invalid', 'unknown'
658 # One of 'complete', 'incomplete', 'invalid', 'unknown'
613 'status' : str,
659 'status' : str,
614
660
615 # If status is 'incomplete', indent should contain the characters to use
661 # If status is 'incomplete', indent should contain the characters to use
616 # to indent the next line. This is only a hint: frontends may ignore it
662 # to indent the next line. This is only a hint: frontends may ignore it
617 # and use their own autoindentation rules. For other statuses, this
663 # and use their own autoindentation rules. For other statuses, this
618 # field does not exist.
664 # field does not exist.
619 'indent': str,
665 'indent': str,
620 }
666 }
621
667
622 Connect
668 Connect
623 -------
669 -------
624
670
625 When a client connects to the request/reply socket of the kernel, it can issue
671 When a client connects to the request/reply socket of the kernel, it can issue
626 a connect request to get basic information about the kernel, such as the ports
672 a connect request to get basic information about the kernel, such as the ports
627 the other ZeroMQ sockets are listening on. This allows clients to only have
673 the other ZeroMQ sockets are listening on. This allows clients to only have
628 to know about a single port (the shell channel) to connect to a kernel.
674 to know about a single port (the shell channel) to connect to a kernel.
629
675
630 Message type: ``connect_request``::
676 Message type: ``connect_request``::
631
677
632 content = {
678 content = {
633 }
679 }
634
680
635 Message type: ``connect_reply``::
681 Message type: ``connect_reply``::
636
682
637 content = {
683 content = {
638 'shell_port' : int, # The port the shell ROUTER socket is listening on.
684 'shell_port' : int, # The port the shell ROUTER socket is listening on.
639 'iopub_port' : int, # The port the PUB socket is listening on.
685 'iopub_port' : int, # The port the PUB socket is listening on.
640 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
686 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
641 'hb_port' : int, # The port the heartbeat socket is listening on.
687 'hb_port' : int, # The port the heartbeat socket is listening on.
642 }
688 }
643
689
644 .. _msging_kernel_info:
690 .. _msging_kernel_info:
645
691
646 Kernel info
692 Kernel info
647 -----------
693 -----------
648
694
649 If a client needs to know information about the kernel, it can
695 If a client needs to know information about the kernel, it can
650 make a request of the kernel's information.
696 make a request of the kernel's information.
651 This message can be used to fetch core information of the
697 This message can be used to fetch core information of the
652 kernel, including language (e.g., Python), language version number and
698 kernel, including language (e.g., Python), language version number and
653 IPython version number, and the IPython message spec version number.
699 IPython version number, and the IPython message spec version number.
654
700
655 Message type: ``kernel_info_request``::
701 Message type: ``kernel_info_request``::
656
702
657 content = {
703 content = {
658 }
704 }
659
705
660 Message type: ``kernel_info_reply``::
706 Message type: ``kernel_info_reply``::
661
707
662 content = {
708 content = {
663 # Version of messaging protocol.
709 # Version of messaging protocol.
664 # The first integer indicates major version. It is incremented when
710 # The first integer indicates major version. It is incremented when
665 # there is any backward incompatible change.
711 # there is any backward incompatible change.
666 # The second integer indicates minor version. It is incremented when
712 # The second integer indicates minor version. It is incremented when
667 # there is any backward compatible change.
713 # there is any backward compatible change.
668 'protocol_version': 'X.Y.Z',
714 'protocol_version': 'X.Y.Z',
669
715
670 # The kernel implementation name
716 # The kernel implementation name
671 # (e.g. 'ipython' for the IPython kernel)
717 # (e.g. 'ipython' for the IPython kernel)
672 'implementation': str,
718 'implementation': str,
673
719
674 # Implementation version number.
720 # Implementation version number.
675 # The version number of the kernel's implementation
721 # The version number of the kernel's implementation
676 # (e.g. IPython.__version__ for the IPython kernel)
722 # (e.g. IPython.__version__ for the IPython kernel)
677 'implementation_version': 'X.Y.Z',
723 'implementation_version': 'X.Y.Z',
678
724
679 # Programming language in which kernel is implemented.
725 # Programming language in which kernel is implemented.
680 # Kernel included in IPython returns 'python'.
726 # Kernel included in IPython returns 'python'.
681 'language': str,
727 'language': str,
682
728
683 # Language version number.
729 # Language version number.
684 # It is Python version number (e.g., '2.7.3') for the kernel
730 # It is Python version number (e.g., '2.7.3') for the kernel
685 # included in IPython.
731 # included in IPython.
686 'language_version': 'X.Y.Z',
732 'language_version': 'X.Y.Z',
687
733
688 # Information about the language of code for the kernel
734 # Information about the language of code for the kernel
689 'language_info': {
735 'language_info': {
690 'mimetype': str,
736 'mimetype': str,
691
737
692 # Pygments lexer, for highlighting
738 # Pygments lexer, for highlighting
693 # Only needed if it differs from the top level 'language' field.
739 # Only needed if it differs from the top level 'language' field.
694 'pygments_lexer': str,
740 'pygments_lexer': str,
695
741
696 # Codemirror mode, for for highlighting in the notebook.
742 # Codemirror mode, for for highlighting in the notebook.
697 # Only needed if it differs from the top level 'language' field.
743 # Only needed if it differs from the top level 'language' field.
698 'codemirror_mode': str or dict,
744 'codemirror_mode': str or dict,
699 },
745 },
700
746
701 # A banner of information about the kernel,
747 # A banner of information about the kernel,
702 # which may be desplayed in console environments.
748 # which may be desplayed in console environments.
703 'banner' : str,
749 'banner' : str,
704
750
705 # Optional: A list of dictionaries, each with keys 'text' and 'url'.
751 # Optional: A list of dictionaries, each with keys 'text' and 'url'.
706 # These will be displayed in the help menu in the notebook UI.
752 # These will be displayed in the help menu in the notebook UI.
707 'help_links': [
753 'help_links': [
708 {'text': str, 'url': str}
754 {'text': str, 'url': str}
709 ],
755 ],
710 }
756 }
711
757
712 Refer to the lists of available `Pygments lexers <http://pygments.org/docs/lexers/>`_
758 Refer to the lists of available `Pygments lexers <http://pygments.org/docs/lexers/>`_
713 and `codemirror modes <http://codemirror.net/mode/index.html>`_ for those fields.
759 and `codemirror modes <http://codemirror.net/mode/index.html>`_ for those fields.
714
760
715 .. versionchanged:: 5.0
761 .. versionchanged:: 5.0
716
762
717 Versions changed from lists of integers to strings.
763 Versions changed from lists of integers to strings.
718
764
719 .. versionchanged:: 5.0
765 .. versionchanged:: 5.0
720
766
721 ``ipython_version`` is removed.
767 ``ipython_version`` is removed.
722
768
723 .. versionchanged:: 5.0
769 .. versionchanged:: 5.0
724
770
725 ``language_info``, ``implementation``, ``implementation_version``, ``banner``
771 ``language_info``, ``implementation``, ``implementation_version``, ``banner``
726 and ``help_links`` keys are added.
772 and ``help_links`` keys are added.
727
773
728 .. _msging_shutdown:
774 .. _msging_shutdown:
729
775
730 Kernel shutdown
776 Kernel shutdown
731 ---------------
777 ---------------
732
778
733 The clients can request the kernel to shut itself down; this is used in
779 The clients can request the kernel to shut itself down; this is used in
734 multiple cases:
780 multiple cases:
735
781
736 - when the user chooses to close the client application via a menu or window
782 - when the user chooses to close the client application via a menu or window
737 control.
783 control.
738 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
784 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
739 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
785 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
740 IPythonQt client) to force a kernel restart to get a clean kernel without
786 IPythonQt client) to force a kernel restart to get a clean kernel without
741 losing client-side state like history or inlined figures.
787 losing client-side state like history or inlined figures.
742
788
743 The client sends a shutdown request to the kernel, and once it receives the
789 The client sends a shutdown request to the kernel, and once it receives the
744 reply message (which is otherwise empty), it can assume that the kernel has
790 reply message (which is otherwise empty), it can assume that the kernel has
745 completed shutdown safely.
791 completed shutdown safely.
746
792
747 Upon their own shutdown, client applications will typically execute a last
793 Upon their own shutdown, client applications will typically execute a last
748 minute sanity check and forcefully terminate any kernel that is still alive, to
794 minute sanity check and forcefully terminate any kernel that is still alive, to
749 avoid leaving stray processes in the user's machine.
795 avoid leaving stray processes in the user's machine.
750
796
751 Message type: ``shutdown_request``::
797 Message type: ``shutdown_request``::
752
798
753 content = {
799 content = {
754 'restart' : bool # whether the shutdown is final, or precedes a restart
800 'restart' : bool # whether the shutdown is final, or precedes a restart
755 }
801 }
756
802
757 Message type: ``shutdown_reply``::
803 Message type: ``shutdown_reply``::
758
804
759 content = {
805 content = {
760 'restart' : bool # whether the shutdown is final, or precedes a restart
806 'restart' : bool # whether the shutdown is final, or precedes a restart
761 }
807 }
762
808
763 .. Note::
809 .. Note::
764
810
765 When the clients detect a dead kernel thanks to inactivity on the heartbeat
811 When the clients detect a dead kernel thanks to inactivity on the heartbeat
766 socket, they simply send a forceful process termination signal, since a dead
812 socket, they simply send a forceful process termination signal, since a dead
767 process is unlikely to respond in any useful way to messages.
813 process is unlikely to respond in any useful way to messages.
768
814
769
815
770 Messages on the PUB/SUB socket
816 Messages on the PUB/SUB socket
771 ==============================
817 ==============================
772
818
773 Streams (stdout, stderr, etc)
819 Streams (stdout, stderr, etc)
774 ------------------------------
820 ------------------------------
775
821
776 Message type: ``stream``::
822 Message type: ``stream``::
777
823
778 content = {
824 content = {
779 # The name of the stream is one of 'stdout', 'stderr'
825 # The name of the stream is one of 'stdout', 'stderr'
780 'name' : str,
826 'name' : str,
781
827
782 # The text is an arbitrary string to be written to that stream
828 # The text is an arbitrary string to be written to that stream
783 'text' : str,
829 'text' : str,
784 }
830 }
785
831
786 .. versionchanged:: 5.0
832 .. versionchanged:: 5.0
787
833
788 'data' key renamed to 'text' for conistency with the notebook format.
834 'data' key renamed to 'text' for conistency with the notebook format.
789
835
790 Display Data
836 Display Data
791 ------------
837 ------------
792
838
793 This type of message is used to bring back data that should be displayed (text,
839 This type of message is used to bring back data that should be displayed (text,
794 html, svg, etc.) in the frontends. This data is published to all frontends.
840 html, svg, etc.) in the frontends. This data is published to all frontends.
795 Each message can have multiple representations of the data; it is up to the
841 Each message can have multiple representations of the data; it is up to the
796 frontend to decide which to use and how. A single message should contain all
842 frontend to decide which to use and how. A single message should contain all
797 possible representations of the same information. Each representation should
843 possible representations of the same information. Each representation should
798 be a JSON'able data structure, and should be a valid MIME type.
844 be a JSON'able data structure, and should be a valid MIME type.
799
845
800 Some questions remain about this design:
846 Some questions remain about this design:
801
847
802 * Do we use this message type for execute_result/displayhook? Probably not, because
848 * Do we use this message type for execute_result/displayhook? Probably not, because
803 the displayhook also has to handle the Out prompt display. On the other hand
849 the displayhook also has to handle the Out prompt display. On the other hand
804 we could put that information into the metadata section.
850 we could put that information into the metadata section.
805
851
806 .. _display_data:
852 .. _display_data:
807
853
808 Message type: ``display_data``::
854 Message type: ``display_data``::
809
855
810 content = {
856 content = {
811
857
812 # Who create the data
858 # Who create the data
813 'source' : str,
859 'source' : str,
814
860
815 # The data dict contains key/value pairs, where the keys are MIME
861 # The data dict contains key/value pairs, where the keys are MIME
816 # types and the values are the raw data of the representation in that
862 # types and the values are the raw data of the representation in that
817 # format.
863 # format.
818 'data' : dict,
864 'data' : dict,
819
865
820 # Any metadata that describes the data
866 # Any metadata that describes the data
821 'metadata' : dict
867 'metadata' : dict
822 }
868 }
823
869
824
870
825 The ``metadata`` contains any metadata that describes the output.
871 The ``metadata`` contains any metadata that describes the output.
826 Global keys are assumed to apply to the output as a whole.
872 Global keys are assumed to apply to the output as a whole.
827 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
873 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
828 which are interpreted as applying only to output of that type.
874 which are interpreted as applying only to output of that type.
829 Third parties should put any data they write into a single dict
875 Third parties should put any data they write into a single dict
830 with a reasonably unique name to avoid conflicts.
876 with a reasonably unique name to avoid conflicts.
831
877
832 The only metadata keys currently defined in IPython are the width and height
878 The only metadata keys currently defined in IPython are the width and height
833 of images::
879 of images::
834
880
835 metadata = {
881 metadata = {
836 'image/png' : {
882 'image/png' : {
837 'width': 640,
883 'width': 640,
838 'height': 480
884 'height': 480
839 }
885 }
840 }
886 }
841
887
842
888
843 .. versionchanged:: 5.0
889 .. versionchanged:: 5.0
844
890
845 `application/json` data should be unpacked JSON data,
891 `application/json` data should be unpacked JSON data,
846 not double-serialized as a JSON string.
892 not double-serialized as a JSON string.
847
893
848
894
849 Raw Data Publication
895 Raw Data Publication
850 --------------------
896 --------------------
851
897
852 ``display_data`` lets you publish *representations* of data, such as images and html.
898 ``display_data`` lets you publish *representations* of data, such as images and html.
853 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
899 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
854
900
855 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
901 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
856
902
857 .. sourcecode:: python
903 .. sourcecode:: python
858
904
859 from IPython.kernel.zmq.datapub import publish_data
905 from IPython.kernel.zmq.datapub import publish_data
860 ns = dict(x=my_array)
906 ns = dict(x=my_array)
861 publish_data(ns)
907 publish_data(ns)
862
908
863
909
864 Message type: ``data_pub``::
910 Message type: ``data_pub``::
865
911
866 content = {
912 content = {
867 # the keys of the data dict, after it has been unserialized
913 # the keys of the data dict, after it has been unserialized
868 'keys' : ['a', 'b']
914 'keys' : ['a', 'b']
869 }
915 }
870 # the namespace dict will be serialized in the message buffers,
916 # the namespace dict will be serialized in the message buffers,
871 # which will have a length of at least one
917 # which will have a length of at least one
872 buffers = [b'pdict', ...]
918 buffers = [b'pdict', ...]
873
919
874
920
875 The interpretation of a sequence of data_pub messages for a given parent request should be
921 The interpretation of a sequence of data_pub messages for a given parent request should be
876 to update a single namespace with subsequent results.
922 to update a single namespace with subsequent results.
877
923
878 .. note::
924 .. note::
879
925
880 No frontends directly handle data_pub messages at this time.
926 No frontends directly handle data_pub messages at this time.
881 It is currently only used by the client/engines in :mod:`IPython.parallel`,
927 It is currently only used by the client/engines in :mod:`IPython.parallel`,
882 where engines may publish *data* to the Client,
928 where engines may publish *data* to the Client,
883 of which the Client can then publish *representations* via ``display_data``
929 of which the Client can then publish *representations* via ``display_data``
884 to various frontends.
930 to various frontends.
885
931
886 Code inputs
932 Code inputs
887 -----------
933 -----------
888
934
889 To let all frontends know what code is being executed at any given time, these
935 To let all frontends know what code is being executed at any given time, these
890 messages contain a re-broadcast of the ``code`` portion of an
936 messages contain a re-broadcast of the ``code`` portion of an
891 :ref:`execute_request <execute>`, along with the :ref:`execution_count
937 :ref:`execute_request <execute>`, along with the :ref:`execution_count
892 <execution_counter>`.
938 <execution_counter>`.
893
939
894 Message type: ``execute_input``::
940 Message type: ``execute_input``::
895
941
896 content = {
942 content = {
897 'code' : str, # Source code to be executed, one or more lines
943 'code' : str, # Source code to be executed, one or more lines
898
944
899 # The counter for this execution is also provided so that clients can
945 # The counter for this execution is also provided so that clients can
900 # display it, since IPython automatically creates variables called _iN
946 # display it, since IPython automatically creates variables called _iN
901 # (for input prompt In[N]).
947 # (for input prompt In[N]).
902 'execution_count' : int
948 'execution_count' : int
903 }
949 }
904
950
905 .. versionchanged:: 5.0
951 .. versionchanged:: 5.0
906
952
907 ``pyin`` is renamed to ``execute_input``.
953 ``pyin`` is renamed to ``execute_input``.
908
954
909
955
910 Execution results
956 Execution results
911 -----------------
957 -----------------
912
958
913 Results of an execution are published as an ``execute_result``.
959 Results of an execution are published as an ``execute_result``.
914 These are identical to `display_data`_ messages, with the addition of an ``execution_count`` key.
960 These are identical to `display_data`_ messages, with the addition of an ``execution_count`` key.
915
961
916 Results can have multiple simultaneous formats depending on its
962 Results can have multiple simultaneous formats depending on its
917 configuration. A plain text representation should always be provided
963 configuration. A plain text representation should always be provided
918 in the ``text/plain`` mime-type. Frontends are free to display any or all of these
964 in the ``text/plain`` mime-type. Frontends are free to display any or all of these
919 according to its capabilities.
965 according to its capabilities.
920 Frontends should ignore mime-types they do not understand. The data itself is
966 Frontends should ignore mime-types they do not understand. The data itself is
921 any JSON object and depends on the format. It is often, but not always a string.
967 any JSON object and depends on the format. It is often, but not always a string.
922
968
923 Message type: ``execute_result``::
969 Message type: ``execute_result``::
924
970
925 content = {
971 content = {
926
972
927 # The counter for this execution is also provided so that clients can
973 # The counter for this execution is also provided so that clients can
928 # display it, since IPython automatically creates variables called _N
974 # display it, since IPython automatically creates variables called _N
929 # (for prompt N).
975 # (for prompt N).
930 'execution_count' : int,
976 'execution_count' : int,
931
977
932 # data and metadata are identical to a display_data message.
978 # data and metadata are identical to a display_data message.
933 # the object being displayed is that passed to the display hook,
979 # the object being displayed is that passed to the display hook,
934 # i.e. the *result* of the execution.
980 # i.e. the *result* of the execution.
935 'data' : dict,
981 'data' : dict,
936 'metadata' : dict,
982 'metadata' : dict,
937 }
983 }
938
984
939 Execution errors
985 Execution errors
940 ----------------
986 ----------------
941
987
942 When an error occurs during code execution
988 When an error occurs during code execution
943
989
944 Message type: ``error``::
990 Message type: ``error``::
945
991
946 content = {
992 content = {
947 # Similar content to the execute_reply messages for the 'error' case,
993 # Similar content to the execute_reply messages for the 'error' case,
948 # except the 'status' field is omitted.
994 # except the 'status' field is omitted.
949 }
995 }
950
996
951 .. versionchanged:: 5.0
997 .. versionchanged:: 5.0
952
998
953 ``pyerr`` renamed to ``error``
999 ``pyerr`` renamed to ``error``
954
1000
955 Kernel status
1001 Kernel status
956 -------------
1002 -------------
957
1003
958 This message type is used by frontends to monitor the status of the kernel.
1004 This message type is used by frontends to monitor the status of the kernel.
959
1005
960 Message type: ``status``::
1006 Message type: ``status``::
961
1007
962 content = {
1008 content = {
963 # When the kernel starts to handle a message, it will enter the 'busy'
1009 # When the kernel starts to handle a message, it will enter the 'busy'
964 # state and when it finishes, it will enter the 'idle' state.
1010 # state and when it finishes, it will enter the 'idle' state.
965 # The kernel will publish state 'starting' exactly once at process startup.
1011 # The kernel will publish state 'starting' exactly once at process startup.
966 execution_state : ('busy', 'idle', 'starting')
1012 execution_state : ('busy', 'idle', 'starting')
967 }
1013 }
968
1014
969 .. versionchanged:: 5.0
1015 .. versionchanged:: 5.0
970
1016
971 Busy and idle messages should be sent before/after handling every message,
1017 Busy and idle messages should be sent before/after handling every message,
972 not just execution.
1018 not just execution.
973
1019
974 Clear output
1020 Clear output
975 ------------
1021 ------------
976
1022
977 This message type is used to clear the output that is visible on the frontend.
1023 This message type is used to clear the output that is visible on the frontend.
978
1024
979 Message type: ``clear_output``::
1025 Message type: ``clear_output``::
980
1026
981 content = {
1027 content = {
982
1028
983 # Wait to clear the output until new output is available. Clears the
1029 # Wait to clear the output until new output is available. Clears the
984 # existing output immediately before the new output is displayed.
1030 # existing output immediately before the new output is displayed.
985 # Useful for creating simple animations with minimal flickering.
1031 # Useful for creating simple animations with minimal flickering.
986 'wait' : bool,
1032 'wait' : bool,
987 }
1033 }
988
1034
989 .. versionchanged:: 4.1
1035 .. versionchanged:: 4.1
990
1036
991 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
1037 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
992 and ``wait`` is added.
1038 and ``wait`` is added.
993 The selective clearing keys are ignored in v4 and the default behavior remains the same,
1039 The selective clearing keys are ignored in v4 and the default behavior remains the same,
994 so v4 clear_output messages will be safely handled by a v4.1 frontend.
1040 so v4 clear_output messages will be safely handled by a v4.1 frontend.
995
1041
996
1042
997 Messages on the stdin ROUTER/DEALER sockets
1043 Messages on the stdin ROUTER/DEALER sockets
998 ===========================================
1044 ===========================================
999
1045
1000 This is a socket where the request/reply pattern goes in the opposite direction:
1046 This is a socket where the request/reply pattern goes in the opposite direction:
1001 from the kernel to a *single* frontend, and its purpose is to allow
1047 from the kernel to a *single* frontend, and its purpose is to allow
1002 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
1048 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
1003 to be fulfilled by the client. The request should be made to the frontend that
1049 to be fulfilled by the client. The request should be made to the frontend that
1004 made the execution request that prompted ``raw_input`` to be called. For now we
1050 made the execution request that prompted ``raw_input`` to be called. For now we
1005 will keep these messages as simple as possible, since they only mean to convey
1051 will keep these messages as simple as possible, since they only mean to convey
1006 the ``raw_input(prompt)`` call.
1052 the ``raw_input(prompt)`` call.
1007
1053
1008 Message type: ``input_request``::
1054 Message type: ``input_request``::
1009
1055
1010 content = {
1056 content = {
1011 # the text to show at the prompt
1057 # the text to show at the prompt
1012 'prompt' : str,
1058 'prompt' : str,
1013 # Is the request for a password?
1059 # Is the request for a password?
1014 # If so, the frontend shouldn't echo input.
1060 # If so, the frontend shouldn't echo input.
1015 'password' : bool
1061 'password' : bool
1016 }
1062 }
1017
1063
1018 Message type: ``input_reply``::
1064 Message type: ``input_reply``::
1019
1065
1020 content = { 'value' : str }
1066 content = { 'value' : str }
1021
1067
1022
1068
1023 When ``password`` is True, the frontend should not echo the input as it is entered.
1069 When ``password`` is True, the frontend should not echo the input as it is entered.
1024
1070
1025 .. versionchanged:: 5.0
1071 .. versionchanged:: 5.0
1026
1072
1027 ``password`` key added.
1073 ``password`` key added.
1028
1074
1029 .. note::
1075 .. note::
1030
1076
1031 The stdin socket of the client is required to have the same zmq IDENTITY
1077 The stdin socket of the client is required to have the same zmq IDENTITY
1032 as the client's shell socket.
1078 as the client's shell socket.
1033 Because of this, the ``input_request`` must be sent with the same IDENTITY
1079 Because of this, the ``input_request`` must be sent with the same IDENTITY
1034 routing prefix as the ``execute_reply`` in order for the frontend to receive
1080 routing prefix as the ``execute_reply`` in order for the frontend to receive
1035 the message.
1081 the message.
1036
1082
1037 .. note::
1083 .. note::
1038
1084
1039 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
1085 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
1040 practice the kernel should behave like an interactive program. When a
1086 practice the kernel should behave like an interactive program. When a
1041 program is opened on the console, the keyboard effectively takes over the
1087 program is opened on the console, the keyboard effectively takes over the
1042 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
1088 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
1043 Since the IPython kernel effectively behaves like a console program (albeit
1089 Since the IPython kernel effectively behaves like a console program (albeit
1044 one whose "keyboard" is actually living in a separate process and
1090 one whose "keyboard" is actually living in a separate process and
1045 transported over the zmq connection), raw ``stdin`` isn't expected to be
1091 transported over the zmq connection), raw ``stdin`` isn't expected to be
1046 available.
1092 available.
1047
1093
1048 .. _kernel_heartbeat:
1094 .. _kernel_heartbeat:
1049
1095
1050 Heartbeat for kernels
1096 Heartbeat for kernels
1051 =====================
1097 =====================
1052
1098
1053 Clients send ping messages on a REQ socket, which are echoed right back
1099 Clients send ping messages on a REQ socket, which are echoed right back
1054 from the Kernel's REP socket. These are simple bytestrings, not full JSON messages described above.
1100 from the Kernel's REP socket. These are simple bytestrings, not full JSON messages described above.
1055
1101
1056
1102
1057 Custom Messages
1103 Custom Messages
1058 ===============
1104 ===============
1059
1105
1060 .. versionadded:: 4.1
1106 .. versionadded:: 4.1
1061
1107
1062 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
1108 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
1063 and Kernel-side components, and allow them to communicate with each other.
1109 and Kernel-side components, and allow them to communicate with each other.
1064 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
1110 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
1065 and can communicate in either direction.
1111 and can communicate in either direction.
1066
1112
1067 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
1113 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
1068 and no messages expect a reply.
1114 and no messages expect a reply.
1069 The Kernel listens for these messages on the Shell channel,
1115 The Kernel listens for these messages on the Shell channel,
1070 and the Frontend listens for them on the IOPub channel.
1116 and the Frontend listens for them on the IOPub channel.
1071
1117
1072 Opening a Comm
1118 Opening a Comm
1073 --------------
1119 --------------
1074
1120
1075 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1121 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1076
1122
1077 {
1123 {
1078 'comm_id' : 'u-u-i-d',
1124 'comm_id' : 'u-u-i-d',
1079 'target_name' : 'my_comm',
1125 'target_name' : 'my_comm',
1080 'data' : {}
1126 'data' : {}
1081 }
1127 }
1082
1128
1083 Every Comm has an ID and a target name.
1129 Every Comm has an ID and a target name.
1084 The code handling the message on the receiving side is responsible for maintaining a mapping
1130 The code handling the message on the receiving side is responsible for maintaining a mapping
1085 of target_name keys to constructors.
1131 of target_name keys to constructors.
1086 After a ``comm_open`` message has been sent,
1132 After a ``comm_open`` message has been sent,
1087 there should be a corresponding Comm instance on both sides.
1133 there should be a corresponding Comm instance on both sides.
1088 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1134 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1089
1135
1090 If the ``target_name`` key is not found on the receiving side,
1136 If the ``target_name`` key is not found on the receiving side,
1091 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1137 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1092
1138
1093 Comm Messages
1139 Comm Messages
1094 -------------
1140 -------------
1095
1141
1096 Comm messages are one-way communications to update comm state,
1142 Comm messages are one-way communications to update comm state,
1097 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1143 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1098
1144
1099 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1145 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1100
1146
1101 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1147 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1102
1148
1103 Message type: ``comm_msg``::
1149 Message type: ``comm_msg``::
1104
1150
1105 {
1151 {
1106 'comm_id' : 'u-u-i-d',
1152 'comm_id' : 'u-u-i-d',
1107 'data' : {}
1153 'data' : {}
1108 }
1154 }
1109
1155
1110 Tearing Down Comms
1156 Tearing Down Comms
1111 ------------------
1157 ------------------
1112
1158
1113 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1159 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1114 This is done with a ``comm_close`` message.
1160 This is done with a ``comm_close`` message.
1115
1161
1116 Message type: ``comm_close``::
1162 Message type: ``comm_close``::
1117
1163
1118 {
1164 {
1119 'comm_id' : 'u-u-i-d',
1165 'comm_id' : 'u-u-i-d',
1120 'data' : {}
1166 'data' : {}
1121 }
1167 }
1122
1168
1123 Output Side Effects
1169 Output Side Effects
1124 -------------------
1170 -------------------
1125
1171
1126 Since comm messages can execute arbitrary user code,
1172 Since comm messages can execute arbitrary user code,
1127 handlers should set the parent header and publish status busy / idle,
1173 handlers should set the parent header and publish status busy / idle,
1128 just like an execute request.
1174 just like an execute request.
1129
1175
1130
1176
1131 To Do
1177 To Do
1132 =====
1178 =====
1133
1179
1134 Missing things include:
1180 Missing things include:
1135
1181
1136 * Important: finish thinking through the payload concept and API.
1182 * Important: finish thinking through the payload concept and API.
1137
1183
1138 .. include:: ../links.txt
1184 .. include:: ../links.txt
General Comments 0
You need to be logged in to leave comments. Login now