##// END OF EJS Templates
Separate IPython kernel implementation from kernel machinery
Thomas Kluyver -
Show More
@@ -1,4 +1,286 b''
1 """The IPython kernel implementation"""
2
3 import getpass
4 import sys
5 import traceback
6
7 from IPython.core import release
8 from IPython.utils.py3compat import builtin_mod, PY3
9 from IPython.utils.tokenutil import token_at_cursor
10 from IPython.utils.traitlets import Instance, Type, Any
11
1 from .kernelbase import KernelBase
12 from .kernelbase import KernelBase
13 from .serialize import serialize_object, unpack_apply_message
14 from .zmqshell import ZMQInteractiveShell
2
15
3 class Kernel(KernelBase):
16 class Kernel(KernelBase):
4 pass No newline at end of file
17 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
18 shell_class = Type(ZMQInteractiveShell)
19
20 user_module = Any()
21 def _user_module_changed(self, name, old, new):
22 if self.shell is not None:
23 self.shell.user_module = new
24
25 user_ns = Instance(dict, args=None, allow_none=True)
26 def _user_ns_changed(self, name, old, new):
27 if self.shell is not None:
28 self.shell.user_ns = new
29 self.shell.init_user_ns()
30
31 # A reference to the Python builtin 'raw_input' function.
32 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
33 _sys_raw_input = Any()
34 _sys_eval_input = Any()
35
36 def __init__(self, **kwargs):
37 super(Kernel, self).__init__(**kwargs)
38
39 # Initialize the InteractiveShell subclass
40 self.shell = self.shell_class.instance(parent=self,
41 profile_dir = self.profile_dir,
42 user_module = self.user_module,
43 user_ns = self.user_ns,
44 kernel = self,
45 )
46 self.shell.displayhook.session = self.session
47 self.shell.displayhook.pub_socket = self.iopub_socket
48 self.shell.displayhook.topic = self._topic('execute_result')
49 self.shell.display_pub.session = self.session
50 self.shell.display_pub.pub_socket = self.iopub_socket
51 self.shell.data_pub.session = self.session
52 self.shell.data_pub.pub_socket = self.iopub_socket
53
54 # TMP - hack while developing
55 self.shell._reply_content = None
56
57 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
58 comm_manager = self.shell.comm_manager
59 for msg_type in comm_msg_types:
60 self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
61
62 # Kernel info fields
63 implementation = 'ipython'
64 implementation_version = release.version
65 language = 'python'
66 language_version = sys.version.split()[0]
67 @property
68 def banner(self):
69 return self.shell.banner
70
71 def set_parent(self, ident, parent):
72 """Overridden from parent to tell the display hook and output streams
73 about the parent message.
74 """
75 super(Kernel, self).set_parent(ident, parent)
76 self.shell.set_parent(parent)
77
78 def _forward_input(self, allow_stdin=False):
79 """Forward raw_input and getpass to the current frontend.
80
81 via input_request
82 """
83 self._allow_stdin = allow_stdin
84
85 if PY3:
86 self._sys_raw_input = builtin_mod.input
87 builtin_mod.input = self.raw_input
88 else:
89 self._sys_raw_input = builtin_mod.raw_input
90 self._sys_eval_input = builtin_mod.input
91 builtin_mod.raw_input = self.raw_input
92 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
93 self._save_getpass = getpass.getpass
94 getpass.getpass = self.getpass
95
96 def _restore_input(self):
97 """Restore raw_input, getpass"""
98 if PY3:
99 builtin_mod.input = self._sys_raw_input
100 else:
101 builtin_mod.raw_input = self._sys_raw_input
102 builtin_mod.input = self._sys_eval_input
103
104 getpass.getpass = self._save_getpass
105
106 @property
107 def execution_count(self):
108 return self.shell.execution_count
109
110 @execution_count.setter
111 def execution_count(self, value):
112 # Ignore the incrememnting done by KernelBase, in favour of our shell's
113 # execution counter.
114 pass
115
116 def do_execute(self, code, silent, store_history=True,
117 user_expressions=None, allow_stdin=False):
118 shell = self.shell # we'll need this a lot here
119
120 self._forward_input(allow_stdin)
121
122 reply_content = {}
123 # FIXME: the shell calls the exception handler itself.
124 shell._reply_content = None
125 try:
126 shell.run_cell(code, store_history=store_history, silent=silent)
127 except:
128 status = u'error'
129 # FIXME: this code right now isn't being used yet by default,
130 # because the run_cell() call above directly fires off exception
131 # reporting. This code, therefore, is only active in the scenario
132 # where runlines itself has an unhandled exception. We need to
133 # uniformize this, for all exception construction to come from a
134 # single location in the codbase.
135 etype, evalue, tb = sys.exc_info()
136 tb_list = traceback.format_exception(etype, evalue, tb)
137 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
138 else:
139 status = u'ok'
140 finally:
141 self._restore_input()
142
143 reply_content[u'status'] = status
144
145 # Return the execution counter so clients can display prompts
146 reply_content['execution_count'] = shell.execution_count - 1
147
148 # FIXME - fish exception info out of shell, possibly left there by
149 # runlines. We'll need to clean up this logic later.
150 if shell._reply_content is not None:
151 reply_content.update(shell._reply_content)
152 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
153 reply_content['engine_info'] = e_info
154 # reset after use
155 shell._reply_content = None
156
157 if 'traceback' in reply_content:
158 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
159
160
161 # At this point, we can tell whether the main code execution succeeded
162 # or not. If it did, we proceed to evaluate user_expressions
163 if reply_content['status'] == 'ok':
164 reply_content[u'user_expressions'] = \
165 shell.user_expressions(user_expressions or {})
166 else:
167 # If there was an error, don't even try to compute expressions
168 reply_content[u'user_expressions'] = {}
169
170 # Payloads should be retrieved regardless of outcome, so we can both
171 # recover partial output (that could have been generated early in a
172 # block, before an error) and clear the payload system always.
173 reply_content[u'payload'] = shell.payload_manager.read_payload()
174 # Be agressive about clearing the payload because we don't want
175 # it to sit in memory until the next execute_request comes in.
176 shell.payload_manager.clear_payload()
177
178 return reply_content
179
180 def do_complete(self, code, cursor_pos):
181 txt, matches = self.shell.complete('', code, cursor_pos)
182 return {'matches' : matches,
183 'cursor_end' : cursor_pos,
184 'cursor_start' : cursor_pos - len(txt),
185 'metadata' : {},
186 'status' : 'ok'}
187
188 def do_inspect(self, code, cursor_pos, detail_level=0):
189 name = token_at_cursor(code, cursor_pos)
190 info = self.shell.object_inspect(name)
191
192 reply_content = {'status' : 'ok'}
193 reply_content['data'] = data = {}
194 reply_content['metadata'] = {}
195 reply_content['found'] = info['found']
196 if info['found']:
197 info_text = self.shell.object_inspect_text(
198 name,
199 detail_level=detail_level,
200 )
201 data['text/plain'] = info_text
202
203 return reply_content
204
205 def do_history(self, hist_access_type, output, raw, session=None, start=None,
206 stop=None, n=None, pattern=None, unique=False):
207 if hist_access_type == 'tail':
208 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
209 include_latest=True)
210
211 elif hist_access_type == 'range':
212 hist = self.shell.history_manager.get_range(session, start, stop,
213 raw=raw, output=output)
214
215 elif hist_access_type == 'search':
216 hist = self.shell.history_manager.search(
217 pattern, raw=raw, output=output, n=n, unique=unique)
218 else:
219 hist = []
220
221 return {'history' : list(hist)}
222
223 def do_shutdown(self, restart):
224 self.shell.exit_now = True
225 return dict(status='ok', restart=restart)
226
227 def do_apply(self, content, bufs, msg_id, reply_metadata):
228 shell = self.shell
229 try:
230 working = shell.user_ns
231
232 prefix = "_"+str(msg_id).replace("-","")+"_"
233
234 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
235
236 fname = getattr(f, '__name__', 'f')
237
238 fname = prefix+"f"
239 argname = prefix+"args"
240 kwargname = prefix+"kwargs"
241 resultname = prefix+"result"
242
243 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
244 # print ns
245 working.update(ns)
246 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
247 try:
248 exec(code, shell.user_global_ns, shell.user_ns)
249 result = working.get(resultname)
250 finally:
251 for key in ns:
252 working.pop(key)
253
254 result_buf = serialize_object(result,
255 buffer_threshold=self.session.buffer_threshold,
256 item_threshold=self.session.item_threshold,
257 )
258
259 except:
260 # invoke IPython traceback formatting
261 shell.showtraceback()
262 # FIXME - fish exception info out of shell, possibly left there by
263 # run_code. We'll need to clean up this logic later.
264 reply_content = {}
265 if shell._reply_content is not None:
266 reply_content.update(shell._reply_content)
267 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
268 reply_content['engine_info'] = e_info
269 # reset after use
270 shell._reply_content = None
271
272 self.send_response(self.iopub_socket, u'error', reply_content,
273 ident=self._topic('error'))
274 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
275 result_buf = []
276
277 if reply_content['ename'] == 'UnmetDependency':
278 reply_metadata['dependencies_met'] = False
279 else:
280 reply_content = {'status' : 'ok'}
281
282 return reply_content, result_buf
283
284 def do_clear(self):
285 self.shell.reset(False)
286 return dict(status='ok')
@@ -1,14 +1,12 b''
1 """An interactive kernel that talks to frontends over 0MQ."""
1 """Base class for a kernel that talks to frontends over 0MQ."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import getpass
9 import sys
8 import sys
10 import time
9 import time
11 import traceback
12 import logging
10 import logging
13 import uuid
11 import uuid
14
12
@@ -25,28 +23,19 b' from IPython.config.configurable import Configurable'
25 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.error import StdinNotImplementedError
26 from IPython.core import release
24 from IPython.core import release
27 from IPython.utils import py3compat
25 from IPython.utils import py3compat
28 from IPython.utils.py3compat import builtin_mod, unicode_type, string_types
26 from IPython.utils.py3compat import unicode_type, string_types
29 from IPython.utils.jsonutil import json_clean
27 from IPython.utils.jsonutil import json_clean
30 from IPython.utils.tokenutil import token_at_cursor
31 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
32 Any, Instance, Float, Dict, List, Set, Integer, Unicode,
29 Any, Instance, Float, Dict, List, Set, Integer, Unicode, Bool,
33 Type, Bool,
34 )
30 )
35
31
36 from .serialize import serialize_object, unpack_apply_message
37 from .session import Session
32 from .session import Session
38 from .zmqshell import ZMQInteractiveShell
39
33
40
34
41 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
42 # Main kernel class
36 # Main kernel class
43 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
44
38
45 protocol_version = release.kernel_protocol_version
46 ipython_version = release.version
47 language_version = sys.version.split()[0]
48
49
50 class KernelBase(Configurable):
39 class KernelBase(Configurable):
51
40
52 #---------------------------------------------------------------------------
41 #---------------------------------------------------------------------------
@@ -60,9 +49,6 b' class KernelBase(Configurable):'
60 loop = ioloop.IOLoop.instance()
49 loop = ioloop.IOLoop.instance()
61 loop.add_callback(self.enter_eventloop)
50 loop.add_callback(self.enter_eventloop)
62
51
63 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
64 shell_class = Type(ZMQInteractiveShell)
65
66 session = Instance(Session)
52 session = Instance(Session)
67 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
53 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
68 shell_streams = List()
54 shell_streams = List()
@@ -70,17 +56,6 b' class KernelBase(Configurable):'
70 iopub_socket = Instance(zmq.Socket)
56 iopub_socket = Instance(zmq.Socket)
71 stdin_socket = Instance(zmq.Socket)
57 stdin_socket = Instance(zmq.Socket)
72 log = Instance(logging.Logger)
58 log = Instance(logging.Logger)
73
74 user_module = Any()
75 def _user_module_changed(self, name, old, new):
76 if self.shell is not None:
77 self.shell.user_module = new
78
79 user_ns = Instance(dict, args=None, allow_none=True)
80 def _user_ns_changed(self, name, old, new):
81 if self.shell is not None:
82 self.shell.user_ns = new
83 self.shell.init_user_ns()
84
59
85 # identities:
60 # identities:
86 int_id = Integer(-1)
61 int_id = Integer(-1)
@@ -127,36 +102,17 b' class KernelBase(Configurable):'
127 # by record_ports and used by connect_request.
102 # by record_ports and used by connect_request.
128 _recorded_ports = Dict()
103 _recorded_ports = Dict()
129
104
130 # A reference to the Python builtin 'raw_input' function.
131 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
132 _sys_raw_input = Any()
133 _sys_eval_input = Any()
134
135 # set of aborted msg_ids
105 # set of aborted msg_ids
136 aborted = Set()
106 aborted = Set()
137
107
108 # Track execution count here. For IPython, we override this to use the
109 # execution count we store in the shell.
110 execution_count = 0
111
138
112
139 def __init__(self, **kwargs):
113 def __init__(self, **kwargs):
140 super(KernelBase, self).__init__(**kwargs)
114 super(KernelBase, self).__init__(**kwargs)
141
115
142 # Initialize the InteractiveShell subclass
143 self.shell = self.shell_class.instance(parent=self,
144 profile_dir = self.profile_dir,
145 user_module = self.user_module,
146 user_ns = self.user_ns,
147 kernel = self,
148 )
149 self.shell.displayhook.session = self.session
150 self.shell.displayhook.pub_socket = self.iopub_socket
151 self.shell.displayhook.topic = self._topic('execute_result')
152 self.shell.display_pub.session = self.session
153 self.shell.display_pub.pub_socket = self.iopub_socket
154 self.shell.data_pub.session = self.session
155 self.shell.data_pub.pub_socket = self.iopub_socket
156
157 # TMP - hack while developing
158 self.shell._reply_content = None
159
160 # Build dict of handlers for message types
116 # Build dict of handlers for message types
161 msg_types = [ 'execute_request', 'complete_request',
117 msg_types = [ 'execute_request', 'complete_request',
162 'inspect_request', 'history_request',
118 'inspect_request', 'history_request',
@@ -168,11 +124,6 b' class KernelBase(Configurable):'
168 for msg_type in msg_types:
124 for msg_type in msg_types:
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
125 self.shell_handlers[msg_type] = getattr(self, msg_type)
170
126
171 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
172 comm_manager = self.shell.comm_manager
173 for msg_type in comm_msg_types:
174 self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
175
176 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
127 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
177 self.control_handlers = {}
128 self.control_handlers = {}
178 for msg_type in control_msg_types:
129 for msg_type in control_msg_types:
@@ -191,7 +142,6 b' class KernelBase(Configurable):'
191 self.log.debug("Control received: %s", msg)
142 self.log.debug("Control received: %s", msg)
192
143
193 header = msg['header']
144 header = msg['header']
194 msg_id = header['msg_id']
195 msg_type = header['msg_type']
145 msg_type = header['msg_type']
196
146
197 handler = self.control_handlers.get(msg_type, None)
147 handler = self.control_handlers.get(msg_type, None)
@@ -233,7 +183,7 b' class KernelBase(Configurable):'
233 status = {'status' : 'aborted'}
183 status = {'status' : 'aborted'}
234 md = {'engine' : self.ident}
184 md = {'engine' : self.ident}
235 md.update(status)
185 md.update(status)
236 reply_msg = self.session.send(stream, reply_type, metadata=md,
186 self.session.send(stream, reply_type, metadata=md,
237 content=status, parent=msg, ident=idents)
187 content=status, parent=msg, ident=idents)
238 return
188 return
239
189
@@ -340,34 +290,6 b' class KernelBase(Configurable):'
340 ident=self._topic('status'),
290 ident=self._topic('status'),
341 )
291 )
342
292
343 def _forward_input(self, allow_stdin=False):
344 """Forward raw_input and getpass to the current frontend.
345
346 via input_request
347 """
348 self._allow_stdin = allow_stdin
349
350 if py3compat.PY3:
351 self._sys_raw_input = builtin_mod.input
352 builtin_mod.input = self.raw_input
353 else:
354 self._sys_raw_input = builtin_mod.raw_input
355 self._sys_eval_input = builtin_mod.input
356 builtin_mod.raw_input = self.raw_input
357 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
358 self._save_getpass = getpass.getpass
359 getpass.getpass = self.getpass
360
361 def _restore_input(self):
362 """Restore raw_input, getpass"""
363 if py3compat.PY3:
364 builtin_mod.input = self._sys_raw_input
365 else:
366 builtin_mod.raw_input = self._sys_raw_input
367 builtin_mod.input = self._sys_eval_input
368
369 getpass.getpass = self._save_getpass
370
371 def set_parent(self, ident, parent):
293 def set_parent(self, ident, parent):
372 """Set the current parent_header
294 """Set the current parent_header
373
295
@@ -379,7 +301,19 b' class KernelBase(Configurable):'
379 """
301 """
380 self._parent_ident = ident
302 self._parent_ident = ident
381 self._parent_header = parent
303 self._parent_header = parent
382 self.shell.set_parent(parent)
304
305 def send_response(self, stream, msg_or_type, content=None, ident=None,
306 buffers=None, track=False, header=None, metadata=None):
307 """Send a response to the message we're currently processing.
308
309 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
310 except ``parent``.
311
312 This relies on :meth:`set_parent` having been called for the current
313 message.
314 """
315 return self.session.send(stream, msg_or_type, content, self._parent_header,
316 ident, buffers, track, header, metadata)
383
317
384 def execute_request(self, stream, ident, parent):
318 def execute_request(self, stream, ident, parent):
385 """handle an execute_request"""
319 """handle an execute_request"""
@@ -391,6 +325,8 b' class KernelBase(Configurable):'
391 code = py3compat.cast_unicode_py2(content[u'code'])
325 code = py3compat.cast_unicode_py2(content[u'code'])
392 silent = content[u'silent']
326 silent = content[u'silent']
393 store_history = content.get(u'store_history', not silent)
327 store_history = content.get(u'store_history', not silent)
328 user_expressions = content.get('user_expressions', {})
329 allow_stdin = content.get('allow_stdin', False)
394 except:
330 except:
395 self.log.error("Got bad msg: ")
331 self.log.error("Got bad msg: ")
396 self.log.error("%s", parent)
332 self.log.error("%s", parent)
@@ -398,72 +334,17 b' class KernelBase(Configurable):'
398
334
399 md = self._make_metadata(parent['metadata'])
335 md = self._make_metadata(parent['metadata'])
400
336
401 shell = self.shell # we'll need this a lot here
402
403 self._forward_input(content.get('allow_stdin', False))
404 # Set the parent message of the display hook and out streams.
337 # Set the parent message of the display hook and out streams.
405 self.set_parent(ident, parent)
338 self.set_parent(ident, parent)
406
339
407 # Re-broadcast our input for the benefit of listening clients, and
340 # Re-broadcast our input for the benefit of listening clients, and
408 # start computing output
341 # start computing output
409 if not silent:
342 if not silent:
410 self._publish_execute_input(code, parent, shell.execution_count)
343 self.execution_count += 1
411
344 self._publish_execute_input(code, parent, self.execution_count)
412 reply_content = {}
413 # FIXME: the shell calls the exception handler itself.
414 shell._reply_content = None
415 try:
416 shell.run_cell(code, store_history=store_history, silent=silent)
417 except:
418 status = u'error'
419 # FIXME: this code right now isn't being used yet by default,
420 # because the run_cell() call above directly fires off exception
421 # reporting. This code, therefore, is only active in the scenario
422 # where runlines itself has an unhandled exception. We need to
423 # uniformize this, for all exception construction to come from a
424 # single location in the codbase.
425 etype, evalue, tb = sys.exc_info()
426 tb_list = traceback.format_exception(etype, evalue, tb)
427 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
428 else:
429 status = u'ok'
430 finally:
431 self._restore_input()
432
433 reply_content[u'status'] = status
434
435 # Return the execution counter so clients can display prompts
436 reply_content['execution_count'] = shell.execution_count - 1
437
438 # FIXME - fish exception info out of shell, possibly left there by
439 # runlines. We'll need to clean up this logic later.
440 if shell._reply_content is not None:
441 reply_content.update(shell._reply_content)
442 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
443 reply_content['engine_info'] = e_info
444 # reset after use
445 shell._reply_content = None
446
447 if 'traceback' in reply_content:
448 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
449
345
450
346 reply_content = self.do_execute(code, silent, store_history,
451 # At this point, we can tell whether the main code execution succeeded
347 user_expressions, allow_stdin)
452 # or not. If it did, we proceed to evaluate user_expressions
453 if reply_content['status'] == 'ok':
454 reply_content[u'user_expressions'] = \
455 shell.user_expressions(content.get(u'user_expressions', {}))
456 else:
457 # If there was an error, don't even try to compute expressions
458 reply_content[u'user_expressions'] = {}
459
460 # Payloads should be retrieved regardless of outcome, so we can both
461 # recover partial output (that could have been generated early in a
462 # block, before an error) and clear the payload system always.
463 reply_content[u'payload'] = shell.payload_manager.read_payload()
464 # Be agressive about clearing the payload because we don't want
465 # it to sit in memory until the next execute_request comes in.
466 shell.payload_manager.clear_payload()
467
348
468 # Flush output before sending the reply.
349 # Flush output before sending the reply.
469 sys.stdout.flush()
350 sys.stdout.flush()
@@ -498,12 +379,7 b' class KernelBase(Configurable):'
498 code = content['code']
379 code = content['code']
499 cursor_pos = content['cursor_pos']
380 cursor_pos = content['cursor_pos']
500
381
501 txt, matches = self.shell.complete('', code, cursor_pos)
382 matches = self.do_complete(code, cursor_pos)
502 matches = {'matches' : matches,
503 'cursor_end' : cursor_pos,
504 'cursor_start' : cursor_pos - len(txt),
505 'metadata' : {},
506 'status' : 'ok'}
507 matches = json_clean(matches)
383 matches = json_clean(matches)
508 completion_msg = self.session.send(stream, 'complete_reply',
384 completion_msg = self.session.send(stream, 'complete_reply',
509 matches, parent, ident)
385 matches, parent, ident)
@@ -512,19 +388,8 b' class KernelBase(Configurable):'
512 def inspect_request(self, stream, ident, parent):
388 def inspect_request(self, stream, ident, parent):
513 content = parent['content']
389 content = parent['content']
514
390
515 name = token_at_cursor(content['code'], content['cursor_pos'])
391 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
516 info = self.shell.object_inspect(name)
392 content.get('detail_level', 0))
517
518 reply_content = {'status' : 'ok'}
519 reply_content['data'] = data = {}
520 reply_content['metadata'] = {}
521 reply_content['found'] = info['found']
522 if info['found']:
523 info_text = self.shell.object_inspect_text(
524 name,
525 detail_level=content.get('detail_level', 0),
526 )
527 reply_content['data']['text/plain'] = info_text
528 # Before we send this object over, we scrub it for JSON usage
393 # Before we send this object over, we scrub it for JSON usage
529 reply_content = json_clean(reply_content)
394 reply_content = json_clean(reply_content)
530 msg = self.session.send(stream, 'inspect_reply',
395 msg = self.session.send(stream, 'inspect_reply',
@@ -534,36 +399,22 b' class KernelBase(Configurable):'
534 def history_request(self, stream, ident, parent):
399 def history_request(self, stream, ident, parent):
535 # We need to pull these out, as passing **kwargs doesn't work with
400 # We need to pull these out, as passing **kwargs doesn't work with
536 # unicode keys before Python 2.6.5.
401 # unicode keys before Python 2.6.5.
537 hist_access_type = parent['content']['hist_access_type']
402 content = parent['content']
538 raw = parent['content']['raw']
539 output = parent['content']['output']
540 if hist_access_type == 'tail':
541 n = parent['content']['n']
542 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
543 include_latest=True)
544
545 elif hist_access_type == 'range':
546 session = parent['content']['session']
547 start = parent['content']['start']
548 stop = parent['content']['stop']
549 hist = self.shell.history_manager.get_range(session, start, stop,
550 raw=raw, output=output)
551
552 elif hist_access_type == 'search':
553 n = parent['content'].get('n')
554 unique = parent['content'].get('unique', False)
555 pattern = parent['content']['pattern']
556 hist = self.shell.history_manager.search(
557 pattern, raw=raw, output=output, n=n, unique=unique)
558
403
559 else:
404 reply_content = self.do_history(content['hist_access_type'],
560 hist = []
405 content['output'], content['raw'],
561 hist = list(hist)
406 content.get('session', None),
562 content = {'history' : hist}
407 content.get('start', None),
563 content = json_clean(content)
408 content.get('stop', None),
409 content.get('n', None),
410 content.get('pattern', None),
411 content.get('unique', False),
412 )
413
414 reply_content = json_clean(reply_content)
564 msg = self.session.send(stream, 'history_reply',
415 msg = self.session.send(stream, 'history_reply',
565 content, parent, ident)
416 reply_content, parent, ident)
566 self.log.debug("Sending history reply with %i entries", len(hist))
417 self.log.debug("%s", msg)
567
418
568 def connect_request(self, stream, ident, parent):
419 def connect_request(self, stream, ident, parent):
569 if self._recorded_ports is not None:
420 if self._recorded_ports is not None:
@@ -574,23 +425,24 b' class KernelBase(Configurable):'
574 content, parent, ident)
425 content, parent, ident)
575 self.log.debug("%s", msg)
426 self.log.debug("%s", msg)
576
427
577 def kernel_info_request(self, stream, ident, parent):
428 @property
578 vinfo = {
429 def kernel_info(self):
579 'protocol_version': protocol_version,
430 return {
580 'implementation': 'ipython',
431 'protocol_version': release.kernel_protocol_version,
581 'implementation_version': ipython_version,
432 'implementation': self.implementation,
582 'language_version': language_version,
433 'implementation_version': self.implementation_version,
583 'language': 'python',
434 'language': self.language,
584 'banner': self.shell.banner,
435 'language_version': self.language_version,
436 'banner': self.banner,
585 }
437 }
438
439 def kernel_info_request(self, stream, ident, parent):
586 msg = self.session.send(stream, 'kernel_info_reply',
440 msg = self.session.send(stream, 'kernel_info_reply',
587 vinfo, parent, ident)
441 self.kernel_info, parent, ident)
588 self.log.debug("%s", msg)
442 self.log.debug("%s", msg)
589
443
590 def shutdown_request(self, stream, ident, parent):
444 def shutdown_request(self, stream, ident, parent):
591 self.shell.exit_now = True
445 content = self.do_shutdown(parent['content']['restart'])
592 content = dict(status='ok')
593 content.update(parent['content'])
594 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
446 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
595 # same content, but different msg_id for broadcasting on IOPub
447 # same content, but different msg_id for broadcasting on IOPub
596 self._shutdown_message = self.session.msg(u'shutdown_reply',
448 self._shutdown_message = self.session.msg(u'shutdown_reply',
@@ -618,62 +470,11 b' class KernelBase(Configurable):'
618 self._publish_status(u'busy', parent)
470 self._publish_status(u'busy', parent)
619
471
620 # Set the parent message of the display hook and out streams.
472 # Set the parent message of the display hook and out streams.
621 shell = self.shell
473 self.set_parent(ident, parent)
622 shell.set_parent(parent)
623
474
624 md = self._make_metadata(parent['metadata'])
475 md = self._make_metadata(parent['metadata'])
625 try:
626 working = shell.user_ns
627
628 prefix = "_"+str(msg_id).replace("-","")+"_"
629
630 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
631
632 fname = getattr(f, '__name__', 'f')
633
476
634 fname = prefix+"f"
477 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
635 argname = prefix+"args"
636 kwargname = prefix+"kwargs"
637 resultname = prefix+"result"
638
639 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
640 # print ns
641 working.update(ns)
642 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
643 try:
644 exec(code, shell.user_global_ns, shell.user_ns)
645 result = working.get(resultname)
646 finally:
647 for key in ns:
648 working.pop(key)
649
650 result_buf = serialize_object(result,
651 buffer_threshold=self.session.buffer_threshold,
652 item_threshold=self.session.item_threshold,
653 )
654
655 except:
656 # invoke IPython traceback formatting
657 shell.showtraceback()
658 # FIXME - fish exception info out of shell, possibly left there by
659 # run_code. We'll need to clean up this logic later.
660 reply_content = {}
661 if shell._reply_content is not None:
662 reply_content.update(shell._reply_content)
663 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
664 reply_content['engine_info'] = e_info
665 # reset after use
666 shell._reply_content = None
667
668 self.session.send(self.iopub_socket, u'error', reply_content, parent=parent,
669 ident=self._topic('error'))
670 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
671 result_buf = []
672
673 if reply_content['ename'] == 'UnmetDependency':
674 md['dependencies_met'] = False
675 else:
676 reply_content = {'status' : 'ok'}
677
478
678 # put 'ok'/'error' status in header, for scheduler introspection:
479 # put 'ok'/'error' status in header, for scheduler introspection:
679 md['status'] = reply_content['status']
480 md['status'] = reply_content['status']
@@ -682,7 +483,7 b' class KernelBase(Configurable):'
682 sys.stdout.flush()
483 sys.stdout.flush()
683 sys.stderr.flush()
484 sys.stderr.flush()
684
485
685 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
486 self.session.send(stream, u'apply_reply', reply_content,
686 parent=parent, ident=ident,buffers=result_buf, metadata=md)
487 parent=parent, ident=ident,buffers=result_buf, metadata=md)
687
488
688 self._publish_status(u'idle', parent)
489 self._publish_status(u'idle', parent)
@@ -708,23 +509,14 b' class KernelBase(Configurable):'
708
509
709 def clear_request(self, stream, idents, parent):
510 def clear_request(self, stream, idents, parent):
710 """Clear our namespace."""
511 """Clear our namespace."""
711 self.shell.reset(False)
512 content = self.do_clear()
712 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
513 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
713 content = dict(status='ok'))
514 content = content)
714
715
515
716 #---------------------------------------------------------------------------
516 #---------------------------------------------------------------------------
717 # Protected interface
517 # Protected interface
718 #---------------------------------------------------------------------------
518 #---------------------------------------------------------------------------
719
519
720 def _wrap_exception(self, method=None):
721 # import here, because _wrap_exception is only used in parallel,
722 # and parallel has higher min pyzmq version
723 from IPython.parallel.error import wrap_exception
724 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
725 content = wrap_exception(e_info)
726 return content
727
728 def _topic(self, topic):
520 def _topic(self, topic):
729 """prefixed topic for IOPub messages"""
521 """prefixed topic for IOPub messages"""
730 if self.int_id >= 0:
522 if self.int_id >= 0:
@@ -188,8 +188,8 b' class AsyncResultTest(ClusterTestCase):'
188 ar = v.apply_async(time.sleep, 0.25)
188 ar = v.apply_async(time.sleep, 0.25)
189 while not ar.ready():
189 while not ar.ready():
190 time.sleep(0.01)
190 time.sleep(0.01)
191 self.assertTrue(ar.elapsed < 1)
191 self.assertLess(ar.elapsed, 1)
192 self.assertTrue(ar.elapsed < 1)
192 self.assertLess(ar.elapsed, 1)
193 ar.get(2)
193 ar.get(2)
194
194
195 def test_hubresult_timestamps(self):
195 def test_hubresult_timestamps(self):
General Comments 0
You need to be logged in to leave comments. Login now