##// END OF EJS Templates
Merge remote-tracking branch 'takluyver/history-request' into takluyver-history-request
Thomas Kluyver -
r3843:54f4e0bf merge
parent child Browse files
Show More
@@ -1,496 +1,496
1 """ A FrontendWidget that emulates the interface of the console IPython and
1 """ A FrontendWidget that emulates the interface of the console IPython and
2 supports the additional functionality provided by the IPython kernel.
2 supports the additional functionality provided by the IPython kernel.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Imports
6 # Imports
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Standard library imports
9 # Standard library imports
10 from collections import namedtuple
10 from collections import namedtuple
11 import os.path
11 import os.path
12 import re
12 import re
13 from subprocess import Popen
13 from subprocess import Popen
14 import sys
14 import sys
15 from textwrap import dedent
15 from textwrap import dedent
16
16
17 # System library imports
17 # System library imports
18 from IPython.external.qt import QtCore, QtGui
18 from IPython.external.qt import QtCore, QtGui
19
19
20 # Local imports
20 # Local imports
21 from IPython.core.inputsplitter import IPythonInputSplitter, \
21 from IPython.core.inputsplitter import IPythonInputSplitter, \
22 transform_ipy_prompt
22 transform_ipy_prompt
23 from IPython.core.usage import default_gui_banner
23 from IPython.core.usage import default_gui_banner
24 from IPython.utils.traitlets import Bool, Str, Unicode
24 from IPython.utils.traitlets import Bool, Str, Unicode
25 from frontend_widget import FrontendWidget
25 from frontend_widget import FrontendWidget
26 from styles import (default_light_style_sheet, default_light_syntax_style,
26 from styles import (default_light_style_sheet, default_light_syntax_style,
27 default_dark_style_sheet, default_dark_syntax_style,
27 default_dark_style_sheet, default_dark_syntax_style,
28 default_bw_style_sheet, default_bw_syntax_style)
28 default_bw_style_sheet, default_bw_syntax_style)
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Constants
31 # Constants
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 # Default strings to build and display input and output prompts (and separators
34 # Default strings to build and display input and output prompts (and separators
35 # in between)
35 # in between)
36 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
36 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
37 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
37 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
38 default_input_sep = '\n'
38 default_input_sep = '\n'
39 default_output_sep = ''
39 default_output_sep = ''
40 default_output_sep2 = ''
40 default_output_sep2 = ''
41
41
42 # Base path for most payload sources.
42 # Base path for most payload sources.
43 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
43 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # IPythonWidget class
46 # IPythonWidget class
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 class IPythonWidget(FrontendWidget):
49 class IPythonWidget(FrontendWidget):
50 """ A FrontendWidget for an IPython kernel.
50 """ A FrontendWidget for an IPython kernel.
51 """
51 """
52
52
53 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
53 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
54 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
54 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
55 # settings.
55 # settings.
56 custom_edit = Bool(False)
56 custom_edit = Bool(False)
57 custom_edit_requested = QtCore.Signal(object, object)
57 custom_edit_requested = QtCore.Signal(object, object)
58
58
59 # A command for invoking a system text editor. If the string contains a
59 # A command for invoking a system text editor. If the string contains a
60 # {filename} format specifier, it will be used. Otherwise, the filename will
60 # {filename} format specifier, it will be used. Otherwise, the filename will
61 # be appended to the end the command.
61 # be appended to the end the command.
62 editor = Unicode('default', config=True)
62 editor = Unicode('default', config=True)
63
63
64 # The editor command to use when a specific line number is requested. The
64 # The editor command to use when a specific line number is requested. The
65 # string should contain two format specifiers: {line} and {filename}. If
65 # string should contain two format specifiers: {line} and {filename}. If
66 # this parameter is not specified, the line number option to the %edit magic
66 # this parameter is not specified, the line number option to the %edit magic
67 # will be ignored.
67 # will be ignored.
68 editor_line = Unicode(config=True)
68 editor_line = Unicode(config=True)
69
69
70 # A CSS stylesheet. The stylesheet can contain classes for:
70 # A CSS stylesheet. The stylesheet can contain classes for:
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
74 style_sheet = Unicode(config=True)
74 style_sheet = Unicode(config=True)
75
75
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
77 # the style sheet is queried for Pygments style information.
77 # the style sheet is queried for Pygments style information.
78 syntax_style = Str(config=True)
78 syntax_style = Str(config=True)
79
79
80 # Prompts.
80 # Prompts.
81 in_prompt = Str(default_in_prompt, config=True)
81 in_prompt = Str(default_in_prompt, config=True)
82 out_prompt = Str(default_out_prompt, config=True)
82 out_prompt = Str(default_out_prompt, config=True)
83 input_sep = Str(default_input_sep, config=True)
83 input_sep = Str(default_input_sep, config=True)
84 output_sep = Str(default_output_sep, config=True)
84 output_sep = Str(default_output_sep, config=True)
85 output_sep2 = Str(default_output_sep2, config=True)
85 output_sep2 = Str(default_output_sep2, config=True)
86
86
87 # FrontendWidget protected class variables.
87 # FrontendWidget protected class variables.
88 _input_splitter_class = IPythonInputSplitter
88 _input_splitter_class = IPythonInputSplitter
89
89
90 # IPythonWidget protected class variables.
90 # IPythonWidget protected class variables.
91 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
91 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
92 _payload_source_edit = zmq_shell_source + '.edit_magic'
92 _payload_source_edit = zmq_shell_source + '.edit_magic'
93 _payload_source_exit = zmq_shell_source + '.ask_exit'
93 _payload_source_exit = zmq_shell_source + '.ask_exit'
94 _payload_source_loadpy = zmq_shell_source + '.magic_loadpy'
94 _payload_source_loadpy = zmq_shell_source + '.magic_loadpy'
95 _payload_source_page = 'IPython.zmq.page.page'
95 _payload_source_page = 'IPython.zmq.page.page'
96
96
97 #---------------------------------------------------------------------------
97 #---------------------------------------------------------------------------
98 # 'object' interface
98 # 'object' interface
99 #---------------------------------------------------------------------------
99 #---------------------------------------------------------------------------
100
100
101 def __init__(self, *args, **kw):
101 def __init__(self, *args, **kw):
102 super(IPythonWidget, self).__init__(*args, **kw)
102 super(IPythonWidget, self).__init__(*args, **kw)
103
103
104 # IPythonWidget protected variables.
104 # IPythonWidget protected variables.
105 self._code_to_load = None
105 self._code_to_load = None
106 self._payload_handlers = {
106 self._payload_handlers = {
107 self._payload_source_edit : self._handle_payload_edit,
107 self._payload_source_edit : self._handle_payload_edit,
108 self._payload_source_exit : self._handle_payload_exit,
108 self._payload_source_exit : self._handle_payload_exit,
109 self._payload_source_page : self._handle_payload_page,
109 self._payload_source_page : self._handle_payload_page,
110 self._payload_source_loadpy : self._handle_payload_loadpy }
110 self._payload_source_loadpy : self._handle_payload_loadpy }
111 self._previous_prompt_obj = None
111 self._previous_prompt_obj = None
112 self._keep_kernel_on_exit = None
112 self._keep_kernel_on_exit = None
113
113
114 # Initialize widget styling.
114 # Initialize widget styling.
115 if self.style_sheet:
115 if self.style_sheet:
116 self._style_sheet_changed()
116 self._style_sheet_changed()
117 self._syntax_style_changed()
117 self._syntax_style_changed()
118 else:
118 else:
119 self.set_default_style()
119 self.set_default_style()
120
120
121 #---------------------------------------------------------------------------
121 #---------------------------------------------------------------------------
122 # 'BaseFrontendMixin' abstract interface
122 # 'BaseFrontendMixin' abstract interface
123 #---------------------------------------------------------------------------
123 #---------------------------------------------------------------------------
124
124
125 def _handle_complete_reply(self, rep):
125 def _handle_complete_reply(self, rep):
126 """ Reimplemented to support IPython's improved completion machinery.
126 """ Reimplemented to support IPython's improved completion machinery.
127 """
127 """
128 cursor = self._get_cursor()
128 cursor = self._get_cursor()
129 info = self._request_info.get('complete')
129 info = self._request_info.get('complete')
130 if info and info.id == rep['parent_header']['msg_id'] and \
130 if info and info.id == rep['parent_header']['msg_id'] and \
131 info.pos == cursor.position():
131 info.pos == cursor.position():
132 matches = rep['content']['matches']
132 matches = rep['content']['matches']
133 text = rep['content']['matched_text']
133 text = rep['content']['matched_text']
134 offset = len(text)
134 offset = len(text)
135
135
136 # Clean up matches with period and path separators if the matched
136 # Clean up matches with period and path separators if the matched
137 # text has not been transformed. This is done by truncating all
137 # text has not been transformed. This is done by truncating all
138 # but the last component and then suitably decreasing the offset
138 # but the last component and then suitably decreasing the offset
139 # between the current cursor position and the start of completion.
139 # between the current cursor position and the start of completion.
140 if len(matches) > 1 and matches[0][:offset] == text:
140 if len(matches) > 1 and matches[0][:offset] == text:
141 parts = re.split(r'[./\\]', text)
141 parts = re.split(r'[./\\]', text)
142 sep_count = len(parts) - 1
142 sep_count = len(parts) - 1
143 if sep_count:
143 if sep_count:
144 chop_length = sum(map(len, parts[:sep_count])) + sep_count
144 chop_length = sum(map(len, parts[:sep_count])) + sep_count
145 matches = [ match[chop_length:] for match in matches ]
145 matches = [ match[chop_length:] for match in matches ]
146 offset -= chop_length
146 offset -= chop_length
147
147
148 # Move the cursor to the start of the match and complete.
148 # Move the cursor to the start of the match and complete.
149 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
149 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
150 self._complete_with_items(cursor, matches)
150 self._complete_with_items(cursor, matches)
151
151
152 def _handle_execute_reply(self, msg):
152 def _handle_execute_reply(self, msg):
153 """ Reimplemented to support prompt requests.
153 """ Reimplemented to support prompt requests.
154 """
154 """
155 info = self._request_info.get('execute')
155 info = self._request_info.get('execute')
156 if info and info.id == msg['parent_header']['msg_id']:
156 if info and info.id == msg['parent_header']['msg_id']:
157 if info.kind == 'prompt':
157 if info.kind == 'prompt':
158 number = msg['content']['execution_count'] + 1
158 number = msg['content']['execution_count'] + 1
159 self._show_interpreter_prompt(number)
159 self._show_interpreter_prompt(number)
160 else:
160 else:
161 super(IPythonWidget, self)._handle_execute_reply(msg)
161 super(IPythonWidget, self)._handle_execute_reply(msg)
162
162
163 def _handle_history_tail_reply(self, msg):
163 def _handle_history_reply(self, msg):
164 """ Implemented to handle history tail replies, which are only supported
164 """ Implemented to handle history tail replies, which are only supported
165 by the IPython kernel.
165 by the IPython kernel.
166 """
166 """
167 history_items = msg['content']['history']
167 history_items = msg['content']['history']
168 items = [ line.rstrip() for _, _, line in history_items ]
168 items = [ line.rstrip() for _, _, line in history_items ]
169 self._set_history(items)
169 self._set_history(items)
170
170
171 def _handle_pyout(self, msg):
171 def _handle_pyout(self, msg):
172 """ Reimplemented for IPython-style "display hook".
172 """ Reimplemented for IPython-style "display hook".
173 """
173 """
174 if not self._hidden and self._is_from_this_session(msg):
174 if not self._hidden and self._is_from_this_session(msg):
175 content = msg['content']
175 content = msg['content']
176 prompt_number = content['execution_count']
176 prompt_number = content['execution_count']
177 data = content['data']
177 data = content['data']
178 if data.has_key('text/html'):
178 if data.has_key('text/html'):
179 self._append_plain_text(self.output_sep)
179 self._append_plain_text(self.output_sep)
180 self._append_html(self._make_out_prompt(prompt_number))
180 self._append_html(self._make_out_prompt(prompt_number))
181 html = data['text/html']
181 html = data['text/html']
182 self._append_plain_text('\n')
182 self._append_plain_text('\n')
183 self._append_html(html + self.output_sep2)
183 self._append_html(html + self.output_sep2)
184 elif data.has_key('text/plain'):
184 elif data.has_key('text/plain'):
185 self._append_plain_text(self.output_sep)
185 self._append_plain_text(self.output_sep)
186 self._append_html(self._make_out_prompt(prompt_number))
186 self._append_html(self._make_out_prompt(prompt_number))
187 text = data['text/plain']
187 text = data['text/plain']
188 self._append_plain_text(text + self.output_sep2)
188 self._append_plain_text(text + self.output_sep2)
189
189
190 def _handle_display_data(self, msg):
190 def _handle_display_data(self, msg):
191 """ The base handler for the ``display_data`` message.
191 """ The base handler for the ``display_data`` message.
192 """
192 """
193 # For now, we don't display data from other frontends, but we
193 # For now, we don't display data from other frontends, but we
194 # eventually will as this allows all frontends to monitor the display
194 # eventually will as this allows all frontends to monitor the display
195 # data. But we need to figure out how to handle this in the GUI.
195 # data. But we need to figure out how to handle this in the GUI.
196 if not self._hidden and self._is_from_this_session(msg):
196 if not self._hidden and self._is_from_this_session(msg):
197 source = msg['content']['source']
197 source = msg['content']['source']
198 data = msg['content']['data']
198 data = msg['content']['data']
199 metadata = msg['content']['metadata']
199 metadata = msg['content']['metadata']
200 # In the regular IPythonWidget, we simply print the plain text
200 # In the regular IPythonWidget, we simply print the plain text
201 # representation.
201 # representation.
202 if data.has_key('text/html'):
202 if data.has_key('text/html'):
203 html = data['text/html']
203 html = data['text/html']
204 self._append_html(html)
204 self._append_html(html)
205 elif data.has_key('text/plain'):
205 elif data.has_key('text/plain'):
206 text = data['text/plain']
206 text = data['text/plain']
207 self._append_plain_text(text)
207 self._append_plain_text(text)
208 # This newline seems to be needed for text and html output.
208 # This newline seems to be needed for text and html output.
209 self._append_plain_text(u'\n')
209 self._append_plain_text(u'\n')
210
210
211 def _started_channels(self):
211 def _started_channels(self):
212 """ Reimplemented to make a history request.
212 """ Reimplemented to make a history request.
213 """
213 """
214 super(IPythonWidget, self)._started_channels()
214 super(IPythonWidget, self)._started_channels()
215 self.kernel_manager.xreq_channel.history_tail(1000)
215 self.kernel_manager.xreq_channel.history(hist_access_type='tail', n=1000)
216
216
217 #---------------------------------------------------------------------------
217 #---------------------------------------------------------------------------
218 # 'ConsoleWidget' public interface
218 # 'ConsoleWidget' public interface
219 #---------------------------------------------------------------------------
219 #---------------------------------------------------------------------------
220
220
221 def copy(self):
221 def copy(self):
222 """ Copy the currently selected text to the clipboard, removing prompts
222 """ Copy the currently selected text to the clipboard, removing prompts
223 if possible.
223 if possible.
224 """
224 """
225 text = self._control.textCursor().selection().toPlainText()
225 text = self._control.textCursor().selection().toPlainText()
226 if text:
226 if text:
227 lines = map(transform_ipy_prompt, text.splitlines())
227 lines = map(transform_ipy_prompt, text.splitlines())
228 text = '\n'.join(lines)
228 text = '\n'.join(lines)
229 QtGui.QApplication.clipboard().setText(text)
229 QtGui.QApplication.clipboard().setText(text)
230
230
231 #---------------------------------------------------------------------------
231 #---------------------------------------------------------------------------
232 # 'FrontendWidget' public interface
232 # 'FrontendWidget' public interface
233 #---------------------------------------------------------------------------
233 #---------------------------------------------------------------------------
234
234
235 def execute_file(self, path, hidden=False):
235 def execute_file(self, path, hidden=False):
236 """ Reimplemented to use the 'run' magic.
236 """ Reimplemented to use the 'run' magic.
237 """
237 """
238 # Use forward slashes on Windows to avoid escaping each separator.
238 # Use forward slashes on Windows to avoid escaping each separator.
239 if sys.platform == 'win32':
239 if sys.platform == 'win32':
240 path = os.path.normpath(path).replace('\\', '/')
240 path = os.path.normpath(path).replace('\\', '/')
241
241
242 self.execute('%%run %s' % path, hidden=hidden)
242 self.execute('%%run %s' % path, hidden=hidden)
243
243
244 #---------------------------------------------------------------------------
244 #---------------------------------------------------------------------------
245 # 'FrontendWidget' protected interface
245 # 'FrontendWidget' protected interface
246 #---------------------------------------------------------------------------
246 #---------------------------------------------------------------------------
247
247
248 def _complete(self):
248 def _complete(self):
249 """ Reimplemented to support IPython's improved completion machinery.
249 """ Reimplemented to support IPython's improved completion machinery.
250 """
250 """
251 # We let the kernel split the input line, so we *always* send an empty
251 # We let the kernel split the input line, so we *always* send an empty
252 # text field. Readline-based frontends do get a real text field which
252 # text field. Readline-based frontends do get a real text field which
253 # they can use.
253 # they can use.
254 text = ''
254 text = ''
255
255
256 # Send the completion request to the kernel
256 # Send the completion request to the kernel
257 msg_id = self.kernel_manager.xreq_channel.complete(
257 msg_id = self.kernel_manager.xreq_channel.complete(
258 text, # text
258 text, # text
259 self._get_input_buffer_cursor_line(), # line
259 self._get_input_buffer_cursor_line(), # line
260 self._get_input_buffer_cursor_column(), # cursor_pos
260 self._get_input_buffer_cursor_column(), # cursor_pos
261 self.input_buffer) # block
261 self.input_buffer) # block
262 pos = self._get_cursor().position()
262 pos = self._get_cursor().position()
263 info = self._CompletionRequest(msg_id, pos)
263 info = self._CompletionRequest(msg_id, pos)
264 self._request_info['complete'] = info
264 self._request_info['complete'] = info
265
265
266 def _get_banner(self):
266 def _get_banner(self):
267 """ Reimplemented to return IPython's default banner.
267 """ Reimplemented to return IPython's default banner.
268 """
268 """
269 return default_gui_banner
269 return default_gui_banner
270
270
271 def _process_execute_error(self, msg):
271 def _process_execute_error(self, msg):
272 """ Reimplemented for IPython-style traceback formatting.
272 """ Reimplemented for IPython-style traceback formatting.
273 """
273 """
274 content = msg['content']
274 content = msg['content']
275 traceback = '\n'.join(content['traceback']) + '\n'
275 traceback = '\n'.join(content['traceback']) + '\n'
276 if False:
276 if False:
277 # FIXME: For now, tracebacks come as plain text, so we can't use
277 # FIXME: For now, tracebacks come as plain text, so we can't use
278 # the html renderer yet. Once we refactor ultratb to produce
278 # the html renderer yet. Once we refactor ultratb to produce
279 # properly styled tracebacks, this branch should be the default
279 # properly styled tracebacks, this branch should be the default
280 traceback = traceback.replace(' ', '&nbsp;')
280 traceback = traceback.replace(' ', '&nbsp;')
281 traceback = traceback.replace('\n', '<br/>')
281 traceback = traceback.replace('\n', '<br/>')
282
282
283 ename = content['ename']
283 ename = content['ename']
284 ename_styled = '<span class="error">%s</span>' % ename
284 ename_styled = '<span class="error">%s</span>' % ename
285 traceback = traceback.replace(ename, ename_styled)
285 traceback = traceback.replace(ename, ename_styled)
286
286
287 self._append_html(traceback)
287 self._append_html(traceback)
288 else:
288 else:
289 # This is the fallback for now, using plain text with ansi escapes
289 # This is the fallback for now, using plain text with ansi escapes
290 self._append_plain_text(traceback)
290 self._append_plain_text(traceback)
291
291
292 def _process_execute_payload(self, item):
292 def _process_execute_payload(self, item):
293 """ Reimplemented to dispatch payloads to handler methods.
293 """ Reimplemented to dispatch payloads to handler methods.
294 """
294 """
295 handler = self._payload_handlers.get(item['source'])
295 handler = self._payload_handlers.get(item['source'])
296 if handler is None:
296 if handler is None:
297 # We have no handler for this type of payload, simply ignore it
297 # We have no handler for this type of payload, simply ignore it
298 return False
298 return False
299 else:
299 else:
300 handler(item)
300 handler(item)
301 return True
301 return True
302
302
303 def _show_interpreter_prompt(self, number=None):
303 def _show_interpreter_prompt(self, number=None):
304 """ Reimplemented for IPython-style prompts.
304 """ Reimplemented for IPython-style prompts.
305 """
305 """
306 # If a number was not specified, make a prompt number request.
306 # If a number was not specified, make a prompt number request.
307 if number is None:
307 if number is None:
308 msg_id = self.kernel_manager.xreq_channel.execute('', silent=True)
308 msg_id = self.kernel_manager.xreq_channel.execute('', silent=True)
309 info = self._ExecutionRequest(msg_id, 'prompt')
309 info = self._ExecutionRequest(msg_id, 'prompt')
310 self._request_info['execute'] = info
310 self._request_info['execute'] = info
311 return
311 return
312
312
313 # Show a new prompt and save information about it so that it can be
313 # Show a new prompt and save information about it so that it can be
314 # updated later if the prompt number turns out to be wrong.
314 # updated later if the prompt number turns out to be wrong.
315 self._prompt_sep = self.input_sep
315 self._prompt_sep = self.input_sep
316 self._show_prompt(self._make_in_prompt(number), html=True)
316 self._show_prompt(self._make_in_prompt(number), html=True)
317 block = self._control.document().lastBlock()
317 block = self._control.document().lastBlock()
318 length = len(self._prompt)
318 length = len(self._prompt)
319 self._previous_prompt_obj = self._PromptBlock(block, length, number)
319 self._previous_prompt_obj = self._PromptBlock(block, length, number)
320
320
321 # Update continuation prompt to reflect (possibly) new prompt length.
321 # Update continuation prompt to reflect (possibly) new prompt length.
322 self._set_continuation_prompt(
322 self._set_continuation_prompt(
323 self._make_continuation_prompt(self._prompt), html=True)
323 self._make_continuation_prompt(self._prompt), html=True)
324
324
325 # Load code from the %loadpy magic, if necessary.
325 # Load code from the %loadpy magic, if necessary.
326 if self._code_to_load is not None:
326 if self._code_to_load is not None:
327 self.input_buffer = dedent(self._code_to_load.rstrip())
327 self.input_buffer = dedent(self._code_to_load.rstrip())
328 self._code_to_load = None
328 self._code_to_load = None
329
329
330 def _show_interpreter_prompt_for_reply(self, msg):
330 def _show_interpreter_prompt_for_reply(self, msg):
331 """ Reimplemented for IPython-style prompts.
331 """ Reimplemented for IPython-style prompts.
332 """
332 """
333 # Update the old prompt number if necessary.
333 # Update the old prompt number if necessary.
334 content = msg['content']
334 content = msg['content']
335 previous_prompt_number = content['execution_count']
335 previous_prompt_number = content['execution_count']
336 if self._previous_prompt_obj and \
336 if self._previous_prompt_obj and \
337 self._previous_prompt_obj.number != previous_prompt_number:
337 self._previous_prompt_obj.number != previous_prompt_number:
338 block = self._previous_prompt_obj.block
338 block = self._previous_prompt_obj.block
339
339
340 # Make sure the prompt block has not been erased.
340 # Make sure the prompt block has not been erased.
341 if block.isValid() and block.text():
341 if block.isValid() and block.text():
342
342
343 # Remove the old prompt and insert a new prompt.
343 # Remove the old prompt and insert a new prompt.
344 cursor = QtGui.QTextCursor(block)
344 cursor = QtGui.QTextCursor(block)
345 cursor.movePosition(QtGui.QTextCursor.Right,
345 cursor.movePosition(QtGui.QTextCursor.Right,
346 QtGui.QTextCursor.KeepAnchor,
346 QtGui.QTextCursor.KeepAnchor,
347 self._previous_prompt_obj.length)
347 self._previous_prompt_obj.length)
348 prompt = self._make_in_prompt(previous_prompt_number)
348 prompt = self._make_in_prompt(previous_prompt_number)
349 self._prompt = self._insert_html_fetching_plain_text(
349 self._prompt = self._insert_html_fetching_plain_text(
350 cursor, prompt)
350 cursor, prompt)
351
351
352 # When the HTML is inserted, Qt blows away the syntax
352 # When the HTML is inserted, Qt blows away the syntax
353 # highlighting for the line, so we need to rehighlight it.
353 # highlighting for the line, so we need to rehighlight it.
354 self._highlighter.rehighlightBlock(cursor.block())
354 self._highlighter.rehighlightBlock(cursor.block())
355
355
356 self._previous_prompt_obj = None
356 self._previous_prompt_obj = None
357
357
358 # Show a new prompt with the kernel's estimated prompt number.
358 # Show a new prompt with the kernel's estimated prompt number.
359 self._show_interpreter_prompt(previous_prompt_number + 1)
359 self._show_interpreter_prompt(previous_prompt_number + 1)
360
360
361 #---------------------------------------------------------------------------
361 #---------------------------------------------------------------------------
362 # 'IPythonWidget' interface
362 # 'IPythonWidget' interface
363 #---------------------------------------------------------------------------
363 #---------------------------------------------------------------------------
364
364
365 def set_default_style(self, colors='lightbg'):
365 def set_default_style(self, colors='lightbg'):
366 """ Sets the widget style to the class defaults.
366 """ Sets the widget style to the class defaults.
367
367
368 Parameters:
368 Parameters:
369 -----------
369 -----------
370 colors : str, optional (default lightbg)
370 colors : str, optional (default lightbg)
371 Whether to use the default IPython light background or dark
371 Whether to use the default IPython light background or dark
372 background or B&W style.
372 background or B&W style.
373 """
373 """
374 colors = colors.lower()
374 colors = colors.lower()
375 if colors=='lightbg':
375 if colors=='lightbg':
376 self.style_sheet = default_light_style_sheet
376 self.style_sheet = default_light_style_sheet
377 self.syntax_style = default_light_syntax_style
377 self.syntax_style = default_light_syntax_style
378 elif colors=='linux':
378 elif colors=='linux':
379 self.style_sheet = default_dark_style_sheet
379 self.style_sheet = default_dark_style_sheet
380 self.syntax_style = default_dark_syntax_style
380 self.syntax_style = default_dark_syntax_style
381 elif colors=='nocolor':
381 elif colors=='nocolor':
382 self.style_sheet = default_bw_style_sheet
382 self.style_sheet = default_bw_style_sheet
383 self.syntax_style = default_bw_syntax_style
383 self.syntax_style = default_bw_syntax_style
384 else:
384 else:
385 raise KeyError("No such color scheme: %s"%colors)
385 raise KeyError("No such color scheme: %s"%colors)
386
386
387 #---------------------------------------------------------------------------
387 #---------------------------------------------------------------------------
388 # 'IPythonWidget' protected interface
388 # 'IPythonWidget' protected interface
389 #---------------------------------------------------------------------------
389 #---------------------------------------------------------------------------
390
390
391 def _edit(self, filename, line=None):
391 def _edit(self, filename, line=None):
392 """ Opens a Python script for editing.
392 """ Opens a Python script for editing.
393
393
394 Parameters:
394 Parameters:
395 -----------
395 -----------
396 filename : str
396 filename : str
397 A path to a local system file.
397 A path to a local system file.
398
398
399 line : int, optional
399 line : int, optional
400 A line of interest in the file.
400 A line of interest in the file.
401 """
401 """
402 if self.custom_edit:
402 if self.custom_edit:
403 self.custom_edit_requested.emit(filename, line)
403 self.custom_edit_requested.emit(filename, line)
404 elif self.editor == 'default':
404 elif self.editor == 'default':
405 self._append_plain_text('No default editor available.\n')
405 self._append_plain_text('No default editor available.\n')
406 else:
406 else:
407 try:
407 try:
408 filename = '"%s"' % filename
408 filename = '"%s"' % filename
409 if line and self.editor_line:
409 if line and self.editor_line:
410 command = self.editor_line.format(filename=filename,
410 command = self.editor_line.format(filename=filename,
411 line=line)
411 line=line)
412 else:
412 else:
413 try:
413 try:
414 command = self.editor.format()
414 command = self.editor.format()
415 except KeyError:
415 except KeyError:
416 command = self.editor.format(filename=filename)
416 command = self.editor.format(filename=filename)
417 else:
417 else:
418 command += ' ' + filename
418 command += ' ' + filename
419 except KeyError:
419 except KeyError:
420 self._append_plain_text('Invalid editor command.\n')
420 self._append_plain_text('Invalid editor command.\n')
421 else:
421 else:
422 try:
422 try:
423 Popen(command, shell=True)
423 Popen(command, shell=True)
424 except OSError:
424 except OSError:
425 msg = 'Opening editor with command "%s" failed.\n'
425 msg = 'Opening editor with command "%s" failed.\n'
426 self._append_plain_text(msg % command)
426 self._append_plain_text(msg % command)
427
427
428 def _make_in_prompt(self, number):
428 def _make_in_prompt(self, number):
429 """ Given a prompt number, returns an HTML In prompt.
429 """ Given a prompt number, returns an HTML In prompt.
430 """
430 """
431 body = self.in_prompt % number
431 body = self.in_prompt % number
432 return '<span class="in-prompt">%s</span>' % body
432 return '<span class="in-prompt">%s</span>' % body
433
433
434 def _make_continuation_prompt(self, prompt):
434 def _make_continuation_prompt(self, prompt):
435 """ Given a plain text version of an In prompt, returns an HTML
435 """ Given a plain text version of an In prompt, returns an HTML
436 continuation prompt.
436 continuation prompt.
437 """
437 """
438 end_chars = '...: '
438 end_chars = '...: '
439 space_count = len(prompt.lstrip('\n')) - len(end_chars)
439 space_count = len(prompt.lstrip('\n')) - len(end_chars)
440 body = '&nbsp;' * space_count + end_chars
440 body = '&nbsp;' * space_count + end_chars
441 return '<span class="in-prompt">%s</span>' % body
441 return '<span class="in-prompt">%s</span>' % body
442
442
443 def _make_out_prompt(self, number):
443 def _make_out_prompt(self, number):
444 """ Given a prompt number, returns an HTML Out prompt.
444 """ Given a prompt number, returns an HTML Out prompt.
445 """
445 """
446 body = self.out_prompt % number
446 body = self.out_prompt % number
447 return '<span class="out-prompt">%s</span>' % body
447 return '<span class="out-prompt">%s</span>' % body
448
448
449 #------ Payload handlers --------------------------------------------------
449 #------ Payload handlers --------------------------------------------------
450
450
451 # Payload handlers with a generic interface: each takes the opaque payload
451 # Payload handlers with a generic interface: each takes the opaque payload
452 # dict, unpacks it and calls the underlying functions with the necessary
452 # dict, unpacks it and calls the underlying functions with the necessary
453 # arguments.
453 # arguments.
454
454
455 def _handle_payload_edit(self, item):
455 def _handle_payload_edit(self, item):
456 self._edit(item['filename'], item['line_number'])
456 self._edit(item['filename'], item['line_number'])
457
457
458 def _handle_payload_exit(self, item):
458 def _handle_payload_exit(self, item):
459 self._keep_kernel_on_exit = item['keepkernel']
459 self._keep_kernel_on_exit = item['keepkernel']
460 self.exit_requested.emit()
460 self.exit_requested.emit()
461
461
462 def _handle_payload_loadpy(self, item):
462 def _handle_payload_loadpy(self, item):
463 # Simple save the text of the .py file for later. The text is written
463 # Simple save the text of the .py file for later. The text is written
464 # to the buffer when _prompt_started_hook is called.
464 # to the buffer when _prompt_started_hook is called.
465 self._code_to_load = item['text']
465 self._code_to_load = item['text']
466
466
467 def _handle_payload_page(self, item):
467 def _handle_payload_page(self, item):
468 # Since the plain text widget supports only a very small subset of HTML
468 # Since the plain text widget supports only a very small subset of HTML
469 # and we have no control over the HTML source, we only page HTML
469 # and we have no control over the HTML source, we only page HTML
470 # payloads in the rich text widget.
470 # payloads in the rich text widget.
471 if item['html'] and self.kind == 'rich':
471 if item['html'] and self.kind == 'rich':
472 self._page(item['html'], html=True)
472 self._page(item['html'], html=True)
473 else:
473 else:
474 self._page(item['text'], html=False)
474 self._page(item['text'], html=False)
475
475
476 #------ Trait change handlers --------------------------------------------
476 #------ Trait change handlers --------------------------------------------
477
477
478 def _style_sheet_changed(self):
478 def _style_sheet_changed(self):
479 """ Set the style sheets of the underlying widgets.
479 """ Set the style sheets of the underlying widgets.
480 """
480 """
481 self.setStyleSheet(self.style_sheet)
481 self.setStyleSheet(self.style_sheet)
482 self._control.document().setDefaultStyleSheet(self.style_sheet)
482 self._control.document().setDefaultStyleSheet(self.style_sheet)
483 if self._page_control:
483 if self._page_control:
484 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
484 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
485
485
486 bg_color = self._control.palette().window().color()
486 bg_color = self._control.palette().window().color()
487 self._ansi_processor.set_background_color(bg_color)
487 self._ansi_processor.set_background_color(bg_color)
488
488
489 def _syntax_style_changed(self):
489 def _syntax_style_changed(self):
490 """ Set the style for the syntax highlighter.
490 """ Set the style for the syntax highlighter.
491 """
491 """
492 if self.syntax_style:
492 if self.syntax_style:
493 self._highlighter.set_style(self.syntax_style)
493 self._highlighter.set_style(self.syntax_style)
494 else:
494 else:
495 self._highlighter.set_style_sheet(self.style_sheet)
495 self._highlighter.set_style_sheet(self.style_sheet)
496
496
@@ -1,243 +1,243
1 """ Defines a KernelManager that provides signals and slots.
1 """ Defines a KernelManager that provides signals and slots.
2 """
2 """
3
3
4 # System library imports.
4 # System library imports.
5 from IPython.external.qt import QtCore
5 from IPython.external.qt import QtCore
6
6
7 # IPython imports.
7 # IPython imports.
8 from IPython.utils.traitlets import Type
8 from IPython.utils.traitlets import Type
9 from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
9 from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
10 XReqSocketChannel, RepSocketChannel, HBSocketChannel
10 XReqSocketChannel, RepSocketChannel, HBSocketChannel
11 from util import MetaQObjectHasTraits, SuperQObject
11 from util import MetaQObjectHasTraits, SuperQObject
12
12
13
13
14 class SocketChannelQObject(SuperQObject):
14 class SocketChannelQObject(SuperQObject):
15
15
16 # Emitted when the channel is started.
16 # Emitted when the channel is started.
17 started = QtCore.Signal()
17 started = QtCore.Signal()
18
18
19 # Emitted when the channel is stopped.
19 # Emitted when the channel is stopped.
20 stopped = QtCore.Signal()
20 stopped = QtCore.Signal()
21
21
22 #---------------------------------------------------------------------------
22 #---------------------------------------------------------------------------
23 # 'ZmqSocketChannel' interface
23 # 'ZmqSocketChannel' interface
24 #---------------------------------------------------------------------------
24 #---------------------------------------------------------------------------
25
25
26 def start(self):
26 def start(self):
27 """ Reimplemented to emit signal.
27 """ Reimplemented to emit signal.
28 """
28 """
29 super(SocketChannelQObject, self).start()
29 super(SocketChannelQObject, self).start()
30 self.started.emit()
30 self.started.emit()
31
31
32 def stop(self):
32 def stop(self):
33 """ Reimplemented to emit signal.
33 """ Reimplemented to emit signal.
34 """
34 """
35 super(SocketChannelQObject, self).stop()
35 super(SocketChannelQObject, self).stop()
36 self.stopped.emit()
36 self.stopped.emit()
37
37
38
38
39 class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
39 class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
40
40
41 # Emitted when any message is received.
41 # Emitted when any message is received.
42 message_received = QtCore.Signal(object)
42 message_received = QtCore.Signal(object)
43
43
44 # Emitted when a reply has been received for the corresponding request
44 # Emitted when a reply has been received for the corresponding request
45 # type.
45 # type.
46 execute_reply = QtCore.Signal(object)
46 execute_reply = QtCore.Signal(object)
47 complete_reply = QtCore.Signal(object)
47 complete_reply = QtCore.Signal(object)
48 object_info_reply = QtCore.Signal(object)
48 object_info_reply = QtCore.Signal(object)
49 history_tail_reply = QtCore.Signal(object)
49 history_reply = QtCore.Signal(object)
50
50
51 # Emitted when the first reply comes back.
51 # Emitted when the first reply comes back.
52 first_reply = QtCore.Signal()
52 first_reply = QtCore.Signal()
53
53
54 # Used by the first_reply signal logic to determine if a reply is the
54 # Used by the first_reply signal logic to determine if a reply is the
55 # first.
55 # first.
56 _handlers_called = False
56 _handlers_called = False
57
57
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59 # 'XReqSocketChannel' interface
59 # 'XReqSocketChannel' interface
60 #---------------------------------------------------------------------------
60 #---------------------------------------------------------------------------
61
61
62 def call_handlers(self, msg):
62 def call_handlers(self, msg):
63 """ Reimplemented to emit signals instead of making callbacks.
63 """ Reimplemented to emit signals instead of making callbacks.
64 """
64 """
65 # Emit the generic signal.
65 # Emit the generic signal.
66 self.message_received.emit(msg)
66 self.message_received.emit(msg)
67
67
68 # Emit signals for specialized message types.
68 # Emit signals for specialized message types.
69 msg_type = msg['msg_type']
69 msg_type = msg['msg_type']
70 signal = getattr(self, msg_type, None)
70 signal = getattr(self, msg_type, None)
71 if signal:
71 if signal:
72 signal.emit(msg)
72 signal.emit(msg)
73
73
74 if not self._handlers_called:
74 if not self._handlers_called:
75 self.first_reply.emit()
75 self.first_reply.emit()
76 self._handlers_called = True
76 self._handlers_called = True
77
77
78 #---------------------------------------------------------------------------
78 #---------------------------------------------------------------------------
79 # 'QtXReqSocketChannel' interface
79 # 'QtXReqSocketChannel' interface
80 #---------------------------------------------------------------------------
80 #---------------------------------------------------------------------------
81
81
82 def reset_first_reply(self):
82 def reset_first_reply(self):
83 """ Reset the first_reply signal to fire again on the next reply.
83 """ Reset the first_reply signal to fire again on the next reply.
84 """
84 """
85 self._handlers_called = False
85 self._handlers_called = False
86
86
87
87
88 class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
88 class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
89
89
90 # Emitted when any message is received.
90 # Emitted when any message is received.
91 message_received = QtCore.Signal(object)
91 message_received = QtCore.Signal(object)
92
92
93 # Emitted when a message of type 'stream' is received.
93 # Emitted when a message of type 'stream' is received.
94 stream_received = QtCore.Signal(object)
94 stream_received = QtCore.Signal(object)
95
95
96 # Emitted when a message of type 'pyin' is received.
96 # Emitted when a message of type 'pyin' is received.
97 pyin_received = QtCore.Signal(object)
97 pyin_received = QtCore.Signal(object)
98
98
99 # Emitted when a message of type 'pyout' is received.
99 # Emitted when a message of type 'pyout' is received.
100 pyout_received = QtCore.Signal(object)
100 pyout_received = QtCore.Signal(object)
101
101
102 # Emitted when a message of type 'pyerr' is received.
102 # Emitted when a message of type 'pyerr' is received.
103 pyerr_received = QtCore.Signal(object)
103 pyerr_received = QtCore.Signal(object)
104
104
105 # Emitted when a message of type 'display_data' is received
105 # Emitted when a message of type 'display_data' is received
106 display_data_received = QtCore.Signal(object)
106 display_data_received = QtCore.Signal(object)
107
107
108 # Emitted when a crash report message is received from the kernel's
108 # Emitted when a crash report message is received from the kernel's
109 # last-resort sys.excepthook.
109 # last-resort sys.excepthook.
110 crash_received = QtCore.Signal(object)
110 crash_received = QtCore.Signal(object)
111
111
112 # Emitted when a shutdown is noticed.
112 # Emitted when a shutdown is noticed.
113 shutdown_reply_received = QtCore.Signal(object)
113 shutdown_reply_received = QtCore.Signal(object)
114
114
115 #---------------------------------------------------------------------------
115 #---------------------------------------------------------------------------
116 # 'SubSocketChannel' interface
116 # 'SubSocketChannel' interface
117 #---------------------------------------------------------------------------
117 #---------------------------------------------------------------------------
118
118
119 def call_handlers(self, msg):
119 def call_handlers(self, msg):
120 """ Reimplemented to emit signals instead of making callbacks.
120 """ Reimplemented to emit signals instead of making callbacks.
121 """
121 """
122 # Emit the generic signal.
122 # Emit the generic signal.
123 self.message_received.emit(msg)
123 self.message_received.emit(msg)
124 # Emit signals for specialized message types.
124 # Emit signals for specialized message types.
125 msg_type = msg['msg_type']
125 msg_type = msg['msg_type']
126 signal = getattr(self, msg_type + '_received', None)
126 signal = getattr(self, msg_type + '_received', None)
127 if signal:
127 if signal:
128 signal.emit(msg)
128 signal.emit(msg)
129 elif msg_type in ('stdout', 'stderr'):
129 elif msg_type in ('stdout', 'stderr'):
130 self.stream_received.emit(msg)
130 self.stream_received.emit(msg)
131
131
132 def flush(self):
132 def flush(self):
133 """ Reimplemented to ensure that signals are dispatched immediately.
133 """ Reimplemented to ensure that signals are dispatched immediately.
134 """
134 """
135 super(QtSubSocketChannel, self).flush()
135 super(QtSubSocketChannel, self).flush()
136 QtCore.QCoreApplication.instance().processEvents()
136 QtCore.QCoreApplication.instance().processEvents()
137
137
138
138
139 class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
139 class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
140
140
141 # Emitted when any message is received.
141 # Emitted when any message is received.
142 message_received = QtCore.Signal(object)
142 message_received = QtCore.Signal(object)
143
143
144 # Emitted when an input request is received.
144 # Emitted when an input request is received.
145 input_requested = QtCore.Signal(object)
145 input_requested = QtCore.Signal(object)
146
146
147 #---------------------------------------------------------------------------
147 #---------------------------------------------------------------------------
148 # 'RepSocketChannel' interface
148 # 'RepSocketChannel' interface
149 #---------------------------------------------------------------------------
149 #---------------------------------------------------------------------------
150
150
151 def call_handlers(self, msg):
151 def call_handlers(self, msg):
152 """ Reimplemented to emit signals instead of making callbacks.
152 """ Reimplemented to emit signals instead of making callbacks.
153 """
153 """
154 # Emit the generic signal.
154 # Emit the generic signal.
155 self.message_received.emit(msg)
155 self.message_received.emit(msg)
156
156
157 # Emit signals for specialized message types.
157 # Emit signals for specialized message types.
158 msg_type = msg['msg_type']
158 msg_type = msg['msg_type']
159 if msg_type == 'input_request':
159 if msg_type == 'input_request':
160 self.input_requested.emit(msg)
160 self.input_requested.emit(msg)
161
161
162
162
163 class QtHBSocketChannel(SocketChannelQObject, HBSocketChannel):
163 class QtHBSocketChannel(SocketChannelQObject, HBSocketChannel):
164
164
165 # Emitted when the kernel has died.
165 # Emitted when the kernel has died.
166 kernel_died = QtCore.Signal(object)
166 kernel_died = QtCore.Signal(object)
167
167
168 #---------------------------------------------------------------------------
168 #---------------------------------------------------------------------------
169 # 'HBSocketChannel' interface
169 # 'HBSocketChannel' interface
170 #---------------------------------------------------------------------------
170 #---------------------------------------------------------------------------
171
171
172 def call_handlers(self, since_last_heartbeat):
172 def call_handlers(self, since_last_heartbeat):
173 """ Reimplemented to emit signals instead of making callbacks.
173 """ Reimplemented to emit signals instead of making callbacks.
174 """
174 """
175 # Emit the generic signal.
175 # Emit the generic signal.
176 self.kernel_died.emit(since_last_heartbeat)
176 self.kernel_died.emit(since_last_heartbeat)
177
177
178
178
179 class QtKernelManager(KernelManager, SuperQObject):
179 class QtKernelManager(KernelManager, SuperQObject):
180 """ A KernelManager that provides signals and slots.
180 """ A KernelManager that provides signals and slots.
181 """
181 """
182
182
183 __metaclass__ = MetaQObjectHasTraits
183 __metaclass__ = MetaQObjectHasTraits
184
184
185 # Emitted when the kernel manager has started listening.
185 # Emitted when the kernel manager has started listening.
186 started_channels = QtCore.Signal()
186 started_channels = QtCore.Signal()
187
187
188 # Emitted when the kernel manager has stopped listening.
188 # Emitted when the kernel manager has stopped listening.
189 stopped_channels = QtCore.Signal()
189 stopped_channels = QtCore.Signal()
190
190
191 # Use Qt-specific channel classes that emit signals.
191 # Use Qt-specific channel classes that emit signals.
192 sub_channel_class = Type(QtSubSocketChannel)
192 sub_channel_class = Type(QtSubSocketChannel)
193 xreq_channel_class = Type(QtXReqSocketChannel)
193 xreq_channel_class = Type(QtXReqSocketChannel)
194 rep_channel_class = Type(QtRepSocketChannel)
194 rep_channel_class = Type(QtRepSocketChannel)
195 hb_channel_class = Type(QtHBSocketChannel)
195 hb_channel_class = Type(QtHBSocketChannel)
196
196
197 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
198 # 'KernelManager' interface
198 # 'KernelManager' interface
199 #---------------------------------------------------------------------------
199 #---------------------------------------------------------------------------
200
200
201 #------ Kernel process management ------------------------------------------
201 #------ Kernel process management ------------------------------------------
202
202
203 def start_kernel(self, *args, **kw):
203 def start_kernel(self, *args, **kw):
204 """ Reimplemented for proper heartbeat management.
204 """ Reimplemented for proper heartbeat management.
205 """
205 """
206 if self._xreq_channel is not None:
206 if self._xreq_channel is not None:
207 self._xreq_channel.reset_first_reply()
207 self._xreq_channel.reset_first_reply()
208 super(QtKernelManager, self).start_kernel(*args, **kw)
208 super(QtKernelManager, self).start_kernel(*args, **kw)
209
209
210 #------ Channel management -------------------------------------------------
210 #------ Channel management -------------------------------------------------
211
211
212 def start_channels(self, *args, **kw):
212 def start_channels(self, *args, **kw):
213 """ Reimplemented to emit signal.
213 """ Reimplemented to emit signal.
214 """
214 """
215 super(QtKernelManager, self).start_channels(*args, **kw)
215 super(QtKernelManager, self).start_channels(*args, **kw)
216 self.started_channels.emit()
216 self.started_channels.emit()
217
217
218 def stop_channels(self):
218 def stop_channels(self):
219 """ Reimplemented to emit signal.
219 """ Reimplemented to emit signal.
220 """
220 """
221 super(QtKernelManager, self).stop_channels()
221 super(QtKernelManager, self).stop_channels()
222 self.stopped_channels.emit()
222 self.stopped_channels.emit()
223
223
224 @property
224 @property
225 def xreq_channel(self):
225 def xreq_channel(self):
226 """ Reimplemented for proper heartbeat management.
226 """ Reimplemented for proper heartbeat management.
227 """
227 """
228 if self._xreq_channel is None:
228 if self._xreq_channel is None:
229 self._xreq_channel = super(QtKernelManager, self).xreq_channel
229 self._xreq_channel = super(QtKernelManager, self).xreq_channel
230 self._xreq_channel.first_reply.connect(self._first_reply)
230 self._xreq_channel.first_reply.connect(self._first_reply)
231 return self._xreq_channel
231 return self._xreq_channel
232
232
233 #---------------------------------------------------------------------------
233 #---------------------------------------------------------------------------
234 # Protected interface
234 # Protected interface
235 #---------------------------------------------------------------------------
235 #---------------------------------------------------------------------------
236
236
237 def _first_reply(self):
237 def _first_reply(self):
238 """ Unpauses the heartbeat channel when the first reply is received on
238 """ Unpauses the heartbeat channel when the first reply is received on
239 the execute channel. Note that this will *not* start the heartbeat
239 the execute channel. Note that this will *not* start the heartbeat
240 channel if it is not already running!
240 channel if it is not already running!
241 """
241 """
242 if self._hb_channel is not None:
242 if self._hb_channel is not None:
243 self._hb_channel.unpause()
243 self._hb_channel.unpause()
@@ -1,662 +1,679
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.utils import io
30 from IPython.utils import io
31 from IPython.utils.jsonutil import json_clean
31 from IPython.utils.jsonutil import json_clean
32 from IPython.lib import pylabtools
32 from IPython.lib import pylabtools
33 from IPython.utils.traitlets import Instance, Float
33 from IPython.utils.traitlets import Instance, Float
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
35 start_kernel)
35 start_kernel)
36 from iostream import OutStream
36 from iostream import OutStream
37 from session import Session, Message
37 from session import Session, Message
38 from zmqshell import ZMQInteractiveShell
38 from zmqshell import ZMQInteractiveShell
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Globals
41 # Globals
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 # Module-level logger
44 # Module-level logger
45 logger = logging.getLogger(__name__)
45 logger = logging.getLogger(__name__)
46
46
47 # FIXME: this needs to be done more cleanly later, once we have proper
47 # FIXME: this needs to be done more cleanly later, once we have proper
48 # configuration support. This is a library, so it shouldn't set a stream
48 # configuration support. This is a library, so it shouldn't set a stream
49 # handler, see:
49 # handler, see:
50 # http://docs.python.org/library/logging.html#configuring-logging-for-a-library
50 # http://docs.python.org/library/logging.html#configuring-logging-for-a-library
51 # But this lets us at least do developer debugging for now by manually turning
51 # But this lets us at least do developer debugging for now by manually turning
52 # it on/off. And once we have full config support, the client entry points
52 # it on/off. And once we have full config support, the client entry points
53 # will select their logging handlers, as well as passing to this library the
53 # will select their logging handlers, as well as passing to this library the
54 # logging level.
54 # logging level.
55
55
56 if 0: # dbg - set to 1 to actually see the messages.
56 if 0: # dbg - set to 1 to actually see the messages.
57 logger.addHandler(logging.StreamHandler())
57 logger.addHandler(logging.StreamHandler())
58 logger.setLevel(logging.DEBUG)
58 logger.setLevel(logging.DEBUG)
59
59
60 # /FIXME
60 # /FIXME
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Main kernel class
63 # Main kernel class
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 class Kernel(Configurable):
66 class Kernel(Configurable):
67
67
68 #---------------------------------------------------------------------------
68 #---------------------------------------------------------------------------
69 # Kernel interface
69 # Kernel interface
70 #---------------------------------------------------------------------------
70 #---------------------------------------------------------------------------
71
71
72 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
72 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
73 session = Instance(Session)
73 session = Instance(Session)
74 reply_socket = Instance('zmq.Socket')
74 reply_socket = Instance('zmq.Socket')
75 pub_socket = Instance('zmq.Socket')
75 pub_socket = Instance('zmq.Socket')
76 req_socket = Instance('zmq.Socket')
76 req_socket = Instance('zmq.Socket')
77
77
78 # Private interface
78 # Private interface
79
79
80 # Time to sleep after flushing the stdout/err buffers in each execute
80 # Time to sleep after flushing the stdout/err buffers in each execute
81 # cycle. While this introduces a hard limit on the minimal latency of the
81 # cycle. While this introduces a hard limit on the minimal latency of the
82 # execute cycle, it helps prevent output synchronization problems for
82 # execute cycle, it helps prevent output synchronization problems for
83 # clients.
83 # clients.
84 # Units are in seconds. The minimum zmq latency on local host is probably
84 # Units are in seconds. The minimum zmq latency on local host is probably
85 # ~150 microseconds, set this to 500us for now. We may need to increase it
85 # ~150 microseconds, set this to 500us for now. We may need to increase it
86 # a little if it's not enough after more interactive testing.
86 # a little if it's not enough after more interactive testing.
87 _execute_sleep = Float(0.0005, config=True)
87 _execute_sleep = Float(0.0005, config=True)
88
88
89 # Frequency of the kernel's event loop.
89 # Frequency of the kernel's event loop.
90 # Units are in seconds, kernel subclasses for GUI toolkits may need to
90 # Units are in seconds, kernel subclasses for GUI toolkits may need to
91 # adapt to milliseconds.
91 # adapt to milliseconds.
92 _poll_interval = Float(0.05, config=True)
92 _poll_interval = Float(0.05, config=True)
93
93
94 # If the shutdown was requested over the network, we leave here the
94 # If the shutdown was requested over the network, we leave here the
95 # necessary reply message so it can be sent by our registered atexit
95 # necessary reply message so it can be sent by our registered atexit
96 # handler. This ensures that the reply is only sent to clients truly at
96 # handler. This ensures that the reply is only sent to clients truly at
97 # the end of our shutdown process (which happens after the underlying
97 # the end of our shutdown process (which happens after the underlying
98 # IPython shell's own shutdown).
98 # IPython shell's own shutdown).
99 _shutdown_message = None
99 _shutdown_message = None
100
100
101 # This is a dict of port number that the kernel is listening on. It is set
101 # This is a dict of port number that the kernel is listening on. It is set
102 # by record_ports and used by connect_request.
102 # by record_ports and used by connect_request.
103 _recorded_ports = None
103 _recorded_ports = None
104
104
105
105
106 def __init__(self, **kwargs):
106 def __init__(self, **kwargs):
107 super(Kernel, self).__init__(**kwargs)
107 super(Kernel, self).__init__(**kwargs)
108
108
109 # Before we even start up the shell, register *first* our exit handlers
109 # Before we even start up the shell, register *first* our exit handlers
110 # so they come before the shell's
110 # so they come before the shell's
111 atexit.register(self._at_shutdown)
111 atexit.register(self._at_shutdown)
112
112
113 # Initialize the InteractiveShell subclass
113 # Initialize the InteractiveShell subclass
114 self.shell = ZMQInteractiveShell.instance()
114 self.shell = ZMQInteractiveShell.instance()
115 self.shell.displayhook.session = self.session
115 self.shell.displayhook.session = self.session
116 self.shell.displayhook.pub_socket = self.pub_socket
116 self.shell.displayhook.pub_socket = self.pub_socket
117 self.shell.display_pub.session = self.session
117 self.shell.display_pub.session = self.session
118 self.shell.display_pub.pub_socket = self.pub_socket
118 self.shell.display_pub.pub_socket = self.pub_socket
119
119
120 # TMP - hack while developing
120 # TMP - hack while developing
121 self.shell._reply_content = None
121 self.shell._reply_content = None
122
122
123 # Build dict of handlers for message types
123 # Build dict of handlers for message types
124 msg_types = [ 'execute_request', 'complete_request',
124 msg_types = [ 'execute_request', 'complete_request',
125 'object_info_request', 'history_tail_request',
125 'object_info_request', 'history_request',
126 'connect_request', 'shutdown_request']
126 'connect_request', 'shutdown_request']
127 self.handlers = {}
127 self.handlers = {}
128 for msg_type in msg_types:
128 for msg_type in msg_types:
129 self.handlers[msg_type] = getattr(self, msg_type)
129 self.handlers[msg_type] = getattr(self, msg_type)
130
130
131 def do_one_iteration(self):
131 def do_one_iteration(self):
132 """Do one iteration of the kernel's evaluation loop.
132 """Do one iteration of the kernel's evaluation loop.
133 """
133 """
134 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
134 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
135 if msg is None:
135 if msg is None:
136 return
136 return
137
137
138 # This assert will raise in versions of zeromq 2.0.7 and lesser.
138 # This assert will raise in versions of zeromq 2.0.7 and lesser.
139 # We now require 2.0.8 or above, so we can uncomment for safety.
139 # We now require 2.0.8 or above, so we can uncomment for safety.
140 # print(ident,msg, file=sys.__stdout__)
140 # print(ident,msg, file=sys.__stdout__)
141 assert ident is not None, "Missing message part."
141 assert ident is not None, "Missing message part."
142
142
143 # Print some info about this message and leave a '--->' marker, so it's
143 # Print some info about this message and leave a '--->' marker, so it's
144 # easier to trace visually the message chain when debugging. Each
144 # easier to trace visually the message chain when debugging. Each
145 # handler prints its message at the end.
145 # handler prints its message at the end.
146 # Eventually we'll move these from stdout to a logger.
146 # Eventually we'll move these from stdout to a logger.
147 logger.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***')
147 logger.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***')
148 logger.debug(' Content: '+str(msg['content'])+'\n --->\n ')
148 logger.debug(' Content: '+str(msg['content'])+'\n --->\n ')
149
149
150 # Find and call actual handler for message
150 # Find and call actual handler for message
151 handler = self.handlers.get(msg['msg_type'], None)
151 handler = self.handlers.get(msg['msg_type'], None)
152 if handler is None:
152 if handler is None:
153 logger.error("UNKNOWN MESSAGE TYPE:" +str(msg))
153 logger.error("UNKNOWN MESSAGE TYPE:" +str(msg))
154 else:
154 else:
155 handler(ident, msg)
155 handler(ident, msg)
156
156
157 # Check whether we should exit, in case the incoming message set the
157 # Check whether we should exit, in case the incoming message set the
158 # exit flag on
158 # exit flag on
159 if self.shell.exit_now:
159 if self.shell.exit_now:
160 logger.debug('\nExiting IPython kernel...')
160 logger.debug('\nExiting IPython kernel...')
161 # We do a normal, clean exit, which allows any actions registered
161 # We do a normal, clean exit, which allows any actions registered
162 # via atexit (such as history saving) to take place.
162 # via atexit (such as history saving) to take place.
163 sys.exit(0)
163 sys.exit(0)
164
164
165
165
166 def start(self):
166 def start(self):
167 """ Start the kernel main loop.
167 """ Start the kernel main loop.
168 """
168 """
169 while True:
169 while True:
170 time.sleep(self._poll_interval)
170 time.sleep(self._poll_interval)
171 self.do_one_iteration()
171 self.do_one_iteration()
172
172
173 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
173 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
174 """Record the ports that this kernel is using.
174 """Record the ports that this kernel is using.
175
175
176 The creator of the Kernel instance must call this methods if they
176 The creator of the Kernel instance must call this methods if they
177 want the :meth:`connect_request` method to return the port numbers.
177 want the :meth:`connect_request` method to return the port numbers.
178 """
178 """
179 self._recorded_ports = {
179 self._recorded_ports = {
180 'xrep_port' : xrep_port,
180 'xrep_port' : xrep_port,
181 'pub_port' : pub_port,
181 'pub_port' : pub_port,
182 'req_port' : req_port,
182 'req_port' : req_port,
183 'hb_port' : hb_port
183 'hb_port' : hb_port
184 }
184 }
185
185
186 #---------------------------------------------------------------------------
186 #---------------------------------------------------------------------------
187 # Kernel request handlers
187 # Kernel request handlers
188 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
189
189
190 def _publish_pyin(self, code, parent):
190 def _publish_pyin(self, code, parent):
191 """Publish the code request on the pyin stream."""
191 """Publish the code request on the pyin stream."""
192
192
193 pyin_msg = self.session.send(self.pub_socket, u'pyin',{u'code':code}, parent=parent)
193 pyin_msg = self.session.send(self.pub_socket, u'pyin',{u'code':code}, parent=parent)
194
194
195 def execute_request(self, ident, parent):
195 def execute_request(self, ident, parent):
196
196
197 status_msg = self.session.send(self.pub_socket,
197 status_msg = self.session.send(self.pub_socket,
198 u'status',
198 u'status',
199 {u'execution_state':u'busy'},
199 {u'execution_state':u'busy'},
200 parent=parent
200 parent=parent
201 )
201 )
202
202
203 try:
203 try:
204 content = parent[u'content']
204 content = parent[u'content']
205 code = content[u'code']
205 code = content[u'code']
206 silent = content[u'silent']
206 silent = content[u'silent']
207 except:
207 except:
208 logger.error("Got bad msg: ")
208 logger.error("Got bad msg: ")
209 logger.error(str(Message(parent)))
209 logger.error(str(Message(parent)))
210 return
210 return
211
211
212 shell = self.shell # we'll need this a lot here
212 shell = self.shell # we'll need this a lot here
213
213
214 # Replace raw_input. Note that is not sufficient to replace
214 # Replace raw_input. Note that is not sufficient to replace
215 # raw_input in the user namespace.
215 # raw_input in the user namespace.
216 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
216 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
217 __builtin__.raw_input = raw_input
217 __builtin__.raw_input = raw_input
218
218
219 # Set the parent message of the display hook and out streams.
219 # Set the parent message of the display hook and out streams.
220 shell.displayhook.set_parent(parent)
220 shell.displayhook.set_parent(parent)
221 shell.display_pub.set_parent(parent)
221 shell.display_pub.set_parent(parent)
222 sys.stdout.set_parent(parent)
222 sys.stdout.set_parent(parent)
223 sys.stderr.set_parent(parent)
223 sys.stderr.set_parent(parent)
224
224
225 # Re-broadcast our input for the benefit of listening clients, and
225 # Re-broadcast our input for the benefit of listening clients, and
226 # start computing output
226 # start computing output
227 if not silent:
227 if not silent:
228 self._publish_pyin(code, parent)
228 self._publish_pyin(code, parent)
229
229
230 reply_content = {}
230 reply_content = {}
231 try:
231 try:
232 if silent:
232 if silent:
233 # run_code uses 'exec' mode, so no displayhook will fire, and it
233 # run_code uses 'exec' mode, so no displayhook will fire, and it
234 # doesn't call logging or history manipulations. Print
234 # doesn't call logging or history manipulations. Print
235 # statements in that code will obviously still execute.
235 # statements in that code will obviously still execute.
236 shell.run_code(code)
236 shell.run_code(code)
237 else:
237 else:
238 # FIXME: the shell calls the exception handler itself.
238 # FIXME: the shell calls the exception handler itself.
239 shell._reply_content = None
239 shell._reply_content = None
240 shell.run_cell(code)
240 shell.run_cell(code)
241 except:
241 except:
242 status = u'error'
242 status = u'error'
243 # FIXME: this code right now isn't being used yet by default,
243 # FIXME: this code right now isn't being used yet by default,
244 # because the run_cell() call above directly fires off exception
244 # because the run_cell() call above directly fires off exception
245 # reporting. This code, therefore, is only active in the scenario
245 # reporting. This code, therefore, is only active in the scenario
246 # where runlines itself has an unhandled exception. We need to
246 # where runlines itself has an unhandled exception. We need to
247 # uniformize this, for all exception construction to come from a
247 # uniformize this, for all exception construction to come from a
248 # single location in the codbase.
248 # single location in the codbase.
249 etype, evalue, tb = sys.exc_info()
249 etype, evalue, tb = sys.exc_info()
250 tb_list = traceback.format_exception(etype, evalue, tb)
250 tb_list = traceback.format_exception(etype, evalue, tb)
251 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
251 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
252 else:
252 else:
253 status = u'ok'
253 status = u'ok'
254
254
255 reply_content[u'status'] = status
255 reply_content[u'status'] = status
256
256
257 # Return the execution counter so clients can display prompts
257 # Return the execution counter so clients can display prompts
258 reply_content['execution_count'] = shell.execution_count -1
258 reply_content['execution_count'] = shell.execution_count -1
259
259
260 # FIXME - fish exception info out of shell, possibly left there by
260 # FIXME - fish exception info out of shell, possibly left there by
261 # runlines. We'll need to clean up this logic later.
261 # runlines. We'll need to clean up this logic later.
262 if shell._reply_content is not None:
262 if shell._reply_content is not None:
263 reply_content.update(shell._reply_content)
263 reply_content.update(shell._reply_content)
264
264
265 # At this point, we can tell whether the main code execution succeeded
265 # At this point, we can tell whether the main code execution succeeded
266 # or not. If it did, we proceed to evaluate user_variables/expressions
266 # or not. If it did, we proceed to evaluate user_variables/expressions
267 if reply_content['status'] == 'ok':
267 if reply_content['status'] == 'ok':
268 reply_content[u'user_variables'] = \
268 reply_content[u'user_variables'] = \
269 shell.user_variables(content[u'user_variables'])
269 shell.user_variables(content[u'user_variables'])
270 reply_content[u'user_expressions'] = \
270 reply_content[u'user_expressions'] = \
271 shell.user_expressions(content[u'user_expressions'])
271 shell.user_expressions(content[u'user_expressions'])
272 else:
272 else:
273 # If there was an error, don't even try to compute variables or
273 # If there was an error, don't even try to compute variables or
274 # expressions
274 # expressions
275 reply_content[u'user_variables'] = {}
275 reply_content[u'user_variables'] = {}
276 reply_content[u'user_expressions'] = {}
276 reply_content[u'user_expressions'] = {}
277
277
278 # Payloads should be retrieved regardless of outcome, so we can both
278 # Payloads should be retrieved regardless of outcome, so we can both
279 # recover partial output (that could have been generated early in a
279 # recover partial output (that could have been generated early in a
280 # block, before an error) and clear the payload system always.
280 # block, before an error) and clear the payload system always.
281 reply_content[u'payload'] = shell.payload_manager.read_payload()
281 reply_content[u'payload'] = shell.payload_manager.read_payload()
282 # Be agressive about clearing the payload because we don't want
282 # Be agressive about clearing the payload because we don't want
283 # it to sit in memory until the next execute_request comes in.
283 # it to sit in memory until the next execute_request comes in.
284 shell.payload_manager.clear_payload()
284 shell.payload_manager.clear_payload()
285
285
286 # Flush output before sending the reply.
286 # Flush output before sending the reply.
287 sys.stdout.flush()
287 sys.stdout.flush()
288 sys.stderr.flush()
288 sys.stderr.flush()
289 # FIXME: on rare occasions, the flush doesn't seem to make it to the
289 # FIXME: on rare occasions, the flush doesn't seem to make it to the
290 # clients... This seems to mitigate the problem, but we definitely need
290 # clients... This seems to mitigate the problem, but we definitely need
291 # to better understand what's going on.
291 # to better understand what's going on.
292 if self._execute_sleep:
292 if self._execute_sleep:
293 time.sleep(self._execute_sleep)
293 time.sleep(self._execute_sleep)
294
294
295 # Send the reply.
295 # Send the reply.
296 reply_msg = self.session.send(self.reply_socket, u'execute_reply',
296 reply_msg = self.session.send(self.reply_socket, u'execute_reply',
297 reply_content, parent, ident=ident)
297 reply_content, parent, ident=ident)
298 logger.debug(str(reply_msg))
298 logger.debug(str(reply_msg))
299
299
300 if reply_msg['content']['status'] == u'error':
300 if reply_msg['content']['status'] == u'error':
301 self._abort_queue()
301 self._abort_queue()
302
302
303 status_msg = self.session.send(self.pub_socket,
303 status_msg = self.session.send(self.pub_socket,
304 u'status',
304 u'status',
305 {u'execution_state':u'idle'},
305 {u'execution_state':u'idle'},
306 parent=parent
306 parent=parent
307 )
307 )
308
308
309 def complete_request(self, ident, parent):
309 def complete_request(self, ident, parent):
310 txt, matches = self._complete(parent)
310 txt, matches = self._complete(parent)
311 matches = {'matches' : matches,
311 matches = {'matches' : matches,
312 'matched_text' : txt,
312 'matched_text' : txt,
313 'status' : 'ok'}
313 'status' : 'ok'}
314 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
314 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
315 matches, parent, ident)
315 matches, parent, ident)
316 logger.debug(str(completion_msg))
316 logger.debug(str(completion_msg))
317
317
318 def object_info_request(self, ident, parent):
318 def object_info_request(self, ident, parent):
319 object_info = self.shell.object_inspect(parent['content']['oname'])
319 object_info = self.shell.object_inspect(parent['content']['oname'])
320 # Before we send this object over, we scrub it for JSON usage
320 # Before we send this object over, we scrub it for JSON usage
321 oinfo = json_clean(object_info)
321 oinfo = json_clean(object_info)
322 msg = self.session.send(self.reply_socket, 'object_info_reply',
322 msg = self.session.send(self.reply_socket, 'object_info_reply',
323 oinfo, parent, ident)
323 oinfo, parent, ident)
324 logger.debug(msg)
324 logger.debug(msg)
325
325
326 def history_tail_request(self, ident, parent):
326 def history_request(self, ident, parent):
327 # We need to pull these out, as passing **kwargs doesn't work with
327 # We need to pull these out, as passing **kwargs doesn't work with
328 # unicode keys before Python 2.6.5.
328 # unicode keys before Python 2.6.5.
329 n = parent['content']['n']
329 hist_access_type = parent['content']['hist_access_type']
330 raw = parent['content']['raw']
330 raw = parent['content']['raw']
331 output = parent['content']['output']
331 output = parent['content']['output']
332 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output)
332 if hist_access_type == 'tail':
333 n = parent['content']['n']
334 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
335 include_latest=True)
336
337 elif hist_access_type == 'range':
338 session = parent['content']['session']
339 start = parent['content']['start']
340 stop = parent['content']['stop']
341 hist = self.shell.history_manager.get_range(session, start, stop,
342 raw=raw, output=output)
343
344 elif hist_access_type == 'search':
345 pattern = parent['content']['pattern']
346 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
347
348 else:
349 hist = []
333 content = {'history' : list(hist)}
350 content = {'history' : list(hist)}
334 msg = self.session.send(self.reply_socket, 'history_tail_reply',
351 msg = self.session.send(self.reply_socket, 'history_reply',
335 content, parent, ident)
352 content, parent, ident)
336 logger.debug(str(msg))
353 logger.debug(str(msg))
337
354
338 def connect_request(self, ident, parent):
355 def connect_request(self, ident, parent):
339 if self._recorded_ports is not None:
356 if self._recorded_ports is not None:
340 content = self._recorded_ports.copy()
357 content = self._recorded_ports.copy()
341 else:
358 else:
342 content = {}
359 content = {}
343 msg = self.session.send(self.reply_socket, 'connect_reply',
360 msg = self.session.send(self.reply_socket, 'connect_reply',
344 content, parent, ident)
361 content, parent, ident)
345 logger.debug(msg)
362 logger.debug(msg)
346
363
347 def shutdown_request(self, ident, parent):
364 def shutdown_request(self, ident, parent):
348 self.shell.exit_now = True
365 self.shell.exit_now = True
349 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
366 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
350 sys.exit(0)
367 sys.exit(0)
351
368
352 #---------------------------------------------------------------------------
369 #---------------------------------------------------------------------------
353 # Protected interface
370 # Protected interface
354 #---------------------------------------------------------------------------
371 #---------------------------------------------------------------------------
355
372
356 def _abort_queue(self):
373 def _abort_queue(self):
357 while True:
374 while True:
358 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
375 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
359 if msg is None:
376 if msg is None:
360 break
377 break
361 else:
378 else:
362 assert ident is not None, \
379 assert ident is not None, \
363 "Unexpected missing message part."
380 "Unexpected missing message part."
364
381
365 logger.debug("Aborting:\n"+str(Message(msg)))
382 logger.debug("Aborting:\n"+str(Message(msg)))
366 msg_type = msg['msg_type']
383 msg_type = msg['msg_type']
367 reply_type = msg_type.split('_')[0] + '_reply'
384 reply_type = msg_type.split('_')[0] + '_reply'
368 reply_msg = self.session.send(self.reply_socket, reply_type,
385 reply_msg = self.session.send(self.reply_socket, reply_type,
369 {'status' : 'aborted'}, msg, ident=ident)
386 {'status' : 'aborted'}, msg, ident=ident)
370 logger.debug(reply_msg)
387 logger.debug(reply_msg)
371 # We need to wait a bit for requests to come in. This can probably
388 # We need to wait a bit for requests to come in. This can probably
372 # be set shorter for true asynchronous clients.
389 # be set shorter for true asynchronous clients.
373 time.sleep(0.1)
390 time.sleep(0.1)
374
391
375 def _raw_input(self, prompt, ident, parent):
392 def _raw_input(self, prompt, ident, parent):
376 # Flush output before making the request.
393 # Flush output before making the request.
377 sys.stderr.flush()
394 sys.stderr.flush()
378 sys.stdout.flush()
395 sys.stdout.flush()
379
396
380 # Send the input request.
397 # Send the input request.
381 content = dict(prompt=prompt)
398 content = dict(prompt=prompt)
382 msg = self.session.send(self.req_socket, u'input_request', content, parent)
399 msg = self.session.send(self.req_socket, u'input_request', content, parent)
383
400
384 # Await a response.
401 # Await a response.
385 ident, reply = self.session.recv(self.req_socket, 0)
402 ident, reply = self.session.recv(self.req_socket, 0)
386 try:
403 try:
387 value = reply['content']['value']
404 value = reply['content']['value']
388 except:
405 except:
389 logger.error("Got bad raw_input reply: ")
406 logger.error("Got bad raw_input reply: ")
390 logger.error(str(Message(parent)))
407 logger.error(str(Message(parent)))
391 value = ''
408 value = ''
392 return value
409 return value
393
410
394 def _complete(self, msg):
411 def _complete(self, msg):
395 c = msg['content']
412 c = msg['content']
396 try:
413 try:
397 cpos = int(c['cursor_pos'])
414 cpos = int(c['cursor_pos'])
398 except:
415 except:
399 # If we don't get something that we can convert to an integer, at
416 # If we don't get something that we can convert to an integer, at
400 # least attempt the completion guessing the cursor is at the end of
417 # least attempt the completion guessing the cursor is at the end of
401 # the text, if there's any, and otherwise of the line
418 # the text, if there's any, and otherwise of the line
402 cpos = len(c['text'])
419 cpos = len(c['text'])
403 if cpos==0:
420 if cpos==0:
404 cpos = len(c['line'])
421 cpos = len(c['line'])
405 return self.shell.complete(c['text'], c['line'], cpos)
422 return self.shell.complete(c['text'], c['line'], cpos)
406
423
407 def _object_info(self, context):
424 def _object_info(self, context):
408 symbol, leftover = self._symbol_from_context(context)
425 symbol, leftover = self._symbol_from_context(context)
409 if symbol is not None and not leftover:
426 if symbol is not None and not leftover:
410 doc = getattr(symbol, '__doc__', '')
427 doc = getattr(symbol, '__doc__', '')
411 else:
428 else:
412 doc = ''
429 doc = ''
413 object_info = dict(docstring = doc)
430 object_info = dict(docstring = doc)
414 return object_info
431 return object_info
415
432
416 def _symbol_from_context(self, context):
433 def _symbol_from_context(self, context):
417 if not context:
434 if not context:
418 return None, context
435 return None, context
419
436
420 base_symbol_string = context[0]
437 base_symbol_string = context[0]
421 symbol = self.shell.user_ns.get(base_symbol_string, None)
438 symbol = self.shell.user_ns.get(base_symbol_string, None)
422 if symbol is None:
439 if symbol is None:
423 symbol = __builtin__.__dict__.get(base_symbol_string, None)
440 symbol = __builtin__.__dict__.get(base_symbol_string, None)
424 if symbol is None:
441 if symbol is None:
425 return None, context
442 return None, context
426
443
427 context = context[1:]
444 context = context[1:]
428 for i, name in enumerate(context):
445 for i, name in enumerate(context):
429 new_symbol = getattr(symbol, name, None)
446 new_symbol = getattr(symbol, name, None)
430 if new_symbol is None:
447 if new_symbol is None:
431 return symbol, context[i:]
448 return symbol, context[i:]
432 else:
449 else:
433 symbol = new_symbol
450 symbol = new_symbol
434
451
435 return symbol, []
452 return symbol, []
436
453
437 def _at_shutdown(self):
454 def _at_shutdown(self):
438 """Actions taken at shutdown by the kernel, called by python's atexit.
455 """Actions taken at shutdown by the kernel, called by python's atexit.
439 """
456 """
440 # io.rprint("Kernel at_shutdown") # dbg
457 # io.rprint("Kernel at_shutdown") # dbg
441 if self._shutdown_message is not None:
458 if self._shutdown_message is not None:
442 self.session.send(self.reply_socket, self._shutdown_message)
459 self.session.send(self.reply_socket, self._shutdown_message)
443 self.session.send(self.pub_socket, self._shutdown_message)
460 self.session.send(self.pub_socket, self._shutdown_message)
444 logger.debug(str(self._shutdown_message))
461 logger.debug(str(self._shutdown_message))
445 # A very short sleep to give zmq time to flush its message buffers
462 # A very short sleep to give zmq time to flush its message buffers
446 # before Python truly shuts down.
463 # before Python truly shuts down.
447 time.sleep(0.01)
464 time.sleep(0.01)
448
465
449
466
450 class QtKernel(Kernel):
467 class QtKernel(Kernel):
451 """A Kernel subclass with Qt support."""
468 """A Kernel subclass with Qt support."""
452
469
453 def start(self):
470 def start(self):
454 """Start a kernel with QtPy4 event loop integration."""
471 """Start a kernel with QtPy4 event loop integration."""
455
472
456 from PyQt4 import QtCore
473 from PyQt4 import QtCore
457 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
474 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
458
475
459 self.app = get_app_qt4([" "])
476 self.app = get_app_qt4([" "])
460 self.app.setQuitOnLastWindowClosed(False)
477 self.app.setQuitOnLastWindowClosed(False)
461 self.timer = QtCore.QTimer()
478 self.timer = QtCore.QTimer()
462 self.timer.timeout.connect(self.do_one_iteration)
479 self.timer.timeout.connect(self.do_one_iteration)
463 # Units for the timer are in milliseconds
480 # Units for the timer are in milliseconds
464 self.timer.start(1000*self._poll_interval)
481 self.timer.start(1000*self._poll_interval)
465 start_event_loop_qt4(self.app)
482 start_event_loop_qt4(self.app)
466
483
467
484
468 class WxKernel(Kernel):
485 class WxKernel(Kernel):
469 """A Kernel subclass with Wx support."""
486 """A Kernel subclass with Wx support."""
470
487
471 def start(self):
488 def start(self):
472 """Start a kernel with wx event loop support."""
489 """Start a kernel with wx event loop support."""
473
490
474 import wx
491 import wx
475 from IPython.lib.guisupport import start_event_loop_wx
492 from IPython.lib.guisupport import start_event_loop_wx
476
493
477 doi = self.do_one_iteration
494 doi = self.do_one_iteration
478 # Wx uses milliseconds
495 # Wx uses milliseconds
479 poll_interval = int(1000*self._poll_interval)
496 poll_interval = int(1000*self._poll_interval)
480
497
481 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
498 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
482 # We make the Frame hidden when we create it in the main app below.
499 # We make the Frame hidden when we create it in the main app below.
483 class TimerFrame(wx.Frame):
500 class TimerFrame(wx.Frame):
484 def __init__(self, func):
501 def __init__(self, func):
485 wx.Frame.__init__(self, None, -1)
502 wx.Frame.__init__(self, None, -1)
486 self.timer = wx.Timer(self)
503 self.timer = wx.Timer(self)
487 # Units for the timer are in milliseconds
504 # Units for the timer are in milliseconds
488 self.timer.Start(poll_interval)
505 self.timer.Start(poll_interval)
489 self.Bind(wx.EVT_TIMER, self.on_timer)
506 self.Bind(wx.EVT_TIMER, self.on_timer)
490 self.func = func
507 self.func = func
491
508
492 def on_timer(self, event):
509 def on_timer(self, event):
493 self.func()
510 self.func()
494
511
495 # We need a custom wx.App to create our Frame subclass that has the
512 # We need a custom wx.App to create our Frame subclass that has the
496 # wx.Timer to drive the ZMQ event loop.
513 # wx.Timer to drive the ZMQ event loop.
497 class IPWxApp(wx.App):
514 class IPWxApp(wx.App):
498 def OnInit(self):
515 def OnInit(self):
499 self.frame = TimerFrame(doi)
516 self.frame = TimerFrame(doi)
500 self.frame.Show(False)
517 self.frame.Show(False)
501 return True
518 return True
502
519
503 # The redirect=False here makes sure that wx doesn't replace
520 # The redirect=False here makes sure that wx doesn't replace
504 # sys.stdout/stderr with its own classes.
521 # sys.stdout/stderr with its own classes.
505 self.app = IPWxApp(redirect=False)
522 self.app = IPWxApp(redirect=False)
506 start_event_loop_wx(self.app)
523 start_event_loop_wx(self.app)
507
524
508
525
509 class TkKernel(Kernel):
526 class TkKernel(Kernel):
510 """A Kernel subclass with Tk support."""
527 """A Kernel subclass with Tk support."""
511
528
512 def start(self):
529 def start(self):
513 """Start a Tk enabled event loop."""
530 """Start a Tk enabled event loop."""
514
531
515 import Tkinter
532 import Tkinter
516 doi = self.do_one_iteration
533 doi = self.do_one_iteration
517 # Tk uses milliseconds
534 # Tk uses milliseconds
518 poll_interval = int(1000*self._poll_interval)
535 poll_interval = int(1000*self._poll_interval)
519 # For Tkinter, we create a Tk object and call its withdraw method.
536 # For Tkinter, we create a Tk object and call its withdraw method.
520 class Timer(object):
537 class Timer(object):
521 def __init__(self, func):
538 def __init__(self, func):
522 self.app = Tkinter.Tk()
539 self.app = Tkinter.Tk()
523 self.app.withdraw()
540 self.app.withdraw()
524 self.func = func
541 self.func = func
525
542
526 def on_timer(self):
543 def on_timer(self):
527 self.func()
544 self.func()
528 self.app.after(poll_interval, self.on_timer)
545 self.app.after(poll_interval, self.on_timer)
529
546
530 def start(self):
547 def start(self):
531 self.on_timer() # Call it once to get things going.
548 self.on_timer() # Call it once to get things going.
532 self.app.mainloop()
549 self.app.mainloop()
533
550
534 self.timer = Timer(doi)
551 self.timer = Timer(doi)
535 self.timer.start()
552 self.timer.start()
536
553
537
554
538 class GTKKernel(Kernel):
555 class GTKKernel(Kernel):
539 """A Kernel subclass with GTK support."""
556 """A Kernel subclass with GTK support."""
540
557
541 def start(self):
558 def start(self):
542 """Start the kernel, coordinating with the GTK event loop"""
559 """Start the kernel, coordinating with the GTK event loop"""
543 from .gui.gtkembed import GTKEmbed
560 from .gui.gtkembed import GTKEmbed
544
561
545 gtk_kernel = GTKEmbed(self)
562 gtk_kernel = GTKEmbed(self)
546 gtk_kernel.start()
563 gtk_kernel.start()
547
564
548
565
549 #-----------------------------------------------------------------------------
566 #-----------------------------------------------------------------------------
550 # Kernel main and launch functions
567 # Kernel main and launch functions
551 #-----------------------------------------------------------------------------
568 #-----------------------------------------------------------------------------
552
569
553 def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,
570 def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,
554 executable=None, independent=False, pylab=False, colors=None):
571 executable=None, independent=False, pylab=False, colors=None):
555 """Launches a localhost kernel, binding to the specified ports.
572 """Launches a localhost kernel, binding to the specified ports.
556
573
557 Parameters
574 Parameters
558 ----------
575 ----------
559 ip : str, optional
576 ip : str, optional
560 The ip address the kernel will bind to.
577 The ip address the kernel will bind to.
561
578
562 xrep_port : int, optional
579 xrep_port : int, optional
563 The port to use for XREP channel.
580 The port to use for XREP channel.
564
581
565 pub_port : int, optional
582 pub_port : int, optional
566 The port to use for the SUB channel.
583 The port to use for the SUB channel.
567
584
568 req_port : int, optional
585 req_port : int, optional
569 The port to use for the REQ (raw input) channel.
586 The port to use for the REQ (raw input) channel.
570
587
571 hb_port : int, optional
588 hb_port : int, optional
572 The port to use for the hearbeat REP channel.
589 The port to use for the hearbeat REP channel.
573
590
574 executable : str, optional (default sys.executable)
591 executable : str, optional (default sys.executable)
575 The Python executable to use for the kernel process.
592 The Python executable to use for the kernel process.
576
593
577 independent : bool, optional (default False)
594 independent : bool, optional (default False)
578 If set, the kernel process is guaranteed to survive if this process
595 If set, the kernel process is guaranteed to survive if this process
579 dies. If not set, an effort is made to ensure that the kernel is killed
596 dies. If not set, an effort is made to ensure that the kernel is killed
580 when this process dies. Note that in this case it is still good practice
597 when this process dies. Note that in this case it is still good practice
581 to kill kernels manually before exiting.
598 to kill kernels manually before exiting.
582
599
583 pylab : bool or string, optional (default False)
600 pylab : bool or string, optional (default False)
584 If not False, the kernel will be launched with pylab enabled. If a
601 If not False, the kernel will be launched with pylab enabled. If a
585 string is passed, matplotlib will use the specified backend. Otherwise,
602 string is passed, matplotlib will use the specified backend. Otherwise,
586 matplotlib's default backend will be used.
603 matplotlib's default backend will be used.
587
604
588 colors : None or string, optional (default None)
605 colors : None or string, optional (default None)
589 If not None, specify the color scheme. One of (NoColor, LightBG, Linux)
606 If not None, specify the color scheme. One of (NoColor, LightBG, Linux)
590
607
591 Returns
608 Returns
592 -------
609 -------
593 A tuple of form:
610 A tuple of form:
594 (kernel_process, xrep_port, pub_port, req_port)
611 (kernel_process, xrep_port, pub_port, req_port)
595 where kernel_process is a Popen object and the ports are integers.
612 where kernel_process is a Popen object and the ports are integers.
596 """
613 """
597 extra_arguments = []
614 extra_arguments = []
598 if pylab:
615 if pylab:
599 extra_arguments.append('--pylab')
616 extra_arguments.append('--pylab')
600 if isinstance(pylab, basestring):
617 if isinstance(pylab, basestring):
601 extra_arguments.append(pylab)
618 extra_arguments.append(pylab)
602 if ip is not None:
619 if ip is not None:
603 extra_arguments.append('--ip')
620 extra_arguments.append('--ip')
604 if isinstance(ip, basestring):
621 if isinstance(ip, basestring):
605 extra_arguments.append(ip)
622 extra_arguments.append(ip)
606 if colors is not None:
623 if colors is not None:
607 extra_arguments.append('--colors')
624 extra_arguments.append('--colors')
608 extra_arguments.append(colors)
625 extra_arguments.append(colors)
609 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
626 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
610 xrep_port, pub_port, req_port, hb_port,
627 xrep_port, pub_port, req_port, hb_port,
611 executable, independent, extra_arguments)
628 executable, independent, extra_arguments)
612
629
613
630
614 def main():
631 def main():
615 """ The IPython kernel main entry point.
632 """ The IPython kernel main entry point.
616 """
633 """
617 parser = make_argument_parser()
634 parser = make_argument_parser()
618 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
635 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
619 const='auto', help = \
636 const='auto', help = \
620 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
637 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
621 given, the GUI backend is matplotlib's, otherwise use one of: \
638 given, the GUI backend is matplotlib's, otherwise use one of: \
622 ['tk', 'gtk', 'qt', 'wx', 'osx', 'inline'].")
639 ['tk', 'gtk', 'qt', 'wx', 'osx', 'inline'].")
623 parser.add_argument('--colors',
640 parser.add_argument('--colors',
624 type=str, dest='colors',
641 type=str, dest='colors',
625 help="Set the color scheme (NoColor, Linux, and LightBG).",
642 help="Set the color scheme (NoColor, Linux, and LightBG).",
626 metavar='ZMQInteractiveShell.colors')
643 metavar='ZMQInteractiveShell.colors')
627 namespace = parser.parse_args()
644 namespace = parser.parse_args()
628
645
629 kernel_class = Kernel
646 kernel_class = Kernel
630
647
631 kernel_classes = {
648 kernel_classes = {
632 'qt' : QtKernel,
649 'qt' : QtKernel,
633 'qt4': QtKernel,
650 'qt4': QtKernel,
634 'inline': Kernel,
651 'inline': Kernel,
635 'osx': TkKernel,
652 'osx': TkKernel,
636 'wx' : WxKernel,
653 'wx' : WxKernel,
637 'tk' : TkKernel,
654 'tk' : TkKernel,
638 'gtk': GTKKernel,
655 'gtk': GTKKernel,
639 }
656 }
640 if namespace.pylab:
657 if namespace.pylab:
641 if namespace.pylab == 'auto':
658 if namespace.pylab == 'auto':
642 gui, backend = pylabtools.find_gui_and_backend()
659 gui, backend = pylabtools.find_gui_and_backend()
643 else:
660 else:
644 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
661 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
645 kernel_class = kernel_classes.get(gui)
662 kernel_class = kernel_classes.get(gui)
646 if kernel_class is None:
663 if kernel_class is None:
647 raise ValueError('GUI is not supported: %r' % gui)
664 raise ValueError('GUI is not supported: %r' % gui)
648 pylabtools.activate_matplotlib(backend)
665 pylabtools.activate_matplotlib(backend)
649 if namespace.colors:
666 if namespace.colors:
650 ZMQInteractiveShell.colors=namespace.colors
667 ZMQInteractiveShell.colors=namespace.colors
651
668
652 kernel = make_kernel(namespace, kernel_class, OutStream)
669 kernel = make_kernel(namespace, kernel_class, OutStream)
653
670
654 if namespace.pylab:
671 if namespace.pylab:
655 pylabtools.import_pylab(kernel.shell.user_ns, backend,
672 pylabtools.import_pylab(kernel.shell.user_ns, backend,
656 shell=kernel.shell)
673 shell=kernel.shell)
657
674
658 start_kernel(namespace, kernel)
675 start_kernel(namespace, kernel)
659
676
660
677
661 if __name__ == '__main__':
678 if __name__ == '__main__':
662 main()
679 main()
@@ -1,920 +1,937
1 """Base classes to manage the interaction with a running kernel.
1 """Base classes to manage the interaction with a running kernel.
2
2
3 TODO
3 TODO
4 * Create logger to handle debugging and console messages.
4 * Create logger to handle debugging and console messages.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2010 The IPython Development Team
8 # Copyright (C) 2008-2010 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import atexit
19 import atexit
20 from Queue import Queue, Empty
20 from Queue import Queue, Empty
21 from subprocess import Popen
21 from subprocess import Popen
22 import signal
22 import signal
23 import sys
23 import sys
24 from threading import Thread
24 from threading import Thread
25 import time
25 import time
26 import logging
26 import logging
27
27
28 # System library imports.
28 # System library imports.
29 import zmq
29 import zmq
30 from zmq import POLLIN, POLLOUT, POLLERR
30 from zmq import POLLIN, POLLOUT, POLLERR
31 from zmq.eventloop import ioloop
31 from zmq.eventloop import ioloop
32
32
33 # Local imports.
33 # Local imports.
34 from IPython.utils import io
34 from IPython.utils import io
35 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
35 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
36 from IPython.utils.traitlets import HasTraits, Any, Instance, Type, TCPAddress
36 from IPython.utils.traitlets import HasTraits, Any, Instance, Type, TCPAddress
37 from session import Session, Message
37 from session import Session, Message
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Constants and exceptions
40 # Constants and exceptions
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 class InvalidPortNumber(Exception):
43 class InvalidPortNumber(Exception):
44 pass
44 pass
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Utility functions
47 # Utility functions
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 # some utilities to validate message structure, these might get moved elsewhere
50 # some utilities to validate message structure, these might get moved elsewhere
51 # if they prove to have more generic utility
51 # if they prove to have more generic utility
52
52
53 def validate_string_list(lst):
53 def validate_string_list(lst):
54 """Validate that the input is a list of strings.
54 """Validate that the input is a list of strings.
55
55
56 Raises ValueError if not."""
56 Raises ValueError if not."""
57 if not isinstance(lst, list):
57 if not isinstance(lst, list):
58 raise ValueError('input %r must be a list' % lst)
58 raise ValueError('input %r must be a list' % lst)
59 for x in lst:
59 for x in lst:
60 if not isinstance(x, basestring):
60 if not isinstance(x, basestring):
61 raise ValueError('element %r in list must be a string' % x)
61 raise ValueError('element %r in list must be a string' % x)
62
62
63
63
64 def validate_string_dict(dct):
64 def validate_string_dict(dct):
65 """Validate that the input is a dict with string keys and values.
65 """Validate that the input is a dict with string keys and values.
66
66
67 Raises ValueError if not."""
67 Raises ValueError if not."""
68 for k,v in dct.iteritems():
68 for k,v in dct.iteritems():
69 if not isinstance(k, basestring):
69 if not isinstance(k, basestring):
70 raise ValueError('key %r in dict must be a string' % k)
70 raise ValueError('key %r in dict must be a string' % k)
71 if not isinstance(v, basestring):
71 if not isinstance(v, basestring):
72 raise ValueError('value %r in dict must be a string' % v)
72 raise ValueError('value %r in dict must be a string' % v)
73
73
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # ZMQ Socket Channel classes
76 # ZMQ Socket Channel classes
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 class ZmqSocketChannel(Thread):
79 class ZmqSocketChannel(Thread):
80 """The base class for the channels that use ZMQ sockets.
80 """The base class for the channels that use ZMQ sockets.
81 """
81 """
82 context = None
82 context = None
83 session = None
83 session = None
84 socket = None
84 socket = None
85 ioloop = None
85 ioloop = None
86 iostate = None
86 iostate = None
87 _address = None
87 _address = None
88
88
89 def __init__(self, context, session, address):
89 def __init__(self, context, session, address):
90 """Create a channel
90 """Create a channel
91
91
92 Parameters
92 Parameters
93 ----------
93 ----------
94 context : :class:`zmq.Context`
94 context : :class:`zmq.Context`
95 The ZMQ context to use.
95 The ZMQ context to use.
96 session : :class:`session.Session`
96 session : :class:`session.Session`
97 The session to use.
97 The session to use.
98 address : tuple
98 address : tuple
99 Standard (ip, port) tuple that the kernel is listening on.
99 Standard (ip, port) tuple that the kernel is listening on.
100 """
100 """
101 super(ZmqSocketChannel, self).__init__()
101 super(ZmqSocketChannel, self).__init__()
102 self.daemon = True
102 self.daemon = True
103
103
104 self.context = context
104 self.context = context
105 self.session = session
105 self.session = session
106 if address[1] == 0:
106 if address[1] == 0:
107 message = 'The port number for a channel cannot be 0.'
107 message = 'The port number for a channel cannot be 0.'
108 raise InvalidPortNumber(message)
108 raise InvalidPortNumber(message)
109 self._address = address
109 self._address = address
110
110
111 def stop(self):
111 def stop(self):
112 """Stop the channel's activity.
112 """Stop the channel's activity.
113
113
114 This calls :method:`Thread.join` and returns when the thread
114 This calls :method:`Thread.join` and returns when the thread
115 terminates. :class:`RuntimeError` will be raised if
115 terminates. :class:`RuntimeError` will be raised if
116 :method:`self.start` is called again.
116 :method:`self.start` is called again.
117 """
117 """
118 self.join()
118 self.join()
119
119
120 @property
120 @property
121 def address(self):
121 def address(self):
122 """Get the channel's address as an (ip, port) tuple.
122 """Get the channel's address as an (ip, port) tuple.
123
123
124 By the default, the address is (localhost, 0), where 0 means a random
124 By the default, the address is (localhost, 0), where 0 means a random
125 port.
125 port.
126 """
126 """
127 return self._address
127 return self._address
128
128
129 def add_io_state(self, state):
129 def add_io_state(self, state):
130 """Add IO state to the eventloop.
130 """Add IO state to the eventloop.
131
131
132 Parameters
132 Parameters
133 ----------
133 ----------
134 state : zmq.POLLIN|zmq.POLLOUT|zmq.POLLERR
134 state : zmq.POLLIN|zmq.POLLOUT|zmq.POLLERR
135 The IO state flag to set.
135 The IO state flag to set.
136
136
137 This is thread safe as it uses the thread safe IOLoop.add_callback.
137 This is thread safe as it uses the thread safe IOLoop.add_callback.
138 """
138 """
139 def add_io_state_callback():
139 def add_io_state_callback():
140 if not self.iostate & state:
140 if not self.iostate & state:
141 self.iostate = self.iostate | state
141 self.iostate = self.iostate | state
142 self.ioloop.update_handler(self.socket, self.iostate)
142 self.ioloop.update_handler(self.socket, self.iostate)
143 self.ioloop.add_callback(add_io_state_callback)
143 self.ioloop.add_callback(add_io_state_callback)
144
144
145 def drop_io_state(self, state):
145 def drop_io_state(self, state):
146 """Drop IO state from the eventloop.
146 """Drop IO state from the eventloop.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 state : zmq.POLLIN|zmq.POLLOUT|zmq.POLLERR
150 state : zmq.POLLIN|zmq.POLLOUT|zmq.POLLERR
151 The IO state flag to set.
151 The IO state flag to set.
152
152
153 This is thread safe as it uses the thread safe IOLoop.add_callback.
153 This is thread safe as it uses the thread safe IOLoop.add_callback.
154 """
154 """
155 def drop_io_state_callback():
155 def drop_io_state_callback():
156 if self.iostate & state:
156 if self.iostate & state:
157 self.iostate = self.iostate & (~state)
157 self.iostate = self.iostate & (~state)
158 self.ioloop.update_handler(self.socket, self.iostate)
158 self.ioloop.update_handler(self.socket, self.iostate)
159 self.ioloop.add_callback(drop_io_state_callback)
159 self.ioloop.add_callback(drop_io_state_callback)
160
160
161
161
162 class XReqSocketChannel(ZmqSocketChannel):
162 class XReqSocketChannel(ZmqSocketChannel):
163 """The XREQ channel for issues request/replies to the kernel.
163 """The XREQ channel for issues request/replies to the kernel.
164 """
164 """
165
165
166 command_queue = None
166 command_queue = None
167
167
168 def __init__(self, context, session, address):
168 def __init__(self, context, session, address):
169 super(XReqSocketChannel, self).__init__(context, session, address)
169 super(XReqSocketChannel, self).__init__(context, session, address)
170 self.command_queue = Queue()
170 self.command_queue = Queue()
171 self.ioloop = ioloop.IOLoop()
171 self.ioloop = ioloop.IOLoop()
172
172
173 def run(self):
173 def run(self):
174 """The thread's main activity. Call start() instead."""
174 """The thread's main activity. Call start() instead."""
175 self.socket = self.context.socket(zmq.XREQ)
175 self.socket = self.context.socket(zmq.XREQ)
176 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
176 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
177 self.socket.connect('tcp://%s:%i' % self.address)
177 self.socket.connect('tcp://%s:%i' % self.address)
178 self.iostate = POLLERR|POLLIN
178 self.iostate = POLLERR|POLLIN
179 self.ioloop.add_handler(self.socket, self._handle_events,
179 self.ioloop.add_handler(self.socket, self._handle_events,
180 self.iostate)
180 self.iostate)
181 self.ioloop.start()
181 self.ioloop.start()
182
182
183 def stop(self):
183 def stop(self):
184 self.ioloop.stop()
184 self.ioloop.stop()
185 super(XReqSocketChannel, self).stop()
185 super(XReqSocketChannel, self).stop()
186
186
187 def call_handlers(self, msg):
187 def call_handlers(self, msg):
188 """This method is called in the ioloop thread when a message arrives.
188 """This method is called in the ioloop thread when a message arrives.
189
189
190 Subclasses should override this method to handle incoming messages.
190 Subclasses should override this method to handle incoming messages.
191 It is important to remember that this method is called in the thread
191 It is important to remember that this method is called in the thread
192 so that some logic must be done to ensure that the application leve
192 so that some logic must be done to ensure that the application leve
193 handlers are called in the application thread.
193 handlers are called in the application thread.
194 """
194 """
195 raise NotImplementedError('call_handlers must be defined in a subclass.')
195 raise NotImplementedError('call_handlers must be defined in a subclass.')
196
196
197 def execute(self, code, silent=False,
197 def execute(self, code, silent=False,
198 user_variables=None, user_expressions=None):
198 user_variables=None, user_expressions=None):
199 """Execute code in the kernel.
199 """Execute code in the kernel.
200
200
201 Parameters
201 Parameters
202 ----------
202 ----------
203 code : str
203 code : str
204 A string of Python code.
204 A string of Python code.
205
205
206 silent : bool, optional (default False)
206 silent : bool, optional (default False)
207 If set, the kernel will execute the code as quietly possible.
207 If set, the kernel will execute the code as quietly possible.
208
208
209 user_variables : list, optional
209 user_variables : list, optional
210 A list of variable names to pull from the user's namespace. They
210 A list of variable names to pull from the user's namespace. They
211 will come back as a dict with these names as keys and their
211 will come back as a dict with these names as keys and their
212 :func:`repr` as values.
212 :func:`repr` as values.
213
213
214 user_expressions : dict, optional
214 user_expressions : dict, optional
215 A dict with string keys and to pull from the user's
215 A dict with string keys and to pull from the user's
216 namespace. They will come back as a dict with these names as keys
216 namespace. They will come back as a dict with these names as keys
217 and their :func:`repr` as values.
217 and their :func:`repr` as values.
218
218
219 Returns
219 Returns
220 -------
220 -------
221 The msg_id of the message sent.
221 The msg_id of the message sent.
222 """
222 """
223 if user_variables is None:
223 if user_variables is None:
224 user_variables = []
224 user_variables = []
225 if user_expressions is None:
225 if user_expressions is None:
226 user_expressions = {}
226 user_expressions = {}
227
227
228 # Don't waste network traffic if inputs are invalid
228 # Don't waste network traffic if inputs are invalid
229 if not isinstance(code, basestring):
229 if not isinstance(code, basestring):
230 raise ValueError('code %r must be a string' % code)
230 raise ValueError('code %r must be a string' % code)
231 validate_string_list(user_variables)
231 validate_string_list(user_variables)
232 validate_string_dict(user_expressions)
232 validate_string_dict(user_expressions)
233
233
234 # Create class for content/msg creation. Related to, but possibly
234 # Create class for content/msg creation. Related to, but possibly
235 # not in Session.
235 # not in Session.
236 content = dict(code=code, silent=silent,
236 content = dict(code=code, silent=silent,
237 user_variables=user_variables,
237 user_variables=user_variables,
238 user_expressions=user_expressions)
238 user_expressions=user_expressions)
239 msg = self.session.msg('execute_request', content)
239 msg = self.session.msg('execute_request', content)
240 self._queue_request(msg)
240 self._queue_request(msg)
241 return msg['header']['msg_id']
241 return msg['header']['msg_id']
242
242
243 def complete(self, text, line, cursor_pos, block=None):
243 def complete(self, text, line, cursor_pos, block=None):
244 """Tab complete text in the kernel's namespace.
244 """Tab complete text in the kernel's namespace.
245
245
246 Parameters
246 Parameters
247 ----------
247 ----------
248 text : str
248 text : str
249 The text to complete.
249 The text to complete.
250 line : str
250 line : str
251 The full line of text that is the surrounding context for the
251 The full line of text that is the surrounding context for the
252 text to complete.
252 text to complete.
253 cursor_pos : int
253 cursor_pos : int
254 The position of the cursor in the line where the completion was
254 The position of the cursor in the line where the completion was
255 requested.
255 requested.
256 block : str, optional
256 block : str, optional
257 The full block of code in which the completion is being requested.
257 The full block of code in which the completion is being requested.
258
258
259 Returns
259 Returns
260 -------
260 -------
261 The msg_id of the message sent.
261 The msg_id of the message sent.
262 """
262 """
263 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
263 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
264 msg = self.session.msg('complete_request', content)
264 msg = self.session.msg('complete_request', content)
265 self._queue_request(msg)
265 self._queue_request(msg)
266 return msg['header']['msg_id']
266 return msg['header']['msg_id']
267
267
268 def object_info(self, oname):
268 def object_info(self, oname):
269 """Get metadata information about an object.
269 """Get metadata information about an object.
270
270
271 Parameters
271 Parameters
272 ----------
272 ----------
273 oname : str
273 oname : str
274 A string specifying the object name.
274 A string specifying the object name.
275
275
276 Returns
276 Returns
277 -------
277 -------
278 The msg_id of the message sent.
278 The msg_id of the message sent.
279 """
279 """
280 content = dict(oname=oname)
280 content = dict(oname=oname)
281 msg = self.session.msg('object_info_request', content)
281 msg = self.session.msg('object_info_request', content)
282 self._queue_request(msg)
282 self._queue_request(msg)
283 return msg['header']['msg_id']
283 return msg['header']['msg_id']
284
284
285 def history_tail(self, n=10, raw=True, output=False):
285 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
286 """Get the history list.
286 """Get entries from the history list.
287
287
288 Parameters
288 Parameters
289 ----------
289 ----------
290 n : int
291 The number of lines of history to get.
292 raw : bool
290 raw : bool
293 If True, return the raw input.
291 If True, return the raw input.
294 output : bool
292 output : bool
295 If True, then return the output as well.
293 If True, then return the output as well.
294 hist_access_type : str
295 'range' (fill in session, start and stop params), 'tail' (fill in n)
296 or 'search' (fill in pattern param).
297
298 session : int
299 For a range request, the session from which to get lines. Session
300 numbers are positive integers; negative ones count back from the
301 current session.
302 start : int
303 The first line number of a history range.
304 stop : int
305 The final (excluded) line number of a history range.
306
307 n : int
308 The number of lines of history to get for a tail request.
309
310 pattern : str
311 The glob-syntax pattern for a search request.
296
312
297 Returns
313 Returns
298 -------
314 -------
299 The msg_id of the message sent.
315 The msg_id of the message sent.
300 """
316 """
301 content = dict(n=n, raw=raw, output=output)
317 content = dict(raw=raw, output=output, hist_access_type=hist_access_type,
302 msg = self.session.msg('history_tail_request', content)
318 **kwargs)
319 msg = self.session.msg('history_request', content)
303 self._queue_request(msg)
320 self._queue_request(msg)
304 return msg['header']['msg_id']
321 return msg['header']['msg_id']
305
322
306 def shutdown(self, restart=False):
323 def shutdown(self, restart=False):
307 """Request an immediate kernel shutdown.
324 """Request an immediate kernel shutdown.
308
325
309 Upon receipt of the (empty) reply, client code can safely assume that
326 Upon receipt of the (empty) reply, client code can safely assume that
310 the kernel has shut down and it's safe to forcefully terminate it if
327 the kernel has shut down and it's safe to forcefully terminate it if
311 it's still alive.
328 it's still alive.
312
329
313 The kernel will send the reply via a function registered with Python's
330 The kernel will send the reply via a function registered with Python's
314 atexit module, ensuring it's truly done as the kernel is done with all
331 atexit module, ensuring it's truly done as the kernel is done with all
315 normal operation.
332 normal operation.
316 """
333 """
317 # Send quit message to kernel. Once we implement kernel-side setattr,
334 # Send quit message to kernel. Once we implement kernel-side setattr,
318 # this should probably be done that way, but for now this will do.
335 # this should probably be done that way, but for now this will do.
319 msg = self.session.msg('shutdown_request', {'restart':restart})
336 msg = self.session.msg('shutdown_request', {'restart':restart})
320 self._queue_request(msg)
337 self._queue_request(msg)
321 return msg['header']['msg_id']
338 return msg['header']['msg_id']
322
339
323 def _handle_events(self, socket, events):
340 def _handle_events(self, socket, events):
324 if events & POLLERR:
341 if events & POLLERR:
325 self._handle_err()
342 self._handle_err()
326 if events & POLLOUT:
343 if events & POLLOUT:
327 self._handle_send()
344 self._handle_send()
328 if events & POLLIN:
345 if events & POLLIN:
329 self._handle_recv()
346 self._handle_recv()
330
347
331 def _handle_recv(self):
348 def _handle_recv(self):
332 ident,msg = self.session.recv(self.socket, 0)
349 ident,msg = self.session.recv(self.socket, 0)
333 self.call_handlers(msg)
350 self.call_handlers(msg)
334
351
335 def _handle_send(self):
352 def _handle_send(self):
336 try:
353 try:
337 msg = self.command_queue.get(False)
354 msg = self.command_queue.get(False)
338 except Empty:
355 except Empty:
339 pass
356 pass
340 else:
357 else:
341 self.session.send(self.socket,msg)
358 self.session.send(self.socket,msg)
342 if self.command_queue.empty():
359 if self.command_queue.empty():
343 self.drop_io_state(POLLOUT)
360 self.drop_io_state(POLLOUT)
344
361
345 def _handle_err(self):
362 def _handle_err(self):
346 # We don't want to let this go silently, so eventually we should log.
363 # We don't want to let this go silently, so eventually we should log.
347 raise zmq.ZMQError()
364 raise zmq.ZMQError()
348
365
349 def _queue_request(self, msg):
366 def _queue_request(self, msg):
350 self.command_queue.put(msg)
367 self.command_queue.put(msg)
351 self.add_io_state(POLLOUT)
368 self.add_io_state(POLLOUT)
352
369
353
370
354 class SubSocketChannel(ZmqSocketChannel):
371 class SubSocketChannel(ZmqSocketChannel):
355 """The SUB channel which listens for messages that the kernel publishes.
372 """The SUB channel which listens for messages that the kernel publishes.
356 """
373 """
357
374
358 def __init__(self, context, session, address):
375 def __init__(self, context, session, address):
359 super(SubSocketChannel, self).__init__(context, session, address)
376 super(SubSocketChannel, self).__init__(context, session, address)
360 self.ioloop = ioloop.IOLoop()
377 self.ioloop = ioloop.IOLoop()
361
378
362 def run(self):
379 def run(self):
363 """The thread's main activity. Call start() instead."""
380 """The thread's main activity. Call start() instead."""
364 self.socket = self.context.socket(zmq.SUB)
381 self.socket = self.context.socket(zmq.SUB)
365 self.socket.setsockopt(zmq.SUBSCRIBE,'')
382 self.socket.setsockopt(zmq.SUBSCRIBE,'')
366 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
383 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
367 self.socket.connect('tcp://%s:%i' % self.address)
384 self.socket.connect('tcp://%s:%i' % self.address)
368 self.iostate = POLLIN|POLLERR
385 self.iostate = POLLIN|POLLERR
369 self.ioloop.add_handler(self.socket, self._handle_events,
386 self.ioloop.add_handler(self.socket, self._handle_events,
370 self.iostate)
387 self.iostate)
371 self.ioloop.start()
388 self.ioloop.start()
372
389
373 def stop(self):
390 def stop(self):
374 self.ioloop.stop()
391 self.ioloop.stop()
375 super(SubSocketChannel, self).stop()
392 super(SubSocketChannel, self).stop()
376
393
377 def call_handlers(self, msg):
394 def call_handlers(self, msg):
378 """This method is called in the ioloop thread when a message arrives.
395 """This method is called in the ioloop thread when a message arrives.
379
396
380 Subclasses should override this method to handle incoming messages.
397 Subclasses should override this method to handle incoming messages.
381 It is important to remember that this method is called in the thread
398 It is important to remember that this method is called in the thread
382 so that some logic must be done to ensure that the application leve
399 so that some logic must be done to ensure that the application leve
383 handlers are called in the application thread.
400 handlers are called in the application thread.
384 """
401 """
385 raise NotImplementedError('call_handlers must be defined in a subclass.')
402 raise NotImplementedError('call_handlers must be defined in a subclass.')
386
403
387 def flush(self, timeout=1.0):
404 def flush(self, timeout=1.0):
388 """Immediately processes all pending messages on the SUB channel.
405 """Immediately processes all pending messages on the SUB channel.
389
406
390 Callers should use this method to ensure that :method:`call_handlers`
407 Callers should use this method to ensure that :method:`call_handlers`
391 has been called for all messages that have been received on the
408 has been called for all messages that have been received on the
392 0MQ SUB socket of this channel.
409 0MQ SUB socket of this channel.
393
410
394 This method is thread safe.
411 This method is thread safe.
395
412
396 Parameters
413 Parameters
397 ----------
414 ----------
398 timeout : float, optional
415 timeout : float, optional
399 The maximum amount of time to spend flushing, in seconds. The
416 The maximum amount of time to spend flushing, in seconds. The
400 default is one second.
417 default is one second.
401 """
418 """
402 # We do the IOLoop callback process twice to ensure that the IOLoop
419 # We do the IOLoop callback process twice to ensure that the IOLoop
403 # gets to perform at least one full poll.
420 # gets to perform at least one full poll.
404 stop_time = time.time() + timeout
421 stop_time = time.time() + timeout
405 for i in xrange(2):
422 for i in xrange(2):
406 self._flushed = False
423 self._flushed = False
407 self.ioloop.add_callback(self._flush)
424 self.ioloop.add_callback(self._flush)
408 while not self._flushed and time.time() < stop_time:
425 while not self._flushed and time.time() < stop_time:
409 time.sleep(0.01)
426 time.sleep(0.01)
410
427
411 def _handle_events(self, socket, events):
428 def _handle_events(self, socket, events):
412 # Turn on and off POLLOUT depending on if we have made a request
429 # Turn on and off POLLOUT depending on if we have made a request
413 if events & POLLERR:
430 if events & POLLERR:
414 self._handle_err()
431 self._handle_err()
415 if events & POLLIN:
432 if events & POLLIN:
416 self._handle_recv()
433 self._handle_recv()
417
434
418 def _handle_err(self):
435 def _handle_err(self):
419 # We don't want to let this go silently, so eventually we should log.
436 # We don't want to let this go silently, so eventually we should log.
420 raise zmq.ZMQError()
437 raise zmq.ZMQError()
421
438
422 def _handle_recv(self):
439 def _handle_recv(self):
423 # Get all of the messages we can
440 # Get all of the messages we can
424 while True:
441 while True:
425 try:
442 try:
426 ident,msg = self.session.recv(self.socket)
443 ident,msg = self.session.recv(self.socket)
427 except zmq.ZMQError:
444 except zmq.ZMQError:
428 # Check the errno?
445 # Check the errno?
429 # Will this trigger POLLERR?
446 # Will this trigger POLLERR?
430 break
447 break
431 else:
448 else:
432 if msg is None:
449 if msg is None:
433 break
450 break
434 self.call_handlers(msg)
451 self.call_handlers(msg)
435
452
436 def _flush(self):
453 def _flush(self):
437 """Callback for :method:`self.flush`."""
454 """Callback for :method:`self.flush`."""
438 self._flushed = True
455 self._flushed = True
439
456
440
457
441 class RepSocketChannel(ZmqSocketChannel):
458 class RepSocketChannel(ZmqSocketChannel):
442 """A reply channel to handle raw_input requests that the kernel makes."""
459 """A reply channel to handle raw_input requests that the kernel makes."""
443
460
444 msg_queue = None
461 msg_queue = None
445
462
446 def __init__(self, context, session, address):
463 def __init__(self, context, session, address):
447 super(RepSocketChannel, self).__init__(context, session, address)
464 super(RepSocketChannel, self).__init__(context, session, address)
448 self.ioloop = ioloop.IOLoop()
465 self.ioloop = ioloop.IOLoop()
449 self.msg_queue = Queue()
466 self.msg_queue = Queue()
450
467
451 def run(self):
468 def run(self):
452 """The thread's main activity. Call start() instead."""
469 """The thread's main activity. Call start() instead."""
453 self.socket = self.context.socket(zmq.XREQ)
470 self.socket = self.context.socket(zmq.XREQ)
454 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
471 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
455 self.socket.connect('tcp://%s:%i' % self.address)
472 self.socket.connect('tcp://%s:%i' % self.address)
456 self.iostate = POLLERR|POLLIN
473 self.iostate = POLLERR|POLLIN
457 self.ioloop.add_handler(self.socket, self._handle_events,
474 self.ioloop.add_handler(self.socket, self._handle_events,
458 self.iostate)
475 self.iostate)
459 self.ioloop.start()
476 self.ioloop.start()
460
477
461 def stop(self):
478 def stop(self):
462 self.ioloop.stop()
479 self.ioloop.stop()
463 super(RepSocketChannel, self).stop()
480 super(RepSocketChannel, self).stop()
464
481
465 def call_handlers(self, msg):
482 def call_handlers(self, msg):
466 """This method is called in the ioloop thread when a message arrives.
483 """This method is called in the ioloop thread when a message arrives.
467
484
468 Subclasses should override this method to handle incoming messages.
485 Subclasses should override this method to handle incoming messages.
469 It is important to remember that this method is called in the thread
486 It is important to remember that this method is called in the thread
470 so that some logic must be done to ensure that the application leve
487 so that some logic must be done to ensure that the application leve
471 handlers are called in the application thread.
488 handlers are called in the application thread.
472 """
489 """
473 raise NotImplementedError('call_handlers must be defined in a subclass.')
490 raise NotImplementedError('call_handlers must be defined in a subclass.')
474
491
475 def input(self, string):
492 def input(self, string):
476 """Send a string of raw input to the kernel."""
493 """Send a string of raw input to the kernel."""
477 content = dict(value=string)
494 content = dict(value=string)
478 msg = self.session.msg('input_reply', content)
495 msg = self.session.msg('input_reply', content)
479 self._queue_reply(msg)
496 self._queue_reply(msg)
480
497
481 def _handle_events(self, socket, events):
498 def _handle_events(self, socket, events):
482 if events & POLLERR:
499 if events & POLLERR:
483 self._handle_err()
500 self._handle_err()
484 if events & POLLOUT:
501 if events & POLLOUT:
485 self._handle_send()
502 self._handle_send()
486 if events & POLLIN:
503 if events & POLLIN:
487 self._handle_recv()
504 self._handle_recv()
488
505
489 def _handle_recv(self):
506 def _handle_recv(self):
490 ident,msg = self.session.recv(self.socket, 0)
507 ident,msg = self.session.recv(self.socket, 0)
491 self.call_handlers(msg)
508 self.call_handlers(msg)
492
509
493 def _handle_send(self):
510 def _handle_send(self):
494 try:
511 try:
495 msg = self.msg_queue.get(False)
512 msg = self.msg_queue.get(False)
496 except Empty:
513 except Empty:
497 pass
514 pass
498 else:
515 else:
499 self.session.send(self.socket,msg)
516 self.session.send(self.socket,msg)
500 if self.msg_queue.empty():
517 if self.msg_queue.empty():
501 self.drop_io_state(POLLOUT)
518 self.drop_io_state(POLLOUT)
502
519
503 def _handle_err(self):
520 def _handle_err(self):
504 # We don't want to let this go silently, so eventually we should log.
521 # We don't want to let this go silently, so eventually we should log.
505 raise zmq.ZMQError()
522 raise zmq.ZMQError()
506
523
507 def _queue_reply(self, msg):
524 def _queue_reply(self, msg):
508 self.msg_queue.put(msg)
525 self.msg_queue.put(msg)
509 self.add_io_state(POLLOUT)
526 self.add_io_state(POLLOUT)
510
527
511
528
512 class HBSocketChannel(ZmqSocketChannel):
529 class HBSocketChannel(ZmqSocketChannel):
513 """The heartbeat channel which monitors the kernel heartbeat.
530 """The heartbeat channel which monitors the kernel heartbeat.
514
531
515 Note that the heartbeat channel is paused by default. As long as you start
532 Note that the heartbeat channel is paused by default. As long as you start
516 this channel, the kernel manager will ensure that it is paused and un-paused
533 this channel, the kernel manager will ensure that it is paused and un-paused
517 as appropriate.
534 as appropriate.
518 """
535 """
519
536
520 time_to_dead = 3.0
537 time_to_dead = 3.0
521 socket = None
538 socket = None
522 poller = None
539 poller = None
523 _running = None
540 _running = None
524 _pause = None
541 _pause = None
525
542
526 def __init__(self, context, session, address):
543 def __init__(self, context, session, address):
527 super(HBSocketChannel, self).__init__(context, session, address)
544 super(HBSocketChannel, self).__init__(context, session, address)
528 self._running = False
545 self._running = False
529 self._pause = True
546 self._pause = True
530
547
531 def _create_socket(self):
548 def _create_socket(self):
532 self.socket = self.context.socket(zmq.REQ)
549 self.socket = self.context.socket(zmq.REQ)
533 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
550 self.socket.setsockopt(zmq.IDENTITY, self.session.session)
534 self.socket.connect('tcp://%s:%i' % self.address)
551 self.socket.connect('tcp://%s:%i' % self.address)
535 self.poller = zmq.Poller()
552 self.poller = zmq.Poller()
536 self.poller.register(self.socket, zmq.POLLIN)
553 self.poller.register(self.socket, zmq.POLLIN)
537
554
538 def run(self):
555 def run(self):
539 """The thread's main activity. Call start() instead."""
556 """The thread's main activity. Call start() instead."""
540 self._create_socket()
557 self._create_socket()
541 self._running = True
558 self._running = True
542 while self._running:
559 while self._running:
543 if self._pause:
560 if self._pause:
544 time.sleep(self.time_to_dead)
561 time.sleep(self.time_to_dead)
545 else:
562 else:
546 since_last_heartbeat = 0.0
563 since_last_heartbeat = 0.0
547 request_time = time.time()
564 request_time = time.time()
548 try:
565 try:
549 #io.rprint('Ping from HB channel') # dbg
566 #io.rprint('Ping from HB channel') # dbg
550 self.socket.send(b'ping')
567 self.socket.send(b'ping')
551 except zmq.ZMQError, e:
568 except zmq.ZMQError, e:
552 #io.rprint('*** HB Error:', e) # dbg
569 #io.rprint('*** HB Error:', e) # dbg
553 if e.errno == zmq.EFSM:
570 if e.errno == zmq.EFSM:
554 #io.rprint('sleep...', self.time_to_dead) # dbg
571 #io.rprint('sleep...', self.time_to_dead) # dbg
555 time.sleep(self.time_to_dead)
572 time.sleep(self.time_to_dead)
556 self._create_socket()
573 self._create_socket()
557 else:
574 else:
558 raise
575 raise
559 else:
576 else:
560 while True:
577 while True:
561 try:
578 try:
562 self.socket.recv(zmq.NOBLOCK)
579 self.socket.recv(zmq.NOBLOCK)
563 except zmq.ZMQError, e:
580 except zmq.ZMQError, e:
564 #io.rprint('*** HB Error 2:', e) # dbg
581 #io.rprint('*** HB Error 2:', e) # dbg
565 if e.errno == zmq.EAGAIN:
582 if e.errno == zmq.EAGAIN:
566 before_poll = time.time()
583 before_poll = time.time()
567 until_dead = self.time_to_dead - (before_poll -
584 until_dead = self.time_to_dead - (before_poll -
568 request_time)
585 request_time)
569
586
570 # When the return value of poll() is an empty
587 # When the return value of poll() is an empty
571 # list, that is when things have gone wrong
588 # list, that is when things have gone wrong
572 # (zeromq bug). As long as it is not an empty
589 # (zeromq bug). As long as it is not an empty
573 # list, poll is working correctly even if it
590 # list, poll is working correctly even if it
574 # returns quickly. Note: poll timeout is in
591 # returns quickly. Note: poll timeout is in
575 # milliseconds.
592 # milliseconds.
576 self.poller.poll(1000*until_dead)
593 self.poller.poll(1000*until_dead)
577
594
578 since_last_heartbeat = time.time()-request_time
595 since_last_heartbeat = time.time()-request_time
579 if since_last_heartbeat > self.time_to_dead:
596 if since_last_heartbeat > self.time_to_dead:
580 self.call_handlers(since_last_heartbeat)
597 self.call_handlers(since_last_heartbeat)
581 break
598 break
582 else:
599 else:
583 # FIXME: We should probably log this instead.
600 # FIXME: We should probably log this instead.
584 raise
601 raise
585 else:
602 else:
586 until_dead = self.time_to_dead - (time.time() -
603 until_dead = self.time_to_dead - (time.time() -
587 request_time)
604 request_time)
588 if until_dead > 0.0:
605 if until_dead > 0.0:
589 #io.rprint('sleep...', self.time_to_dead) # dbg
606 #io.rprint('sleep...', self.time_to_dead) # dbg
590 time.sleep(until_dead)
607 time.sleep(until_dead)
591 break
608 break
592
609
593 def pause(self):
610 def pause(self):
594 """Pause the heartbeat."""
611 """Pause the heartbeat."""
595 self._pause = True
612 self._pause = True
596
613
597 def unpause(self):
614 def unpause(self):
598 """Unpause the heartbeat."""
615 """Unpause the heartbeat."""
599 self._pause = False
616 self._pause = False
600
617
601 def is_beating(self):
618 def is_beating(self):
602 """Is the heartbeat running and not paused."""
619 """Is the heartbeat running and not paused."""
603 if self.is_alive() and not self._pause:
620 if self.is_alive() and not self._pause:
604 return True
621 return True
605 else:
622 else:
606 return False
623 return False
607
624
608 def stop(self):
625 def stop(self):
609 self._running = False
626 self._running = False
610 super(HBSocketChannel, self).stop()
627 super(HBSocketChannel, self).stop()
611
628
612 def call_handlers(self, since_last_heartbeat):
629 def call_handlers(self, since_last_heartbeat):
613 """This method is called in the ioloop thread when a message arrives.
630 """This method is called in the ioloop thread when a message arrives.
614
631
615 Subclasses should override this method to handle incoming messages.
632 Subclasses should override this method to handle incoming messages.
616 It is important to remember that this method is called in the thread
633 It is important to remember that this method is called in the thread
617 so that some logic must be done to ensure that the application leve
634 so that some logic must be done to ensure that the application leve
618 handlers are called in the application thread.
635 handlers are called in the application thread.
619 """
636 """
620 raise NotImplementedError('call_handlers must be defined in a subclass.')
637 raise NotImplementedError('call_handlers must be defined in a subclass.')
621
638
622
639
623 #-----------------------------------------------------------------------------
640 #-----------------------------------------------------------------------------
624 # Main kernel manager class
641 # Main kernel manager class
625 #-----------------------------------------------------------------------------
642 #-----------------------------------------------------------------------------
626
643
627 class KernelManager(HasTraits):
644 class KernelManager(HasTraits):
628 """ Manages a kernel for a frontend.
645 """ Manages a kernel for a frontend.
629
646
630 The SUB channel is for the frontend to receive messages published by the
647 The SUB channel is for the frontend to receive messages published by the
631 kernel.
648 kernel.
632
649
633 The REQ channel is for the frontend to make requests of the kernel.
650 The REQ channel is for the frontend to make requests of the kernel.
634
651
635 The REP channel is for the kernel to request stdin (raw_input) from the
652 The REP channel is for the kernel to request stdin (raw_input) from the
636 frontend.
653 frontend.
637 """
654 """
638 # The PyZMQ Context to use for communication with the kernel.
655 # The PyZMQ Context to use for communication with the kernel.
639 context = Instance(zmq.Context,(),{})
656 context = Instance(zmq.Context,(),{})
640
657
641 # The Session to use for communication with the kernel.
658 # The Session to use for communication with the kernel.
642 session = Instance(Session,(),{})
659 session = Instance(Session,(),{})
643
660
644 # The kernel process with which the KernelManager is communicating.
661 # The kernel process with which the KernelManager is communicating.
645 kernel = Instance(Popen)
662 kernel = Instance(Popen)
646
663
647 # The addresses for the communication channels.
664 # The addresses for the communication channels.
648 xreq_address = TCPAddress((LOCALHOST, 0))
665 xreq_address = TCPAddress((LOCALHOST, 0))
649 sub_address = TCPAddress((LOCALHOST, 0))
666 sub_address = TCPAddress((LOCALHOST, 0))
650 rep_address = TCPAddress((LOCALHOST, 0))
667 rep_address = TCPAddress((LOCALHOST, 0))
651 hb_address = TCPAddress((LOCALHOST, 0))
668 hb_address = TCPAddress((LOCALHOST, 0))
652
669
653 # The classes to use for the various channels.
670 # The classes to use for the various channels.
654 xreq_channel_class = Type(XReqSocketChannel)
671 xreq_channel_class = Type(XReqSocketChannel)
655 sub_channel_class = Type(SubSocketChannel)
672 sub_channel_class = Type(SubSocketChannel)
656 rep_channel_class = Type(RepSocketChannel)
673 rep_channel_class = Type(RepSocketChannel)
657 hb_channel_class = Type(HBSocketChannel)
674 hb_channel_class = Type(HBSocketChannel)
658
675
659 # Protected traits.
676 # Protected traits.
660 _launch_args = Any
677 _launch_args = Any
661 _xreq_channel = Any
678 _xreq_channel = Any
662 _sub_channel = Any
679 _sub_channel = Any
663 _rep_channel = Any
680 _rep_channel = Any
664 _hb_channel = Any
681 _hb_channel = Any
665
682
666 def __init__(self, **kwargs):
683 def __init__(self, **kwargs):
667 super(KernelManager, self).__init__(**kwargs)
684 super(KernelManager, self).__init__(**kwargs)
668 # Uncomment this to try closing the context.
685 # Uncomment this to try closing the context.
669 # atexit.register(self.context.close)
686 # atexit.register(self.context.close)
670
687
671 #--------------------------------------------------------------------------
688 #--------------------------------------------------------------------------
672 # Channel management methods:
689 # Channel management methods:
673 #--------------------------------------------------------------------------
690 #--------------------------------------------------------------------------
674
691
675 def start_channels(self, xreq=True, sub=True, rep=True, hb=True):
692 def start_channels(self, xreq=True, sub=True, rep=True, hb=True):
676 """Starts the channels for this kernel.
693 """Starts the channels for this kernel.
677
694
678 This will create the channels if they do not exist and then start
695 This will create the channels if they do not exist and then start
679 them. If port numbers of 0 are being used (random ports) then you
696 them. If port numbers of 0 are being used (random ports) then you
680 must first call :method:`start_kernel`. If the channels have been
697 must first call :method:`start_kernel`. If the channels have been
681 stopped and you call this, :class:`RuntimeError` will be raised.
698 stopped and you call this, :class:`RuntimeError` will be raised.
682 """
699 """
683 if xreq:
700 if xreq:
684 self.xreq_channel.start()
701 self.xreq_channel.start()
685 if sub:
702 if sub:
686 self.sub_channel.start()
703 self.sub_channel.start()
687 if rep:
704 if rep:
688 self.rep_channel.start()
705 self.rep_channel.start()
689 if hb:
706 if hb:
690 self.hb_channel.start()
707 self.hb_channel.start()
691
708
692 def stop_channels(self):
709 def stop_channels(self):
693 """Stops all the running channels for this kernel.
710 """Stops all the running channels for this kernel.
694 """
711 """
695 if self.xreq_channel.is_alive():
712 if self.xreq_channel.is_alive():
696 self.xreq_channel.stop()
713 self.xreq_channel.stop()
697 if self.sub_channel.is_alive():
714 if self.sub_channel.is_alive():
698 self.sub_channel.stop()
715 self.sub_channel.stop()
699 if self.rep_channel.is_alive():
716 if self.rep_channel.is_alive():
700 self.rep_channel.stop()
717 self.rep_channel.stop()
701 if self.hb_channel.is_alive():
718 if self.hb_channel.is_alive():
702 self.hb_channel.stop()
719 self.hb_channel.stop()
703
720
704 @property
721 @property
705 def channels_running(self):
722 def channels_running(self):
706 """Are any of the channels created and running?"""
723 """Are any of the channels created and running?"""
707 return (self.xreq_channel.is_alive() or self.sub_channel.is_alive() or
724 return (self.xreq_channel.is_alive() or self.sub_channel.is_alive() or
708 self.rep_channel.is_alive() or self.hb_channel.is_alive())
725 self.rep_channel.is_alive() or self.hb_channel.is_alive())
709
726
710 #--------------------------------------------------------------------------
727 #--------------------------------------------------------------------------
711 # Kernel process management methods:
728 # Kernel process management methods:
712 #--------------------------------------------------------------------------
729 #--------------------------------------------------------------------------
713
730
714 def start_kernel(self, **kw):
731 def start_kernel(self, **kw):
715 """Starts a kernel process and configures the manager to use it.
732 """Starts a kernel process and configures the manager to use it.
716
733
717 If random ports (port=0) are being used, this method must be called
734 If random ports (port=0) are being used, this method must be called
718 before the channels are created.
735 before the channels are created.
719
736
720 Parameters:
737 Parameters:
721 -----------
738 -----------
722 ipython : bool, optional (default True)
739 ipython : bool, optional (default True)
723 Whether to use an IPython kernel instead of a plain Python kernel.
740 Whether to use an IPython kernel instead of a plain Python kernel.
724
741
725 **kw : optional
742 **kw : optional
726 See respective options for IPython and Python kernels.
743 See respective options for IPython and Python kernels.
727 """
744 """
728 xreq, sub, rep, hb = self.xreq_address, self.sub_address, \
745 xreq, sub, rep, hb = self.xreq_address, self.sub_address, \
729 self.rep_address, self.hb_address
746 self.rep_address, self.hb_address
730 if xreq[0] not in LOCAL_IPS or sub[0] not in LOCAL_IPS or \
747 if xreq[0] not in LOCAL_IPS or sub[0] not in LOCAL_IPS or \
731 rep[0] not in LOCAL_IPS or hb[0] not in LOCAL_IPS:
748 rep[0] not in LOCAL_IPS or hb[0] not in LOCAL_IPS:
732 raise RuntimeError("Can only launch a kernel on a local interface. "
749 raise RuntimeError("Can only launch a kernel on a local interface. "
733 "Make sure that the '*_address' attributes are "
750 "Make sure that the '*_address' attributes are "
734 "configured properly. "
751 "configured properly. "
735 "Currently valid addresses are: %s"%LOCAL_IPS
752 "Currently valid addresses are: %s"%LOCAL_IPS
736 )
753 )
737
754
738 self._launch_args = kw.copy()
755 self._launch_args = kw.copy()
739 if kw.pop('ipython', True):
756 if kw.pop('ipython', True):
740 from ipkernel import launch_kernel
757 from ipkernel import launch_kernel
741 else:
758 else:
742 from pykernel import launch_kernel
759 from pykernel import launch_kernel
743 self.kernel, xrep, pub, req, _hb = launch_kernel(
760 self.kernel, xrep, pub, req, _hb = launch_kernel(
744 xrep_port=xreq[1], pub_port=sub[1],
761 xrep_port=xreq[1], pub_port=sub[1],
745 req_port=rep[1], hb_port=hb[1], **kw)
762 req_port=rep[1], hb_port=hb[1], **kw)
746 self.xreq_address = (xreq[0], xrep)
763 self.xreq_address = (xreq[0], xrep)
747 self.sub_address = (sub[0], pub)
764 self.sub_address = (sub[0], pub)
748 self.rep_address = (rep[0], req)
765 self.rep_address = (rep[0], req)
749 self.hb_address = (hb[0], _hb)
766 self.hb_address = (hb[0], _hb)
750
767
751 def shutdown_kernel(self, restart=False):
768 def shutdown_kernel(self, restart=False):
752 """ Attempts to the stop the kernel process cleanly. If the kernel
769 """ Attempts to the stop the kernel process cleanly. If the kernel
753 cannot be stopped, it is killed, if possible.
770 cannot be stopped, it is killed, if possible.
754 """
771 """
755 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
772 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
756 if sys.platform == 'win32':
773 if sys.platform == 'win32':
757 self.kill_kernel()
774 self.kill_kernel()
758 return
775 return
759
776
760 # Pause the heart beat channel if it exists.
777 # Pause the heart beat channel if it exists.
761 if self._hb_channel is not None:
778 if self._hb_channel is not None:
762 self._hb_channel.pause()
779 self._hb_channel.pause()
763
780
764 # Don't send any additional kernel kill messages immediately, to give
781 # Don't send any additional kernel kill messages immediately, to give
765 # the kernel a chance to properly execute shutdown actions. Wait for at
782 # the kernel a chance to properly execute shutdown actions. Wait for at
766 # most 1s, checking every 0.1s.
783 # most 1s, checking every 0.1s.
767 self.xreq_channel.shutdown(restart=restart)
784 self.xreq_channel.shutdown(restart=restart)
768 for i in range(10):
785 for i in range(10):
769 if self.is_alive:
786 if self.is_alive:
770 time.sleep(0.1)
787 time.sleep(0.1)
771 else:
788 else:
772 break
789 break
773 else:
790 else:
774 # OK, we've waited long enough.
791 # OK, we've waited long enough.
775 if self.has_kernel:
792 if self.has_kernel:
776 self.kill_kernel()
793 self.kill_kernel()
777
794
778 def restart_kernel(self, now=False, **kw):
795 def restart_kernel(self, now=False, **kw):
779 """Restarts a kernel with the arguments that were used to launch it.
796 """Restarts a kernel with the arguments that were used to launch it.
780
797
781 If the old kernel was launched with random ports, the same ports will be
798 If the old kernel was launched with random ports, the same ports will be
782 used for the new kernel.
799 used for the new kernel.
783
800
784 Parameters
801 Parameters
785 ----------
802 ----------
786 now : bool, optional
803 now : bool, optional
787 If True, the kernel is forcefully restarted *immediately*, without
804 If True, the kernel is forcefully restarted *immediately*, without
788 having a chance to do any cleanup action. Otherwise the kernel is
805 having a chance to do any cleanup action. Otherwise the kernel is
789 given 1s to clean up before a forceful restart is issued.
806 given 1s to clean up before a forceful restart is issued.
790
807
791 In all cases the kernel is restarted, the only difference is whether
808 In all cases the kernel is restarted, the only difference is whether
792 it is given a chance to perform a clean shutdown or not.
809 it is given a chance to perform a clean shutdown or not.
793
810
794 **kw : optional
811 **kw : optional
795 Any options specified here will replace those used to launch the
812 Any options specified here will replace those used to launch the
796 kernel.
813 kernel.
797 """
814 """
798 if self._launch_args is None:
815 if self._launch_args is None:
799 raise RuntimeError("Cannot restart the kernel. "
816 raise RuntimeError("Cannot restart the kernel. "
800 "No previous call to 'start_kernel'.")
817 "No previous call to 'start_kernel'.")
801 else:
818 else:
802 # Stop currently running kernel.
819 # Stop currently running kernel.
803 if self.has_kernel:
820 if self.has_kernel:
804 if now:
821 if now:
805 self.kill_kernel()
822 self.kill_kernel()
806 else:
823 else:
807 self.shutdown_kernel(restart=True)
824 self.shutdown_kernel(restart=True)
808
825
809 # Start new kernel.
826 # Start new kernel.
810 self._launch_args.update(kw)
827 self._launch_args.update(kw)
811 self.start_kernel(**self._launch_args)
828 self.start_kernel(**self._launch_args)
812
829
813 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
830 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
814 # unless there is some delay here.
831 # unless there is some delay here.
815 if sys.platform == 'win32':
832 if sys.platform == 'win32':
816 time.sleep(0.2)
833 time.sleep(0.2)
817
834
818 @property
835 @property
819 def has_kernel(self):
836 def has_kernel(self):
820 """Returns whether a kernel process has been specified for the kernel
837 """Returns whether a kernel process has been specified for the kernel
821 manager.
838 manager.
822 """
839 """
823 return self.kernel is not None
840 return self.kernel is not None
824
841
825 def kill_kernel(self):
842 def kill_kernel(self):
826 """ Kill the running kernel. """
843 """ Kill the running kernel. """
827 if self.has_kernel:
844 if self.has_kernel:
828 # Pause the heart beat channel if it exists.
845 # Pause the heart beat channel if it exists.
829 if self._hb_channel is not None:
846 if self._hb_channel is not None:
830 self._hb_channel.pause()
847 self._hb_channel.pause()
831
848
832 # Attempt to kill the kernel.
849 # Attempt to kill the kernel.
833 try:
850 try:
834 self.kernel.kill()
851 self.kernel.kill()
835 except OSError, e:
852 except OSError, e:
836 # In Windows, we will get an Access Denied error if the process
853 # In Windows, we will get an Access Denied error if the process
837 # has already terminated. Ignore it.
854 # has already terminated. Ignore it.
838 if not (sys.platform == 'win32' and e.winerror == 5):
855 if not (sys.platform == 'win32' and e.winerror == 5):
839 raise
856 raise
840 self.kernel = None
857 self.kernel = None
841 else:
858 else:
842 raise RuntimeError("Cannot kill kernel. No kernel is running!")
859 raise RuntimeError("Cannot kill kernel. No kernel is running!")
843
860
844 def interrupt_kernel(self):
861 def interrupt_kernel(self):
845 """ Interrupts the kernel. Unlike ``signal_kernel``, this operation is
862 """ Interrupts the kernel. Unlike ``signal_kernel``, this operation is
846 well supported on all platforms.
863 well supported on all platforms.
847 """
864 """
848 if self.has_kernel:
865 if self.has_kernel:
849 if sys.platform == 'win32':
866 if sys.platform == 'win32':
850 from parentpoller import ParentPollerWindows as Poller
867 from parentpoller import ParentPollerWindows as Poller
851 Poller.send_interrupt(self.kernel.win32_interrupt_event)
868 Poller.send_interrupt(self.kernel.win32_interrupt_event)
852 else:
869 else:
853 self.kernel.send_signal(signal.SIGINT)
870 self.kernel.send_signal(signal.SIGINT)
854 else:
871 else:
855 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
872 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
856
873
857 def signal_kernel(self, signum):
874 def signal_kernel(self, signum):
858 """ Sends a signal to the kernel. Note that since only SIGTERM is
875 """ Sends a signal to the kernel. Note that since only SIGTERM is
859 supported on Windows, this function is only useful on Unix systems.
876 supported on Windows, this function is only useful on Unix systems.
860 """
877 """
861 if self.has_kernel:
878 if self.has_kernel:
862 self.kernel.send_signal(signum)
879 self.kernel.send_signal(signum)
863 else:
880 else:
864 raise RuntimeError("Cannot signal kernel. No kernel is running!")
881 raise RuntimeError("Cannot signal kernel. No kernel is running!")
865
882
866 @property
883 @property
867 def is_alive(self):
884 def is_alive(self):
868 """Is the kernel process still running?"""
885 """Is the kernel process still running?"""
869 # FIXME: not using a heartbeat means this method is broken for any
886 # FIXME: not using a heartbeat means this method is broken for any
870 # remote kernel, it's only capable of handling local kernels.
887 # remote kernel, it's only capable of handling local kernels.
871 if self.has_kernel:
888 if self.has_kernel:
872 if self.kernel.poll() is None:
889 if self.kernel.poll() is None:
873 return True
890 return True
874 else:
891 else:
875 return False
892 return False
876 else:
893 else:
877 # We didn't start the kernel with this KernelManager so we don't
894 # We didn't start the kernel with this KernelManager so we don't
878 # know if it is running. We should use a heartbeat for this case.
895 # know if it is running. We should use a heartbeat for this case.
879 return True
896 return True
880
897
881 #--------------------------------------------------------------------------
898 #--------------------------------------------------------------------------
882 # Channels used for communication with the kernel:
899 # Channels used for communication with the kernel:
883 #--------------------------------------------------------------------------
900 #--------------------------------------------------------------------------
884
901
885 @property
902 @property
886 def xreq_channel(self):
903 def xreq_channel(self):
887 """Get the REQ socket channel object to make requests of the kernel."""
904 """Get the REQ socket channel object to make requests of the kernel."""
888 if self._xreq_channel is None:
905 if self._xreq_channel is None:
889 self._xreq_channel = self.xreq_channel_class(self.context,
906 self._xreq_channel = self.xreq_channel_class(self.context,
890 self.session,
907 self.session,
891 self.xreq_address)
908 self.xreq_address)
892 return self._xreq_channel
909 return self._xreq_channel
893
910
894 @property
911 @property
895 def sub_channel(self):
912 def sub_channel(self):
896 """Get the SUB socket channel object."""
913 """Get the SUB socket channel object."""
897 if self._sub_channel is None:
914 if self._sub_channel is None:
898 self._sub_channel = self.sub_channel_class(self.context,
915 self._sub_channel = self.sub_channel_class(self.context,
899 self.session,
916 self.session,
900 self.sub_address)
917 self.sub_address)
901 return self._sub_channel
918 return self._sub_channel
902
919
903 @property
920 @property
904 def rep_channel(self):
921 def rep_channel(self):
905 """Get the REP socket channel object to handle stdin (raw_input)."""
922 """Get the REP socket channel object to handle stdin (raw_input)."""
906 if self._rep_channel is None:
923 if self._rep_channel is None:
907 self._rep_channel = self.rep_channel_class(self.context,
924 self._rep_channel = self.rep_channel_class(self.context,
908 self.session,
925 self.session,
909 self.rep_address)
926 self.rep_address)
910 return self._rep_channel
927 return self._rep_channel
911
928
912 @property
929 @property
913 def hb_channel(self):
930 def hb_channel(self):
914 """Get the heartbeat socket channel object to check that the
931 """Get the heartbeat socket channel object to check that the
915 kernel is alive."""
932 kernel is alive."""
916 if self._hb_channel is None:
933 if self._hb_channel is None:
917 self._hb_channel = self.hb_channel_class(self.context,
934 self._hb_channel = self.hb_channel_class(self.context,
918 self.session,
935 self.session,
919 self.hb_address)
936 self.hb_address)
920 return self._hb_channel
937 return self._hb_channel
@@ -1,924 +1,937
1 .. _messaging:
1 .. _messaging:
2
2
3 ======================
3 ======================
4 Messaging in IPython
4 Messaging in IPython
5 ======================
5 ======================
6
6
7
7
8 Introduction
8 Introduction
9 ============
9 ============
10
10
11 This document explains the basic communications design and messaging
11 This document explains the basic communications design and messaging
12 specification for how the various IPython objects interact over a network
12 specification for how the various IPython objects interact over a network
13 transport. The current implementation uses the ZeroMQ_ library for messaging
13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 within and between hosts.
14 within and between hosts.
15
15
16 .. Note::
16 .. Note::
17
17
18 This document should be considered the authoritative description of the
18 This document should be considered the authoritative description of the
19 IPython messaging protocol, and all developers are strongly encouraged to
19 IPython messaging protocol, and all developers are strongly encouraged to
20 keep it updated as the implementation evolves, so that we have a single
20 keep it updated as the implementation evolves, so that we have a single
21 common reference for all protocol details.
21 common reference for all protocol details.
22
22
23 The basic design is explained in the following diagram:
23 The basic design is explained in the following diagram:
24
24
25 .. image:: frontend-kernel.png
25 .. image:: frontend-kernel.png
26 :width: 450px
26 :width: 450px
27 :alt: IPython kernel/frontend messaging architecture.
27 :alt: IPython kernel/frontend messaging architecture.
28 :align: center
28 :align: center
29 :target: ../_images/frontend-kernel.png
29 :target: ../_images/frontend-kernel.png
30
30
31 A single kernel can be simultaneously connected to one or more frontends. The
31 A single kernel can be simultaneously connected to one or more frontends. The
32 kernel has three sockets that serve the following functions:
32 kernel has three sockets that serve the following functions:
33
33
34 1. REQ: this socket is connected to a *single* frontend at a time, and it allows
34 1. REQ: this socket is connected to a *single* frontend at a time, and it allows
35 the kernel to request input from a frontend when :func:`raw_input` is called.
35 the kernel to request input from a frontend when :func:`raw_input` is called.
36 The frontend holding the matching REP socket acts as a 'virtual keyboard'
36 The frontend holding the matching REP socket acts as a 'virtual keyboard'
37 for the kernel while this communication is happening (illustrated in the
37 for the kernel while this communication is happening (illustrated in the
38 figure by the black outline around the central keyboard). In practice,
38 figure by the black outline around the central keyboard). In practice,
39 frontends may display such kernel requests using a special input widget or
39 frontends may display such kernel requests using a special input widget or
40 otherwise indicating that the user is to type input for the kernel instead
40 otherwise indicating that the user is to type input for the kernel instead
41 of normal commands in the frontend.
41 of normal commands in the frontend.
42
42
43 2. XREP: this single sockets allows multiple incoming connections from
43 2. XREP: this single sockets allows multiple incoming connections from
44 frontends, and this is the socket where requests for code execution, object
44 frontends, and this is the socket where requests for code execution, object
45 information, prompts, etc. are made to the kernel by any frontend. The
45 information, prompts, etc. are made to the kernel by any frontend. The
46 communication on this socket is a sequence of request/reply actions from
46 communication on this socket is a sequence of request/reply actions from
47 each frontend and the kernel.
47 each frontend and the kernel.
48
48
49 3. PUB: this socket is the 'broadcast channel' where the kernel publishes all
49 3. PUB: this socket is the 'broadcast channel' where the kernel publishes all
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 client over the XREP socket and its own requests on the REP socket. There
51 client over the XREP socket and its own requests on the REP socket. There
52 are a number of actions in Python which generate side effects: :func:`print`
52 are a number of actions in Python which generate side effects: :func:`print`
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 a multi-client scenario, we want all frontends to be able to know what each
54 a multi-client scenario, we want all frontends to be able to know what each
55 other has sent to the kernel (this can be useful in collaborative scenarios,
55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 for example). This socket allows both side effects and the information
56 for example). This socket allows both side effects and the information
57 about communications taking place with one client over the XREQ/XREP channel
57 about communications taking place with one client over the XREQ/XREP channel
58 to be made available to all clients in a uniform manner.
58 to be made available to all clients in a uniform manner.
59
59
60 All messages are tagged with enough information (details below) for clients
60 All messages are tagged with enough information (details below) for clients
61 to know which messages come from their own interaction with the kernel and
61 to know which messages come from their own interaction with the kernel and
62 which ones are from other clients, so they can display each type
62 which ones are from other clients, so they can display each type
63 appropriately.
63 appropriately.
64
64
65 The actual format of the messages allowed on each of these channels is
65 The actual format of the messages allowed on each of these channels is
66 specified below. Messages are dicts of dicts with string keys and values that
66 specified below. Messages are dicts of dicts with string keys and values that
67 are reasonably representable in JSON. Our current implementation uses JSON
67 are reasonably representable in JSON. Our current implementation uses JSON
68 explicitly as its message format, but this shouldn't be considered a permanent
68 explicitly as its message format, but this shouldn't be considered a permanent
69 feature. As we've discovered that JSON has non-trivial performance issues due
69 feature. As we've discovered that JSON has non-trivial performance issues due
70 to excessive copying, we may in the future move to a pure pickle-based raw
70 to excessive copying, we may in the future move to a pure pickle-based raw
71 message format. However, it should be possible to easily convert from the raw
71 message format. However, it should be possible to easily convert from the raw
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 As long as it's easy to make a JSON version of the objects that is a faithful
73 As long as it's easy to make a JSON version of the objects that is a faithful
74 representation of all the data, we can communicate with such clients.
74 representation of all the data, we can communicate with such clients.
75
75
76 .. Note::
76 .. Note::
77
77
78 Not all of these have yet been fully fleshed out, but the key ones are, see
78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 kernel and frontend files for actual implementation details.
79 kernel and frontend files for actual implementation details.
80
80
81
81
82 Python functional API
82 Python functional API
83 =====================
83 =====================
84
84
85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
86 should develop, at a few key points, functional forms of all the requests that
86 should develop, at a few key points, functional forms of all the requests that
87 take arguments in this manner and automatically construct the necessary dict
87 take arguments in this manner and automatically construct the necessary dict
88 for sending.
88 for sending.
89
89
90
90
91 General Message Format
91 General Message Format
92 ======================
92 ======================
93
93
94 All messages send or received by any IPython process should have the following
94 All messages send or received by any IPython process should have the following
95 generic structure::
95 generic structure::
96
96
97 {
97 {
98 # The message header contains a pair of unique identifiers for the
98 # The message header contains a pair of unique identifiers for the
99 # originating session and the actual message id, in addition to the
99 # originating session and the actual message id, in addition to the
100 # username for the process that generated the message. This is useful in
100 # username for the process that generated the message. This is useful in
101 # collaborative settings where multiple users may be interacting with the
101 # collaborative settings where multiple users may be interacting with the
102 # same kernel simultaneously, so that frontends can label the various
102 # same kernel simultaneously, so that frontends can label the various
103 # messages in a meaningful way.
103 # messages in a meaningful way.
104 'header' : { 'msg_id' : uuid,
104 'header' : { 'msg_id' : uuid,
105 'username' : str,
105 'username' : str,
106 'session' : uuid
106 'session' : uuid
107 },
107 },
108
108
109 # In a chain of messages, the header from the parent is copied so that
109 # In a chain of messages, the header from the parent is copied so that
110 # clients can track where messages come from.
110 # clients can track where messages come from.
111 'parent_header' : dict,
111 'parent_header' : dict,
112
112
113 # All recognized message type strings are listed below.
113 # All recognized message type strings are listed below.
114 'msg_type' : str,
114 'msg_type' : str,
115
115
116 # The actual content of the message must be a dict, whose structure
116 # The actual content of the message must be a dict, whose structure
117 # depends on the message type.x
117 # depends on the message type.x
118 'content' : dict,
118 'content' : dict,
119 }
119 }
120
120
121 For each message type, the actual content will differ and all existing message
121 For each message type, the actual content will differ and all existing message
122 types are specified in what follows of this document.
122 types are specified in what follows of this document.
123
123
124
124
125 Messages on the XREP/XREQ socket
125 Messages on the XREP/XREQ socket
126 ================================
126 ================================
127
127
128 .. _execute:
128 .. _execute:
129
129
130 Execute
130 Execute
131 -------
131 -------
132
132
133 This message type is used by frontends to ask the kernel to execute code on
133 This message type is used by frontends to ask the kernel to execute code on
134 behalf of the user, in a namespace reserved to the user's variables (and thus
134 behalf of the user, in a namespace reserved to the user's variables (and thus
135 separate from the kernel's own internal code and variables).
135 separate from the kernel's own internal code and variables).
136
136
137 Message type: ``execute_request``::
137 Message type: ``execute_request``::
138
138
139 content = {
139 content = {
140 # Source code to be executed by the kernel, one or more lines.
140 # Source code to be executed by the kernel, one or more lines.
141 'code' : str,
141 'code' : str,
142
142
143 # A boolean flag which, if True, signals the kernel to execute this
143 # A boolean flag which, if True, signals the kernel to execute this
144 # code as quietly as possible. This means that the kernel will compile
144 # code as quietly as possible. This means that the kernel will compile
145 # the code witIPython/core/tests/h 'exec' instead of 'single' (so
145 # the code witIPython/core/tests/h 'exec' instead of 'single' (so
146 # sys.displayhook will not fire), and will *not*:
146 # sys.displayhook will not fire), and will *not*:
147 # - broadcast exceptions on the PUB socket
147 # - broadcast exceptions on the PUB socket
148 # - do any logging
148 # - do any logging
149 # - populate any history
149 # - populate any history
150 #
150 #
151 # The default is False.
151 # The default is False.
152 'silent' : bool,
152 'silent' : bool,
153
153
154 # A list of variable names from the user's namespace to be retrieved. What
154 # A list of variable names from the user's namespace to be retrieved. What
155 # returns is a JSON string of the variable's repr(), not a python object.
155 # returns is a JSON string of the variable's repr(), not a python object.
156 'user_variables' : list,
156 'user_variables' : list,
157
157
158 # Similarly, a dict mapping names to expressions to be evaluated in the
158 # Similarly, a dict mapping names to expressions to be evaluated in the
159 # user's dict.
159 # user's dict.
160 'user_expressions' : dict,
160 'user_expressions' : dict,
161 }
161 }
162
162
163 The ``code`` field contains a single string (possibly multiline). The kernel
163 The ``code`` field contains a single string (possibly multiline). The kernel
164 is responsible for splitting this into one or more independent execution blocks
164 is responsible for splitting this into one or more independent execution blocks
165 and deciding whether to compile these in 'single' or 'exec' mode (see below for
165 and deciding whether to compile these in 'single' or 'exec' mode (see below for
166 detailed execution semantics).
166 detailed execution semantics).
167
167
168 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
168 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
169 the notion of a prompt string that allowed arbitrary code to be evaluated, and
169 the notion of a prompt string that allowed arbitrary code to be evaluated, and
170 this was put to good use by many in creating prompts that displayed system
170 this was put to good use by many in creating prompts that displayed system
171 status, path information, and even more esoteric uses like remote instrument
171 status, path information, and even more esoteric uses like remote instrument
172 status aqcuired over the network. But now that IPython has a clean separation
172 status aqcuired over the network. But now that IPython has a clean separation
173 between the kernel and the clients, the kernel has no prompt knowledge; prompts
173 between the kernel and the clients, the kernel has no prompt knowledge; prompts
174 are a frontend-side feature, and it should be even possible for different
174 are a frontend-side feature, and it should be even possible for different
175 frontends to display different prompts while interacting with the same kernel.
175 frontends to display different prompts while interacting with the same kernel.
176
176
177 The kernel now provides the ability to retrieve data from the user's namespace
177 The kernel now provides the ability to retrieve data from the user's namespace
178 after the execution of the main ``code``, thanks to two fields in the
178 after the execution of the main ``code``, thanks to two fields in the
179 ``execute_request`` message:
179 ``execute_request`` message:
180
180
181 - ``user_variables``: If only variables from the user's namespace are needed, a
181 - ``user_variables``: If only variables from the user's namespace are needed, a
182 list of variable names can be passed and a dict with these names as keys and
182 list of variable names can be passed and a dict with these names as keys and
183 their :func:`repr()` as values will be returned.
183 their :func:`repr()` as values will be returned.
184
184
185 - ``user_expressions``: For more complex expressions that require function
185 - ``user_expressions``: For more complex expressions that require function
186 evaluations, a dict can be provided with string keys and arbitrary python
186 evaluations, a dict can be provided with string keys and arbitrary python
187 expressions as values. The return message will contain also a dict with the
187 expressions as values. The return message will contain also a dict with the
188 same keys and the :func:`repr()` of the evaluated expressions as value.
188 same keys and the :func:`repr()` of the evaluated expressions as value.
189
189
190 With this information, frontends can display any status information they wish
190 With this information, frontends can display any status information they wish
191 in the form that best suits each frontend (a status line, a popup, inline for a
191 in the form that best suits each frontend (a status line, a popup, inline for a
192 terminal, etc).
192 terminal, etc).
193
193
194 .. Note::
194 .. Note::
195
195
196 In order to obtain the current execution counter for the purposes of
196 In order to obtain the current execution counter for the purposes of
197 displaying input prompts, frontends simply make an execution request with an
197 displaying input prompts, frontends simply make an execution request with an
198 empty code string and ``silent=True``.
198 empty code string and ``silent=True``.
199
199
200 Execution semantics
200 Execution semantics
201 ~~~~~~~~~~~~~~~~~~~
201 ~~~~~~~~~~~~~~~~~~~
202
202
203 When the silent flag is false, the execution of use code consists of the
203 When the silent flag is false, the execution of use code consists of the
204 following phases (in silent mode, only the ``code`` field is executed):
204 following phases (in silent mode, only the ``code`` field is executed):
205
205
206 1. Run the ``pre_runcode_hook``.
206 1. Run the ``pre_runcode_hook``.
207
207
208 2. Execute the ``code`` field, see below for details.
208 2. Execute the ``code`` field, see below for details.
209
209
210 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
210 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
211 computed. This ensures that any error in the latter don't harm the main
211 computed. This ensures that any error in the latter don't harm the main
212 code execution.
212 code execution.
213
213
214 4. Call any method registered with :meth:`register_post_execute`.
214 4. Call any method registered with :meth:`register_post_execute`.
215
215
216 .. warning::
216 .. warning::
217
217
218 The API for running code before/after the main code block is likely to
218 The API for running code before/after the main code block is likely to
219 change soon. Both the ``pre_runcode_hook`` and the
219 change soon. Both the ``pre_runcode_hook`` and the
220 :meth:`register_post_execute` are susceptible to modification, as we find a
220 :meth:`register_post_execute` are susceptible to modification, as we find a
221 consistent model for both.
221 consistent model for both.
222
222
223 To understand how the ``code`` field is executed, one must know that Python
223 To understand how the ``code`` field is executed, one must know that Python
224 code can be compiled in one of three modes (controlled by the ``mode`` argument
224 code can be compiled in one of three modes (controlled by the ``mode`` argument
225 to the :func:`compile` builtin):
225 to the :func:`compile` builtin):
226
226
227 *single*
227 *single*
228 Valid for a single interactive statement (though the source can contain
228 Valid for a single interactive statement (though the source can contain
229 multiple lines, such as a for loop). When compiled in this mode, the
229 multiple lines, such as a for loop). When compiled in this mode, the
230 generated bytecode contains special instructions that trigger the calling of
230 generated bytecode contains special instructions that trigger the calling of
231 :func:`sys.displayhook` for any expression in the block that returns a value.
231 :func:`sys.displayhook` for any expression in the block that returns a value.
232 This means that a single statement can actually produce multiple calls to
232 This means that a single statement can actually produce multiple calls to
233 :func:`sys.displayhook`, if for example it contains a loop where each
233 :func:`sys.displayhook`, if for example it contains a loop where each
234 iteration computes an unassigned expression would generate 10 calls::
234 iteration computes an unassigned expression would generate 10 calls::
235
235
236 for i in range(10):
236 for i in range(10):
237 i**2
237 i**2
238
238
239 *exec*
239 *exec*
240 An arbitrary amount of source code, this is how modules are compiled.
240 An arbitrary amount of source code, this is how modules are compiled.
241 :func:`sys.displayhook` is *never* implicitly called.
241 :func:`sys.displayhook` is *never* implicitly called.
242
242
243 *eval*
243 *eval*
244 A single expression that returns a value. :func:`sys.displayhook` is *never*
244 A single expression that returns a value. :func:`sys.displayhook` is *never*
245 implicitly called.
245 implicitly called.
246
246
247
247
248 The ``code`` field is split into individual blocks each of which is valid for
248 The ``code`` field is split into individual blocks each of which is valid for
249 execution in 'single' mode, and then:
249 execution in 'single' mode, and then:
250
250
251 - If there is only a single block: it is executed in 'single' mode.
251 - If there is only a single block: it is executed in 'single' mode.
252
252
253 - If there is more than one block:
253 - If there is more than one block:
254
254
255 * if the last one is a single line long, run all but the last in 'exec' mode
255 * if the last one is a single line long, run all but the last in 'exec' mode
256 and the very last one in 'single' mode. This makes it easy to type simple
256 and the very last one in 'single' mode. This makes it easy to type simple
257 expressions at the end to see computed values.
257 expressions at the end to see computed values.
258
258
259 * if the last one is no more than two lines long, run all but the last in
259 * if the last one is no more than two lines long, run all but the last in
260 'exec' mode and the very last one in 'single' mode. This makes it easy to
260 'exec' mode and the very last one in 'single' mode. This makes it easy to
261 type simple expressions at the end to see computed values. - otherwise
261 type simple expressions at the end to see computed values. - otherwise
262 (last one is also multiline), run all in 'exec' mode
262 (last one is also multiline), run all in 'exec' mode
263
263
264 * otherwise (last one is also multiline), run all in 'exec' mode as a single
264 * otherwise (last one is also multiline), run all in 'exec' mode as a single
265 unit.
265 unit.
266
266
267 Any error in retrieving the ``user_variables`` or evaluating the
267 Any error in retrieving the ``user_variables`` or evaluating the
268 ``user_expressions`` will result in a simple error message in the return fields
268 ``user_expressions`` will result in a simple error message in the return fields
269 of the form::
269 of the form::
270
270
271 [ERROR] ExceptionType: Exception message
271 [ERROR] ExceptionType: Exception message
272
272
273 The user can simply send the same variable name or expression for evaluation to
273 The user can simply send the same variable name or expression for evaluation to
274 see a regular traceback.
274 see a regular traceback.
275
275
276 Errors in any registered post_execute functions are also reported similarly,
276 Errors in any registered post_execute functions are also reported similarly,
277 and the failing function is removed from the post_execution set so that it does
277 and the failing function is removed from the post_execution set so that it does
278 not continue triggering failures.
278 not continue triggering failures.
279
279
280 Upon completion of the execution request, the kernel *always* sends a reply,
280 Upon completion of the execution request, the kernel *always* sends a reply,
281 with a status code indicating what happened and additional data depending on
281 with a status code indicating what happened and additional data depending on
282 the outcome. See :ref:`below <execution_results>` for the possible return
282 the outcome. See :ref:`below <execution_results>` for the possible return
283 codes and associated data.
283 codes and associated data.
284
284
285
285
286 Execution counter (old prompt number)
286 Execution counter (old prompt number)
287 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
288
288
289 The kernel has a single, monotonically increasing counter of all execution
289 The kernel has a single, monotonically increasing counter of all execution
290 requests that are made with ``silent=False``. This counter is used to populate
290 requests that are made with ``silent=False``. This counter is used to populate
291 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
291 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
292 display it in some form to the user, which will typically (but not necessarily)
292 display it in some form to the user, which will typically (but not necessarily)
293 be done in the prompts. The value of this counter will be returned as the
293 be done in the prompts. The value of this counter will be returned as the
294 ``execution_count`` field of all ``execute_reply`` messages.
294 ``execution_count`` field of all ``execute_reply`` messages.
295
295
296 .. _execution_results:
296 .. _execution_results:
297
297
298 Execution results
298 Execution results
299 ~~~~~~~~~~~~~~~~~
299 ~~~~~~~~~~~~~~~~~
300
300
301 Message type: ``execute_reply``::
301 Message type: ``execute_reply``::
302
302
303 content = {
303 content = {
304 # One of: 'ok' OR 'error' OR 'abort'
304 # One of: 'ok' OR 'error' OR 'abort'
305 'status' : str,
305 'status' : str,
306
306
307 # The global kernel counter that increases by one with each non-silent
307 # The global kernel counter that increases by one with each non-silent
308 # executed request. This will typically be used by clients to display
308 # executed request. This will typically be used by clients to display
309 # prompt numbers to the user. If the request was a silent one, this will
309 # prompt numbers to the user. If the request was a silent one, this will
310 # be the current value of the counter in the kernel.
310 # be the current value of the counter in the kernel.
311 'execution_count' : int,
311 'execution_count' : int,
312 }
312 }
313
313
314 When status is 'ok', the following extra fields are present::
314 When status is 'ok', the following extra fields are present::
315
315
316 {
316 {
317 # The execution payload is a dict with string keys that may have been
317 # The execution payload is a dict with string keys that may have been
318 # produced by the code being executed. It is retrieved by the kernel at
318 # produced by the code being executed. It is retrieved by the kernel at
319 # the end of the execution and sent back to the front end, which can take
319 # the end of the execution and sent back to the front end, which can take
320 # action on it as needed. See main text for further details.
320 # action on it as needed. See main text for further details.
321 'payload' : dict,
321 'payload' : dict,
322
322
323 # Results for the user_variables and user_expressions.
323 # Results for the user_variables and user_expressions.
324 'user_variables' : dict,
324 'user_variables' : dict,
325 'user_expressions' : dict,
325 'user_expressions' : dict,
326
326
327 # The kernel will often transform the input provided to it. If the
327 # The kernel will often transform the input provided to it. If the
328 # '---->' transform had been applied, this is filled, otherwise it's the
328 # '---->' transform had been applied, this is filled, otherwise it's the
329 # empty string. So transformations like magics don't appear here, only
329 # empty string. So transformations like magics don't appear here, only
330 # autocall ones.
330 # autocall ones.
331 'transformed_code' : str,
331 'transformed_code' : str,
332 }
332 }
333
333
334 .. admonition:: Execution payloads
334 .. admonition:: Execution payloads
335
335
336 The notion of an 'execution payload' is different from a return value of a
336 The notion of an 'execution payload' is different from a return value of a
337 given set of code, which normally is just displayed on the pyout stream
337 given set of code, which normally is just displayed on the pyout stream
338 through the PUB socket. The idea of a payload is to allow special types of
338 through the PUB socket. The idea of a payload is to allow special types of
339 code, typically magics, to populate a data container in the IPython kernel
339 code, typically magics, to populate a data container in the IPython kernel
340 that will be shipped back to the caller via this channel. The kernel will
340 that will be shipped back to the caller via this channel. The kernel will
341 have an API for this, probably something along the lines of::
341 have an API for this, probably something along the lines of::
342
342
343 ip.exec_payload_add(key, value)
343 ip.exec_payload_add(key, value)
344
344
345 though this API is still in the design stages. The data returned in this
345 though this API is still in the design stages. The data returned in this
346 payload will allow frontends to present special views of what just happened.
346 payload will allow frontends to present special views of what just happened.
347
347
348
348
349 When status is 'error', the following extra fields are present::
349 When status is 'error', the following extra fields are present::
350
350
351 {
351 {
352 'exc_name' : str, # Exception name, as a string
352 'exc_name' : str, # Exception name, as a string
353 'exc_value' : str, # Exception value, as a string
353 'exc_value' : str, # Exception value, as a string
354
354
355 # The traceback will contain a list of frames, represented each as a
355 # The traceback will contain a list of frames, represented each as a
356 # string. For now we'll stick to the existing design of ultraTB, which
356 # string. For now we'll stick to the existing design of ultraTB, which
357 # controls exception level of detail statefully. But eventually we'll
357 # controls exception level of detail statefully. But eventually we'll
358 # want to grow into a model where more information is collected and
358 # want to grow into a model where more information is collected and
359 # packed into the traceback object, with clients deciding how little or
359 # packed into the traceback object, with clients deciding how little or
360 # how much of it to unpack. But for now, let's start with a simple list
360 # how much of it to unpack. But for now, let's start with a simple list
361 # of strings, since that requires only minimal changes to ultratb as
361 # of strings, since that requires only minimal changes to ultratb as
362 # written.
362 # written.
363 'traceback' : list,
363 'traceback' : list,
364 }
364 }
365
365
366
366
367 When status is 'abort', there are for now no additional data fields. This
367 When status is 'abort', there are for now no additional data fields. This
368 happens when the kernel was interrupted by a signal.
368 happens when the kernel was interrupted by a signal.
369
369
370 Kernel attribute access
370 Kernel attribute access
371 -----------------------
371 -----------------------
372
372
373 .. warning::
373 .. warning::
374
374
375 This part of the messaging spec is not actually implemented in the kernel
375 This part of the messaging spec is not actually implemented in the kernel
376 yet.
376 yet.
377
377
378 While this protocol does not specify full RPC access to arbitrary methods of
378 While this protocol does not specify full RPC access to arbitrary methods of
379 the kernel object, the kernel does allow read (and in some cases write) access
379 the kernel object, the kernel does allow read (and in some cases write) access
380 to certain attributes.
380 to certain attributes.
381
381
382 The policy for which attributes can be read is: any attribute of the kernel, or
382 The policy for which attributes can be read is: any attribute of the kernel, or
383 its sub-objects, that belongs to a :class:`Configurable` object and has been
383 its sub-objects, that belongs to a :class:`Configurable` object and has been
384 declared at the class-level with Traits validation, is in principle accessible
384 declared at the class-level with Traits validation, is in principle accessible
385 as long as its name does not begin with a leading underscore. The attribute
385 as long as its name does not begin with a leading underscore. The attribute
386 itself will have metadata indicating whether it allows remote read and/or write
386 itself will have metadata indicating whether it allows remote read and/or write
387 access. The message spec follows for attribute read and write requests.
387 access. The message spec follows for attribute read and write requests.
388
388
389 Message type: ``getattr_request``::
389 Message type: ``getattr_request``::
390
390
391 content = {
391 content = {
392 # The (possibly dotted) name of the attribute
392 # The (possibly dotted) name of the attribute
393 'name' : str,
393 'name' : str,
394 }
394 }
395
395
396 When a ``getattr_request`` fails, there are two possible error types:
396 When a ``getattr_request`` fails, there are two possible error types:
397
397
398 - AttributeError: this type of error was raised when trying to access the
398 - AttributeError: this type of error was raised when trying to access the
399 given name by the kernel itself. This means that the attribute likely
399 given name by the kernel itself. This means that the attribute likely
400 doesn't exist.
400 doesn't exist.
401
401
402 - AccessError: the attribute exists but its value is not readable remotely.
402 - AccessError: the attribute exists but its value is not readable remotely.
403
403
404
404
405 Message type: ``getattr_reply``::
405 Message type: ``getattr_reply``::
406
406
407 content = {
407 content = {
408 # One of ['ok', 'AttributeError', 'AccessError'].
408 # One of ['ok', 'AttributeError', 'AccessError'].
409 'status' : str,
409 'status' : str,
410 # If status is 'ok', a JSON object.
410 # If status is 'ok', a JSON object.
411 'value' : object,
411 'value' : object,
412 }
412 }
413
413
414 Message type: ``setattr_request``::
414 Message type: ``setattr_request``::
415
415
416 content = {
416 content = {
417 # The (possibly dotted) name of the attribute
417 # The (possibly dotted) name of the attribute
418 'name' : str,
418 'name' : str,
419
419
420 # A JSON-encoded object, that will be validated by the Traits
420 # A JSON-encoded object, that will be validated by the Traits
421 # information in the kernel
421 # information in the kernel
422 'value' : object,
422 'value' : object,
423 }
423 }
424
424
425 When a ``setattr_request`` fails, there are also two possible error types with
425 When a ``setattr_request`` fails, there are also two possible error types with
426 similar meanings as those of the ``getattr_request`` case, but for writing.
426 similar meanings as those of the ``getattr_request`` case, but for writing.
427
427
428 Message type: ``setattr_reply``::
428 Message type: ``setattr_reply``::
429
429
430 content = {
430 content = {
431 # One of ['ok', 'AttributeError', 'AccessError'].
431 # One of ['ok', 'AttributeError', 'AccessError'].
432 'status' : str,
432 'status' : str,
433 }
433 }
434
434
435
435
436
436
437 Object information
437 Object information
438 ------------------
438 ------------------
439
439
440 One of IPython's most used capabilities is the introspection of Python objects
440 One of IPython's most used capabilities is the introspection of Python objects
441 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
441 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
442 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
442 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
443 enough that it warrants an explicit message type, especially because frontends
443 enough that it warrants an explicit message type, especially because frontends
444 may want to get object information in response to user keystrokes (like Tab or
444 may want to get object information in response to user keystrokes (like Tab or
445 F1) besides from the user explicitly typing code like ``x??``.
445 F1) besides from the user explicitly typing code like ``x??``.
446
446
447 Message type: ``object_info_request``::
447 Message type: ``object_info_request``::
448
448
449 content = {
449 content = {
450 # The (possibly dotted) name of the object to be searched in all
450 # The (possibly dotted) name of the object to be searched in all
451 # relevant namespaces
451 # relevant namespaces
452 'name' : str,
452 'name' : str,
453
453
454 # The level of detail desired. The default (0) is equivalent to typing
454 # The level of detail desired. The default (0) is equivalent to typing
455 # 'x?' at the prompt, 1 is equivalent to 'x??'.
455 # 'x?' at the prompt, 1 is equivalent to 'x??'.
456 'detail_level' : int,
456 'detail_level' : int,
457 }
457 }
458
458
459 The returned information will be a dictionary with keys very similar to the
459 The returned information will be a dictionary with keys very similar to the
460 field names that IPython prints at the terminal.
460 field names that IPython prints at the terminal.
461
461
462 Message type: ``object_info_reply``::
462 Message type: ``object_info_reply``::
463
463
464 content = {
464 content = {
465 # The name the object was requested under
465 # The name the object was requested under
466 'name' : str,
466 'name' : str,
467
467
468 # Boolean flag indicating whether the named object was found or not. If
468 # Boolean flag indicating whether the named object was found or not. If
469 # it's false, all other fields will be empty.
469 # it's false, all other fields will be empty.
470 'found' : bool,
470 'found' : bool,
471
471
472 # Flags for magics and system aliases
472 # Flags for magics and system aliases
473 'ismagic' : bool,
473 'ismagic' : bool,
474 'isalias' : bool,
474 'isalias' : bool,
475
475
476 # The name of the namespace where the object was found ('builtin',
476 # The name of the namespace where the object was found ('builtin',
477 # 'magics', 'alias', 'interactive', etc.)
477 # 'magics', 'alias', 'interactive', etc.)
478 'namespace' : str,
478 'namespace' : str,
479
479
480 # The type name will be type.__name__ for normal Python objects, but it
480 # The type name will be type.__name__ for normal Python objects, but it
481 # can also be a string like 'Magic function' or 'System alias'
481 # can also be a string like 'Magic function' or 'System alias'
482 'type_name' : str,
482 'type_name' : str,
483
483
484 # The string form of the object, possibly truncated for length if
484 # The string form of the object, possibly truncated for length if
485 # detail_level is 0
485 # detail_level is 0
486 'string_form' : str,
486 'string_form' : str,
487
487
488 # For objects with a __class__ attribute this will be set
488 # For objects with a __class__ attribute this will be set
489 'base_class' : str,
489 'base_class' : str,
490
490
491 # For objects with a __len__ attribute this will be set
491 # For objects with a __len__ attribute this will be set
492 'length' : int,
492 'length' : int,
493
493
494 # If the object is a function, class or method whose file we can find,
494 # If the object is a function, class or method whose file we can find,
495 # we give its full path
495 # we give its full path
496 'file' : str,
496 'file' : str,
497
497
498 # For pure Python callable objects, we can reconstruct the object
498 # For pure Python callable objects, we can reconstruct the object
499 # definition line which provides its call signature. For convenience this
499 # definition line which provides its call signature. For convenience this
500 # is returned as a single 'definition' field, but below the raw parts that
500 # is returned as a single 'definition' field, but below the raw parts that
501 # compose it are also returned as the argspec field.
501 # compose it are also returned as the argspec field.
502 'definition' : str,
502 'definition' : str,
503
503
504 # The individual parts that together form the definition string. Clients
504 # The individual parts that together form the definition string. Clients
505 # with rich display capabilities may use this to provide a richer and more
505 # with rich display capabilities may use this to provide a richer and more
506 # precise representation of the definition line (e.g. by highlighting
506 # precise representation of the definition line (e.g. by highlighting
507 # arguments based on the user's cursor position). For non-callable
507 # arguments based on the user's cursor position). For non-callable
508 # objects, this field is empty.
508 # objects, this field is empty.
509 'argspec' : { # The names of all the arguments
509 'argspec' : { # The names of all the arguments
510 args : list,
510 args : list,
511 # The name of the varargs (*args), if any
511 # The name of the varargs (*args), if any
512 varargs : str,
512 varargs : str,
513 # The name of the varkw (**kw), if any
513 # The name of the varkw (**kw), if any
514 varkw : str,
514 varkw : str,
515 # The values (as strings) of all default arguments. Note
515 # The values (as strings) of all default arguments. Note
516 # that these must be matched *in reverse* with the 'args'
516 # that these must be matched *in reverse* with the 'args'
517 # list above, since the first positional args have no default
517 # list above, since the first positional args have no default
518 # value at all.
518 # value at all.
519 defaults : list,
519 defaults : list,
520 },
520 },
521
521
522 # For instances, provide the constructor signature (the definition of
522 # For instances, provide the constructor signature (the definition of
523 # the __init__ method):
523 # the __init__ method):
524 'init_definition' : str,
524 'init_definition' : str,
525
525
526 # Docstrings: for any object (function, method, module, package) with a
526 # Docstrings: for any object (function, method, module, package) with a
527 # docstring, we show it. But in addition, we may provide additional
527 # docstring, we show it. But in addition, we may provide additional
528 # docstrings. For example, for instances we will show the constructor
528 # docstrings. For example, for instances we will show the constructor
529 # and class docstrings as well, if available.
529 # and class docstrings as well, if available.
530 'docstring' : str,
530 'docstring' : str,
531
531
532 # For instances, provide the constructor and class docstrings
532 # For instances, provide the constructor and class docstrings
533 'init_docstring' : str,
533 'init_docstring' : str,
534 'class_docstring' : str,
534 'class_docstring' : str,
535
535
536 # If it's a callable object whose call method has a separate docstring and
536 # If it's a callable object whose call method has a separate docstring and
537 # definition line:
537 # definition line:
538 'call_def' : str,
538 'call_def' : str,
539 'call_docstring' : str,
539 'call_docstring' : str,
540
540
541 # If detail_level was 1, we also try to find the source code that
541 # If detail_level was 1, we also try to find the source code that
542 # defines the object, if possible. The string 'None' will indicate
542 # defines the object, if possible. The string 'None' will indicate
543 # that no source was found.
543 # that no source was found.
544 'source' : str,
544 'source' : str,
545 }
545 }
546 '
546 '
547
547
548 Complete
548 Complete
549 --------
549 --------
550
550
551 Message type: ``complete_request``::
551 Message type: ``complete_request``::
552
552
553 content = {
553 content = {
554 # The text to be completed, such as 'a.is'
554 # The text to be completed, such as 'a.is'
555 'text' : str,
555 'text' : str,
556
556
557 # The full line, such as 'print a.is'. This allows completers to
557 # The full line, such as 'print a.is'. This allows completers to
558 # make decisions that may require information about more than just the
558 # make decisions that may require information about more than just the
559 # current word.
559 # current word.
560 'line' : str,
560 'line' : str,
561
561
562 # The entire block of text where the line is. This may be useful in the
562 # The entire block of text where the line is. This may be useful in the
563 # case of multiline completions where more context may be needed. Note: if
563 # case of multiline completions where more context may be needed. Note: if
564 # in practice this field proves unnecessary, remove it to lighten the
564 # in practice this field proves unnecessary, remove it to lighten the
565 # messages.
565 # messages.
566
566
567 'block' : str,
567 'block' : str,
568
568
569 # The position of the cursor where the user hit 'TAB' on the line.
569 # The position of the cursor where the user hit 'TAB' on the line.
570 'cursor_pos' : int,
570 'cursor_pos' : int,
571 }
571 }
572
572
573 Message type: ``complete_reply``::
573 Message type: ``complete_reply``::
574
574
575 content = {
575 content = {
576 # The list of all matches to the completion request, such as
576 # The list of all matches to the completion request, such as
577 # ['a.isalnum', 'a.isalpha'] for the above example.
577 # ['a.isalnum', 'a.isalpha'] for the above example.
578 'matches' : list
578 'matches' : list
579 }
579 }
580
580
581
581
582 History
582 History
583 -------
583 -------
584
584
585 For clients to explicitly request history from a kernel. The kernel has all
585 For clients to explicitly request history from a kernel. The kernel has all
586 the actual execution history stored in a single location, so clients can
586 the actual execution history stored in a single location, so clients can
587 request it from the kernel when needed.
587 request it from the kernel when needed.
588
588
589 Message type: ``history_request``::
589 Message type: ``history_request``::
590
590
591 content = {
591 content = {
592
592
593 # If True, also return output history in the resulting dict.
593 # If True, also return output history in the resulting dict.
594 'output' : bool,
594 'output' : bool,
595
595
596 # If True, return the raw input history, else the transformed input.
596 # If True, return the raw input history, else the transformed input.
597 'raw' : bool,
597 'raw' : bool,
598
598
599 # This parameter can be one of: A number, a pair of numbers, None
599 # So far, this can be 'range', 'tail' or 'search'.
600 # If not given, last 40 are returned.
600 'hist_access_type' : str,
601 # - number n: return the last n entries.
601
602 # - pair n1, n2: return entries in the range(n1, n2).
602 # If hist_access_type is 'range', get a range of input cells. session can
603 # - None: return all history
603 # be a positive session number, or a negative number to count back from
604 'index' : n or (n1, n2) or None,
604 # the current session.
605 'session' : int,
606 # start and stop are line numbers within that session.
607 'start' : int,
608 'stop' : int,
609
610 # If hist_access_type is 'tail', get the last n cells.
611 'n' : int,
612
613 # If hist_access_type is 'search', get cells matching the specified glob
614 # pattern (with * and ? as wildcards).
615 'pattern' : str,
616
605 }
617 }
606
618
607 Message type: ``history_reply``::
619 Message type: ``history_reply``::
608
620
609 content = {
621 content = {
610 # A dict with prompt numbers as keys and either (input, output) or input
622 # A list of 3 tuples, either:
611 # as the value depending on whether output was True or False,
623 # (session, line_number, input) or
612 # respectively.
624 # (session, line_number, (input, output)),
613 'history' : dict,
625 # depending on whether output was False or True, respectively.
626 'history' : list,
614 }
627 }
615
628
616
629
617 Connect
630 Connect
618 -------
631 -------
619
632
620 When a client connects to the request/reply socket of the kernel, it can issue
633 When a client connects to the request/reply socket of the kernel, it can issue
621 a connect request to get basic information about the kernel, such as the ports
634 a connect request to get basic information about the kernel, such as the ports
622 the other ZeroMQ sockets are listening on. This allows clients to only have
635 the other ZeroMQ sockets are listening on. This allows clients to only have
623 to know about a single port (the XREQ/XREP channel) to connect to a kernel.
636 to know about a single port (the XREQ/XREP channel) to connect to a kernel.
624
637
625 Message type: ``connect_request``::
638 Message type: ``connect_request``::
626
639
627 content = {
640 content = {
628 }
641 }
629
642
630 Message type: ``connect_reply``::
643 Message type: ``connect_reply``::
631
644
632 content = {
645 content = {
633 'xrep_port' : int # The port the XREP socket is listening on.
646 'xrep_port' : int # The port the XREP socket is listening on.
634 'pub_port' : int # The port the PUB socket is listening on.
647 'pub_port' : int # The port the PUB socket is listening on.
635 'req_port' : int # The port the REQ socket is listening on.
648 'req_port' : int # The port the REQ socket is listening on.
636 'hb_port' : int # The port the heartbeat socket is listening on.
649 'hb_port' : int # The port the heartbeat socket is listening on.
637 }
650 }
638
651
639
652
640
653
641 Kernel shutdown
654 Kernel shutdown
642 ---------------
655 ---------------
643
656
644 The clients can request the kernel to shut itself down; this is used in
657 The clients can request the kernel to shut itself down; this is used in
645 multiple cases:
658 multiple cases:
646
659
647 - when the user chooses to close the client application via a menu or window
660 - when the user chooses to close the client application via a menu or window
648 control.
661 control.
649 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
662 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
650 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
663 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
651 IPythonQt client) to force a kernel restart to get a clean kernel without
664 IPythonQt client) to force a kernel restart to get a clean kernel without
652 losing client-side state like history or inlined figures.
665 losing client-side state like history or inlined figures.
653
666
654 The client sends a shutdown request to the kernel, and once it receives the
667 The client sends a shutdown request to the kernel, and once it receives the
655 reply message (which is otherwise empty), it can assume that the kernel has
668 reply message (which is otherwise empty), it can assume that the kernel has
656 completed shutdown safely.
669 completed shutdown safely.
657
670
658 Upon their own shutdown, client applications will typically execute a last
671 Upon their own shutdown, client applications will typically execute a last
659 minute sanity check and forcefully terminate any kernel that is still alive, to
672 minute sanity check and forcefully terminate any kernel that is still alive, to
660 avoid leaving stray processes in the user's machine.
673 avoid leaving stray processes in the user's machine.
661
674
662 For both shutdown request and reply, there is no actual content that needs to
675 For both shutdown request and reply, there is no actual content that needs to
663 be sent, so the content dict is empty.
676 be sent, so the content dict is empty.
664
677
665 Message type: ``shutdown_request``::
678 Message type: ``shutdown_request``::
666
679
667 content = {
680 content = {
668 'restart' : bool # whether the shutdown is final, or precedes a restart
681 'restart' : bool # whether the shutdown is final, or precedes a restart
669 }
682 }
670
683
671 Message type: ``shutdown_reply``::
684 Message type: ``shutdown_reply``::
672
685
673 content = {
686 content = {
674 'restart' : bool # whether the shutdown is final, or precedes a restart
687 'restart' : bool # whether the shutdown is final, or precedes a restart
675 }
688 }
676
689
677 .. Note::
690 .. Note::
678
691
679 When the clients detect a dead kernel thanks to inactivity on the heartbeat
692 When the clients detect a dead kernel thanks to inactivity on the heartbeat
680 socket, they simply send a forceful process termination signal, since a dead
693 socket, they simply send a forceful process termination signal, since a dead
681 process is unlikely to respond in any useful way to messages.
694 process is unlikely to respond in any useful way to messages.
682
695
683
696
684 Messages on the PUB/SUB socket
697 Messages on the PUB/SUB socket
685 ==============================
698 ==============================
686
699
687 Streams (stdout, stderr, etc)
700 Streams (stdout, stderr, etc)
688 ------------------------------
701 ------------------------------
689
702
690 Message type: ``stream``::
703 Message type: ``stream``::
691
704
692 content = {
705 content = {
693 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
706 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
694 'name' : str,
707 'name' : str,
695
708
696 # The data is an arbitrary string to be written to that stream
709 # The data is an arbitrary string to be written to that stream
697 'data' : str,
710 'data' : str,
698 }
711 }
699
712
700 When a kernel receives a raw_input call, it should also broadcast it on the pub
713 When a kernel receives a raw_input call, it should also broadcast it on the pub
701 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
714 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
702 to monitor/display kernel interactions and possibly replay them to their user
715 to monitor/display kernel interactions and possibly replay them to their user
703 or otherwise expose them.
716 or otherwise expose them.
704
717
705 Display Data
718 Display Data
706 ------------
719 ------------
707
720
708 This type of message is used to bring back data that should be diplayed (text,
721 This type of message is used to bring back data that should be diplayed (text,
709 html, svg, etc.) in the frontends. This data is published to all frontends.
722 html, svg, etc.) in the frontends. This data is published to all frontends.
710 Each message can have multiple representations of the data; it is up to the
723 Each message can have multiple representations of the data; it is up to the
711 frontend to decide which to use and how. A single message should contain all
724 frontend to decide which to use and how. A single message should contain all
712 possible representations of the same information. Each representation should
725 possible representations of the same information. Each representation should
713 be a JSON'able data structure, and should be a valid MIME type.
726 be a JSON'able data structure, and should be a valid MIME type.
714
727
715 Some questions remain about this design:
728 Some questions remain about this design:
716
729
717 * Do we use this message type for pyout/displayhook? Probably not, because
730 * Do we use this message type for pyout/displayhook? Probably not, because
718 the displayhook also has to handle the Out prompt display. On the other hand
731 the displayhook also has to handle the Out prompt display. On the other hand
719 we could put that information into the metadata secion.
732 we could put that information into the metadata secion.
720
733
721 Message type: ``display_data``::
734 Message type: ``display_data``::
722
735
723 content = {
736 content = {
724
737
725 # Who create the data
738 # Who create the data
726 'source' : str,
739 'source' : str,
727
740
728 # The data dict contains key/value pairs, where the kids are MIME
741 # The data dict contains key/value pairs, where the kids are MIME
729 # types and the values are the raw data of the representation in that
742 # types and the values are the raw data of the representation in that
730 # format. The data dict must minimally contain the ``text/plain``
743 # format. The data dict must minimally contain the ``text/plain``
731 # MIME type which is used as a backup representation.
744 # MIME type which is used as a backup representation.
732 'data' : dict,
745 'data' : dict,
733
746
734 # Any metadata that describes the data
747 # Any metadata that describes the data
735 'metadata' : dict
748 'metadata' : dict
736 }
749 }
737
750
738 Python inputs
751 Python inputs
739 -------------
752 -------------
740
753
741 These messages are the re-broadcast of the ``execute_request``.
754 These messages are the re-broadcast of the ``execute_request``.
742
755
743 Message type: ``pyin``::
756 Message type: ``pyin``::
744
757
745 content = {
758 content = {
746 'code' : str # Source code to be executed, one or more lines
759 'code' : str # Source code to be executed, one or more lines
747 }
760 }
748
761
749 Python outputs
762 Python outputs
750 --------------
763 --------------
751
764
752 When Python produces output from code that has been compiled in with the
765 When Python produces output from code that has been compiled in with the
753 'single' flag to :func:`compile`, any expression that produces a value (such as
766 'single' flag to :func:`compile`, any expression that produces a value (such as
754 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
767 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
755 this value whatever it wants. The default behavior of ``sys.displayhook`` in
768 this value whatever it wants. The default behavior of ``sys.displayhook`` in
756 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
769 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
757 the value as long as it is not ``None`` (which isn't printed at all). In our
770 the value as long as it is not ``None`` (which isn't printed at all). In our
758 case, the kernel instantiates as ``sys.displayhook`` an object which has
771 case, the kernel instantiates as ``sys.displayhook`` an object which has
759 similar behavior, but which instead of printing to stdout, broadcasts these
772 similar behavior, but which instead of printing to stdout, broadcasts these
760 values as ``pyout`` messages for clients to display appropriately.
773 values as ``pyout`` messages for clients to display appropriately.
761
774
762 IPython's displayhook can handle multiple simultaneous formats depending on its
775 IPython's displayhook can handle multiple simultaneous formats depending on its
763 configuration. The default pretty-printed repr text is always given with the
776 configuration. The default pretty-printed repr text is always given with the
764 ``data`` entry in this message. Any other formats are provided in the
777 ``data`` entry in this message. Any other formats are provided in the
765 ``extra_formats`` list. Frontends are free to display any or all of these
778 ``extra_formats`` list. Frontends are free to display any or all of these
766 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
779 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
767 string, a type string, and the data. The ID is unique to the formatter
780 string, a type string, and the data. The ID is unique to the formatter
768 implementation that created the data. Frontends will typically ignore the ID
781 implementation that created the data. Frontends will typically ignore the ID
769 unless if it has requested a particular formatter. The type string tells the
782 unless if it has requested a particular formatter. The type string tells the
770 frontend how to interpret the data. It is often, but not always a MIME type.
783 frontend how to interpret the data. It is often, but not always a MIME type.
771 Frontends should ignore types that it does not understand. The data itself is
784 Frontends should ignore types that it does not understand. The data itself is
772 any JSON object and depends on the format. It is often, but not always a string.
785 any JSON object and depends on the format. It is often, but not always a string.
773
786
774 Message type: ``pyout``::
787 Message type: ``pyout``::
775
788
776 content = {
789 content = {
777
790
778 # The counter for this execution is also provided so that clients can
791 # The counter for this execution is also provided so that clients can
779 # display it, since IPython automatically creates variables called _N
792 # display it, since IPython automatically creates variables called _N
780 # (for prompt N).
793 # (for prompt N).
781 'execution_count' : int,
794 'execution_count' : int,
782
795
783 # The data dict contains key/value pairs, where the kids are MIME
796 # The data dict contains key/value pairs, where the kids are MIME
784 # types and the values are the raw data of the representation in that
797 # types and the values are the raw data of the representation in that
785 # format. The data dict must minimally contain the ``text/plain``
798 # format. The data dict must minimally contain the ``text/plain``
786 # MIME type which is used as a backup representation.
799 # MIME type which is used as a backup representation.
787 'data' : dict,
800 'data' : dict,
788
801
789 }
802 }
790
803
791 Python errors
804 Python errors
792 -------------
805 -------------
793
806
794 When an error occurs during code execution
807 When an error occurs during code execution
795
808
796 Message type: ``pyerr``::
809 Message type: ``pyerr``::
797
810
798 content = {
811 content = {
799 # Similar content to the execute_reply messages for the 'error' case,
812 # Similar content to the execute_reply messages for the 'error' case,
800 # except the 'status' field is omitted.
813 # except the 'status' field is omitted.
801 }
814 }
802
815
803 Kernel status
816 Kernel status
804 -------------
817 -------------
805
818
806 This message type is used by frontends to monitor the status of the kernel.
819 This message type is used by frontends to monitor the status of the kernel.
807
820
808 Message type: ``status``::
821 Message type: ``status``::
809
822
810 content = {
823 content = {
811 # When the kernel starts to execute code, it will enter the 'busy'
824 # When the kernel starts to execute code, it will enter the 'busy'
812 # state and when it finishes, it will enter the 'idle' state.
825 # state and when it finishes, it will enter the 'idle' state.
813 execution_state : ('busy', 'idle')
826 execution_state : ('busy', 'idle')
814 }
827 }
815
828
816 Kernel crashes
829 Kernel crashes
817 --------------
830 --------------
818
831
819 When the kernel has an unexpected exception, caught by the last-resort
832 When the kernel has an unexpected exception, caught by the last-resort
820 sys.excepthook, we should broadcast the crash handler's output before exiting.
833 sys.excepthook, we should broadcast the crash handler's output before exiting.
821 This will allow clients to notice that a kernel died, inform the user and
834 This will allow clients to notice that a kernel died, inform the user and
822 propose further actions.
835 propose further actions.
823
836
824 Message type: ``crash``::
837 Message type: ``crash``::
825
838
826 content = {
839 content = {
827 # Similarly to the 'error' case for execute_reply messages, this will
840 # Similarly to the 'error' case for execute_reply messages, this will
828 # contain exc_name, exc_type and traceback fields.
841 # contain exc_name, exc_type and traceback fields.
829
842
830 # An additional field with supplementary information such as where to
843 # An additional field with supplementary information such as where to
831 # send the crash message
844 # send the crash message
832 'info' : str,
845 'info' : str,
833 }
846 }
834
847
835
848
836 Future ideas
849 Future ideas
837 ------------
850 ------------
838
851
839 Other potential message types, currently unimplemented, listed below as ideas.
852 Other potential message types, currently unimplemented, listed below as ideas.
840
853
841 Message type: ``file``::
854 Message type: ``file``::
842
855
843 content = {
856 content = {
844 'path' : 'cool.jpg',
857 'path' : 'cool.jpg',
845 'mimetype' : str,
858 'mimetype' : str,
846 'data' : str,
859 'data' : str,
847 }
860 }
848
861
849
862
850 Messages on the REQ/REP socket
863 Messages on the REQ/REP socket
851 ==============================
864 ==============================
852
865
853 This is a socket that goes in the opposite direction: from the kernel to a
866 This is a socket that goes in the opposite direction: from the kernel to a
854 *single* frontend, and its purpose is to allow ``raw_input`` and similar
867 *single* frontend, and its purpose is to allow ``raw_input`` and similar
855 operations that read from ``sys.stdin`` on the kernel to be fulfilled by the
868 operations that read from ``sys.stdin`` on the kernel to be fulfilled by the
856 client. For now we will keep these messages as simple as possible, since they
869 client. For now we will keep these messages as simple as possible, since they
857 basically only mean to convey the ``raw_input(prompt)`` call.
870 basically only mean to convey the ``raw_input(prompt)`` call.
858
871
859 Message type: ``input_request``::
872 Message type: ``input_request``::
860
873
861 content = { 'prompt' : str }
874 content = { 'prompt' : str }
862
875
863 Message type: ``input_reply``::
876 Message type: ``input_reply``::
864
877
865 content = { 'value' : str }
878 content = { 'value' : str }
866
879
867 .. Note::
880 .. Note::
868
881
869 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
882 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
870 practice the kernel should behave like an interactive program. When a
883 practice the kernel should behave like an interactive program. When a
871 program is opened on the console, the keyboard effectively takes over the
884 program is opened on the console, the keyboard effectively takes over the
872 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
885 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
873 Since the IPython kernel effectively behaves like a console program (albeit
886 Since the IPython kernel effectively behaves like a console program (albeit
874 one whose "keyboard" is actually living in a separate process and
887 one whose "keyboard" is actually living in a separate process and
875 transported over the zmq connection), raw ``stdin`` isn't expected to be
888 transported over the zmq connection), raw ``stdin`` isn't expected to be
876 available.
889 available.
877
890
878
891
879 Heartbeat for kernels
892 Heartbeat for kernels
880 =====================
893 =====================
881
894
882 Initially we had considered using messages like those above over ZMQ for a
895 Initially we had considered using messages like those above over ZMQ for a
883 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
896 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
884 alive at all, even if it may be busy executing user code). But this has the
897 alive at all, even if it may be busy executing user code). But this has the
885 problem that if the kernel is locked inside extension code, it wouldn't execute
898 problem that if the kernel is locked inside extension code, it wouldn't execute
886 the python heartbeat code. But it turns out that we can implement a basic
899 the python heartbeat code. But it turns out that we can implement a basic
887 heartbeat with pure ZMQ, without using any Python messaging at all.
900 heartbeat with pure ZMQ, without using any Python messaging at all.
888
901
889 The monitor sends out a single zmq message (right now, it is a str of the
902 The monitor sends out a single zmq message (right now, it is a str of the
890 monitor's lifetime in seconds), and gets the same message right back, prefixed
903 monitor's lifetime in seconds), and gets the same message right back, prefixed
891 with the zmq identity of the XREQ socket in the heartbeat process. This can be
904 with the zmq identity of the XREQ socket in the heartbeat process. This can be
892 a uuid, or even a full message, but there doesn't seem to be a need for packing
905 a uuid, or even a full message, but there doesn't seem to be a need for packing
893 up a message when the sender and receiver are the exact same Python object.
906 up a message when the sender and receiver are the exact same Python object.
894
907
895 The model is this::
908 The model is this::
896
909
897 monitor.send(str(self.lifetime)) # '1.2345678910'
910 monitor.send(str(self.lifetime)) # '1.2345678910'
898
911
899 and the monitor receives some number of messages of the form::
912 and the monitor receives some number of messages of the form::
900
913
901 ['uuid-abcd-dead-beef', '1.2345678910']
914 ['uuid-abcd-dead-beef', '1.2345678910']
902
915
903 where the first part is the zmq.IDENTITY of the heart's XREQ on the engine, and
916 where the first part is the zmq.IDENTITY of the heart's XREQ on the engine, and
904 the rest is the message sent by the monitor. No Python code ever has any
917 the rest is the message sent by the monitor. No Python code ever has any
905 access to the message between the monitor's send, and the monitor's recv.
918 access to the message between the monitor's send, and the monitor's recv.
906
919
907
920
908 ToDo
921 ToDo
909 ====
922 ====
910
923
911 Missing things include:
924 Missing things include:
912
925
913 * Important: finish thinking through the payload concept and API.
926 * Important: finish thinking through the payload concept and API.
914
927
915 * Important: ensure that we have a good solution for magics like %edit. It's
928 * Important: ensure that we have a good solution for magics like %edit. It's
916 likely that with the payload concept we can build a full solution, but not
929 likely that with the payload concept we can build a full solution, but not
917 100% clear yet.
930 100% clear yet.
918
931
919 * Finishing the details of the heartbeat protocol.
932 * Finishing the details of the heartbeat protocol.
920
933
921 * Signal handling: specify what kind of information kernel should broadcast (or
934 * Signal handling: specify what kind of information kernel should broadcast (or
922 not) when it receives signals.
935 not) when it receives signals.
923
936
924 .. include:: ../links.rst
937 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now