##// END OF EJS Templates
lazy load widgets...
Bussonnier Matthias -
Show More
@@ -1,331 +1,336 b''
1 """The IPython kernel implementation"""
1 """The IPython kernel implementation"""
2
2
3 import getpass
3 import getpass
4 import sys
4 import sys
5 import traceback
5 import traceback
6
6
7 from IPython.core import release
7 from IPython.core import release
8 from IPython.html.widgets import Widget
9 from IPython.utils.py3compat import builtin_mod, PY3
8 from IPython.utils.py3compat import builtin_mod, PY3
10 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
11 from IPython.utils.traitlets import Instance, Type, Any
10 from IPython.utils.traitlets import Instance, Type, Any
12 from IPython.utils.decorators import undoc
11 from IPython.utils.decorators import undoc
13
12
14 from ..comm import CommManager
13 from ..comm import CommManager
15 from .kernelbase import Kernel as KernelBase
14 from .kernelbase import Kernel as KernelBase
16 from .serialize import serialize_object, unpack_apply_message
15 from .serialize import serialize_object, unpack_apply_message
17 from .zmqshell import ZMQInteractiveShell
16 from .zmqshell import ZMQInteractiveShell
18
17
18
19 def lazy_import_handle_comm_opened(*args, **kwargs):
20 from IPython.html.widgets import Widget
21 Widget.handle_comm_opened(*args, **kwargs)
22
23
19 class IPythonKernel(KernelBase):
24 class IPythonKernel(KernelBase):
20 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
25 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
21 shell_class = Type(ZMQInteractiveShell)
26 shell_class = Type(ZMQInteractiveShell)
22
27
23 user_module = Any()
28 user_module = Any()
24 def _user_module_changed(self, name, old, new):
29 def _user_module_changed(self, name, old, new):
25 if self.shell is not None:
30 if self.shell is not None:
26 self.shell.user_module = new
31 self.shell.user_module = new
27
32
28 user_ns = Instance(dict, args=None, allow_none=True)
33 user_ns = Instance(dict, args=None, allow_none=True)
29 def _user_ns_changed(self, name, old, new):
34 def _user_ns_changed(self, name, old, new):
30 if self.shell is not None:
35 if self.shell is not None:
31 self.shell.user_ns = new
36 self.shell.user_ns = new
32 self.shell.init_user_ns()
37 self.shell.init_user_ns()
33
38
34 # A reference to the Python builtin 'raw_input' function.
39 # A reference to the Python builtin 'raw_input' function.
35 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
40 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
36 _sys_raw_input = Any()
41 _sys_raw_input = Any()
37 _sys_eval_input = Any()
42 _sys_eval_input = Any()
38
43
39 def __init__(self, **kwargs):
44 def __init__(self, **kwargs):
40 super(IPythonKernel, self).__init__(**kwargs)
45 super(IPythonKernel, self).__init__(**kwargs)
41
46
42 # Initialize the InteractiveShell subclass
47 # Initialize the InteractiveShell subclass
43 self.shell = self.shell_class.instance(parent=self,
48 self.shell = self.shell_class.instance(parent=self,
44 profile_dir = self.profile_dir,
49 profile_dir = self.profile_dir,
45 user_module = self.user_module,
50 user_module = self.user_module,
46 user_ns = self.user_ns,
51 user_ns = self.user_ns,
47 kernel = self,
52 kernel = self,
48 )
53 )
49 self.shell.displayhook.session = self.session
54 self.shell.displayhook.session = self.session
50 self.shell.displayhook.pub_socket = self.iopub_socket
55 self.shell.displayhook.pub_socket = self.iopub_socket
51 self.shell.displayhook.topic = self._topic('execute_result')
56 self.shell.displayhook.topic = self._topic('execute_result')
52 self.shell.display_pub.session = self.session
57 self.shell.display_pub.session = self.session
53 self.shell.display_pub.pub_socket = self.iopub_socket
58 self.shell.display_pub.pub_socket = self.iopub_socket
54 self.shell.data_pub.session = self.session
59 self.shell.data_pub.session = self.session
55 self.shell.data_pub.pub_socket = self.iopub_socket
60 self.shell.data_pub.pub_socket = self.iopub_socket
56
61
57 # TMP - hack while developing
62 # TMP - hack while developing
58 self.shell._reply_content = None
63 self.shell._reply_content = None
59
64
60 self.comm_manager = CommManager(shell=self.shell, parent=self,
65 self.comm_manager = CommManager(shell=self.shell, parent=self,
61 kernel=self)
66 kernel=self)
62 self.comm_manager.register_target('ipython.widget', Widget.handle_comm_opened)
67 self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened)
63
68
64 self.shell.configurables.append(self.comm_manager)
69 self.shell.configurables.append(self.comm_manager)
65 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
70 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
66 for msg_type in comm_msg_types:
71 for msg_type in comm_msg_types:
67 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
72 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
68
73
69 # Kernel info fields
74 # Kernel info fields
70 implementation = 'ipython'
75 implementation = 'ipython'
71 implementation_version = release.version
76 implementation_version = release.version
72 language_info = {
77 language_info = {
73 'name': 'python',
78 'name': 'python',
74 'version': sys.version.split()[0],
79 'version': sys.version.split()[0],
75 'mimetype': 'text/x-python',
80 'mimetype': 'text/x-python',
76 'codemirror_mode': {'name': 'ipython',
81 'codemirror_mode': {'name': 'ipython',
77 'version': sys.version_info[0]},
82 'version': sys.version_info[0]},
78 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
83 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
79 'nbconvert_exporter': 'python',
84 'nbconvert_exporter': 'python',
80 'file_extension': '.py'
85 'file_extension': '.py'
81 }
86 }
82 @property
87 @property
83 def banner(self):
88 def banner(self):
84 return self.shell.banner
89 return self.shell.banner
85
90
86 def start(self):
91 def start(self):
87 self.shell.exit_now = False
92 self.shell.exit_now = False
88 super(IPythonKernel, self).start()
93 super(IPythonKernel, self).start()
89
94
90 def set_parent(self, ident, parent):
95 def set_parent(self, ident, parent):
91 """Overridden from parent to tell the display hook and output streams
96 """Overridden from parent to tell the display hook and output streams
92 about the parent message.
97 about the parent message.
93 """
98 """
94 super(IPythonKernel, self).set_parent(ident, parent)
99 super(IPythonKernel, self).set_parent(ident, parent)
95 self.shell.set_parent(parent)
100 self.shell.set_parent(parent)
96
101
97 def _forward_input(self, allow_stdin=False):
102 def _forward_input(self, allow_stdin=False):
98 """Forward raw_input and getpass to the current frontend.
103 """Forward raw_input and getpass to the current frontend.
99
104
100 via input_request
105 via input_request
101 """
106 """
102 self._allow_stdin = allow_stdin
107 self._allow_stdin = allow_stdin
103
108
104 if PY3:
109 if PY3:
105 self._sys_raw_input = builtin_mod.input
110 self._sys_raw_input = builtin_mod.input
106 builtin_mod.input = self.raw_input
111 builtin_mod.input = self.raw_input
107 else:
112 else:
108 self._sys_raw_input = builtin_mod.raw_input
113 self._sys_raw_input = builtin_mod.raw_input
109 self._sys_eval_input = builtin_mod.input
114 self._sys_eval_input = builtin_mod.input
110 builtin_mod.raw_input = self.raw_input
115 builtin_mod.raw_input = self.raw_input
111 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
116 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
112 self._save_getpass = getpass.getpass
117 self._save_getpass = getpass.getpass
113 getpass.getpass = self.getpass
118 getpass.getpass = self.getpass
114
119
115 def _restore_input(self):
120 def _restore_input(self):
116 """Restore raw_input, getpass"""
121 """Restore raw_input, getpass"""
117 if PY3:
122 if PY3:
118 builtin_mod.input = self._sys_raw_input
123 builtin_mod.input = self._sys_raw_input
119 else:
124 else:
120 builtin_mod.raw_input = self._sys_raw_input
125 builtin_mod.raw_input = self._sys_raw_input
121 builtin_mod.input = self._sys_eval_input
126 builtin_mod.input = self._sys_eval_input
122
127
123 getpass.getpass = self._save_getpass
128 getpass.getpass = self._save_getpass
124
129
125 @property
130 @property
126 def execution_count(self):
131 def execution_count(self):
127 return self.shell.execution_count
132 return self.shell.execution_count
128
133
129 @execution_count.setter
134 @execution_count.setter
130 def execution_count(self, value):
135 def execution_count(self, value):
131 # Ignore the incrememnting done by KernelBase, in favour of our shell's
136 # Ignore the incrememnting done by KernelBase, in favour of our shell's
132 # execution counter.
137 # execution counter.
133 pass
138 pass
134
139
135 def do_execute(self, code, silent, store_history=True,
140 def do_execute(self, code, silent, store_history=True,
136 user_expressions=None, allow_stdin=False):
141 user_expressions=None, allow_stdin=False):
137 shell = self.shell # we'll need this a lot here
142 shell = self.shell # we'll need this a lot here
138
143
139 self._forward_input(allow_stdin)
144 self._forward_input(allow_stdin)
140
145
141 reply_content = {}
146 reply_content = {}
142 # FIXME: the shell calls the exception handler itself.
147 # FIXME: the shell calls the exception handler itself.
143 shell._reply_content = None
148 shell._reply_content = None
144 try:
149 try:
145 shell.run_cell(code, store_history=store_history, silent=silent)
150 shell.run_cell(code, store_history=store_history, silent=silent)
146 except:
151 except:
147 status = u'error'
152 status = u'error'
148 # FIXME: this code right now isn't being used yet by default,
153 # FIXME: this code right now isn't being used yet by default,
149 # because the run_cell() call above directly fires off exception
154 # because the run_cell() call above directly fires off exception
150 # reporting. This code, therefore, is only active in the scenario
155 # reporting. This code, therefore, is only active in the scenario
151 # where runlines itself has an unhandled exception. We need to
156 # where runlines itself has an unhandled exception. We need to
152 # uniformize this, for all exception construction to come from a
157 # uniformize this, for all exception construction to come from a
153 # single location in the codbase.
158 # single location in the codbase.
154 etype, evalue, tb = sys.exc_info()
159 etype, evalue, tb = sys.exc_info()
155 tb_list = traceback.format_exception(etype, evalue, tb)
160 tb_list = traceback.format_exception(etype, evalue, tb)
156 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
161 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
157 else:
162 else:
158 status = u'ok'
163 status = u'ok'
159 finally:
164 finally:
160 self._restore_input()
165 self._restore_input()
161
166
162 reply_content[u'status'] = status
167 reply_content[u'status'] = status
163
168
164 # Return the execution counter so clients can display prompts
169 # Return the execution counter so clients can display prompts
165 reply_content['execution_count'] = shell.execution_count - 1
170 reply_content['execution_count'] = shell.execution_count - 1
166
171
167 # FIXME - fish exception info out of shell, possibly left there by
172 # FIXME - fish exception info out of shell, possibly left there by
168 # runlines. We'll need to clean up this logic later.
173 # runlines. We'll need to clean up this logic later.
169 if shell._reply_content is not None:
174 if shell._reply_content is not None:
170 reply_content.update(shell._reply_content)
175 reply_content.update(shell._reply_content)
171 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
176 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
172 reply_content['engine_info'] = e_info
177 reply_content['engine_info'] = e_info
173 # reset after use
178 # reset after use
174 shell._reply_content = None
179 shell._reply_content = None
175
180
176 if 'traceback' in reply_content:
181 if 'traceback' in reply_content:
177 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
182 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
178
183
179
184
180 # At this point, we can tell whether the main code execution succeeded
185 # At this point, we can tell whether the main code execution succeeded
181 # or not. If it did, we proceed to evaluate user_expressions
186 # or not. If it did, we proceed to evaluate user_expressions
182 if reply_content['status'] == 'ok':
187 if reply_content['status'] == 'ok':
183 reply_content[u'user_expressions'] = \
188 reply_content[u'user_expressions'] = \
184 shell.user_expressions(user_expressions or {})
189 shell.user_expressions(user_expressions or {})
185 else:
190 else:
186 # If there was an error, don't even try to compute expressions
191 # If there was an error, don't even try to compute expressions
187 reply_content[u'user_expressions'] = {}
192 reply_content[u'user_expressions'] = {}
188
193
189 # Payloads should be retrieved regardless of outcome, so we can both
194 # Payloads should be retrieved regardless of outcome, so we can both
190 # recover partial output (that could have been generated early in a
195 # recover partial output (that could have been generated early in a
191 # block, before an error) and clear the payload system always.
196 # block, before an error) and clear the payload system always.
192 reply_content[u'payload'] = shell.payload_manager.read_payload()
197 reply_content[u'payload'] = shell.payload_manager.read_payload()
193 # Be agressive about clearing the payload because we don't want
198 # Be agressive about clearing the payload because we don't want
194 # it to sit in memory until the next execute_request comes in.
199 # it to sit in memory until the next execute_request comes in.
195 shell.payload_manager.clear_payload()
200 shell.payload_manager.clear_payload()
196
201
197 return reply_content
202 return reply_content
198
203
199 def do_complete(self, code, cursor_pos):
204 def do_complete(self, code, cursor_pos):
200 # FIXME: IPython completers currently assume single line,
205 # FIXME: IPython completers currently assume single line,
201 # but completion messages give multi-line context
206 # but completion messages give multi-line context
202 # For now, extract line from cell, based on cursor_pos:
207 # For now, extract line from cell, based on cursor_pos:
203 if cursor_pos is None:
208 if cursor_pos is None:
204 cursor_pos = len(code)
209 cursor_pos = len(code)
205 line, offset = line_at_cursor(code, cursor_pos)
210 line, offset = line_at_cursor(code, cursor_pos)
206 line_cursor = cursor_pos - offset
211 line_cursor = cursor_pos - offset
207
212
208 txt, matches = self.shell.complete('', line, line_cursor)
213 txt, matches = self.shell.complete('', line, line_cursor)
209 return {'matches' : matches,
214 return {'matches' : matches,
210 'cursor_end' : cursor_pos,
215 'cursor_end' : cursor_pos,
211 'cursor_start' : cursor_pos - len(txt),
216 'cursor_start' : cursor_pos - len(txt),
212 'metadata' : {},
217 'metadata' : {},
213 'status' : 'ok'}
218 'status' : 'ok'}
214
219
215 def do_inspect(self, code, cursor_pos, detail_level=0):
220 def do_inspect(self, code, cursor_pos, detail_level=0):
216 name = token_at_cursor(code, cursor_pos)
221 name = token_at_cursor(code, cursor_pos)
217 info = self.shell.object_inspect(name)
222 info = self.shell.object_inspect(name)
218
223
219 reply_content = {'status' : 'ok'}
224 reply_content = {'status' : 'ok'}
220 reply_content['data'] = data = {}
225 reply_content['data'] = data = {}
221 reply_content['metadata'] = {}
226 reply_content['metadata'] = {}
222 reply_content['found'] = info['found']
227 reply_content['found'] = info['found']
223 if info['found']:
228 if info['found']:
224 info_text = self.shell.object_inspect_text(
229 info_text = self.shell.object_inspect_text(
225 name,
230 name,
226 detail_level=detail_level,
231 detail_level=detail_level,
227 )
232 )
228 data['text/plain'] = info_text
233 data['text/plain'] = info_text
229
234
230 return reply_content
235 return reply_content
231
236
232 def do_history(self, hist_access_type, output, raw, session=None, start=None,
237 def do_history(self, hist_access_type, output, raw, session=None, start=None,
233 stop=None, n=None, pattern=None, unique=False):
238 stop=None, n=None, pattern=None, unique=False):
234 if hist_access_type == 'tail':
239 if hist_access_type == 'tail':
235 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
240 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
236 include_latest=True)
241 include_latest=True)
237
242
238 elif hist_access_type == 'range':
243 elif hist_access_type == 'range':
239 hist = self.shell.history_manager.get_range(session, start, stop,
244 hist = self.shell.history_manager.get_range(session, start, stop,
240 raw=raw, output=output)
245 raw=raw, output=output)
241
246
242 elif hist_access_type == 'search':
247 elif hist_access_type == 'search':
243 hist = self.shell.history_manager.search(
248 hist = self.shell.history_manager.search(
244 pattern, raw=raw, output=output, n=n, unique=unique)
249 pattern, raw=raw, output=output, n=n, unique=unique)
245 else:
250 else:
246 hist = []
251 hist = []
247
252
248 return {'history' : list(hist)}
253 return {'history' : list(hist)}
249
254
250 def do_shutdown(self, restart):
255 def do_shutdown(self, restart):
251 self.shell.exit_now = True
256 self.shell.exit_now = True
252 return dict(status='ok', restart=restart)
257 return dict(status='ok', restart=restart)
253
258
254 def do_is_complete(self, code):
259 def do_is_complete(self, code):
255 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
260 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
256 r = {'status': status}
261 r = {'status': status}
257 if status == 'incomplete':
262 if status == 'incomplete':
258 r['indent'] = ' ' * indent_spaces
263 r['indent'] = ' ' * indent_spaces
259 return r
264 return r
260
265
261 def do_apply(self, content, bufs, msg_id, reply_metadata):
266 def do_apply(self, content, bufs, msg_id, reply_metadata):
262 shell = self.shell
267 shell = self.shell
263 try:
268 try:
264 working = shell.user_ns
269 working = shell.user_ns
265
270
266 prefix = "_"+str(msg_id).replace("-","")+"_"
271 prefix = "_"+str(msg_id).replace("-","")+"_"
267
272
268 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
273 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
269
274
270 fname = getattr(f, '__name__', 'f')
275 fname = getattr(f, '__name__', 'f')
271
276
272 fname = prefix+"f"
277 fname = prefix+"f"
273 argname = prefix+"args"
278 argname = prefix+"args"
274 kwargname = prefix+"kwargs"
279 kwargname = prefix+"kwargs"
275 resultname = prefix+"result"
280 resultname = prefix+"result"
276
281
277 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
282 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
278 # print ns
283 # print ns
279 working.update(ns)
284 working.update(ns)
280 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
285 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
281 try:
286 try:
282 exec(code, shell.user_global_ns, shell.user_ns)
287 exec(code, shell.user_global_ns, shell.user_ns)
283 result = working.get(resultname)
288 result = working.get(resultname)
284 finally:
289 finally:
285 for key in ns:
290 for key in ns:
286 working.pop(key)
291 working.pop(key)
287
292
288 result_buf = serialize_object(result,
293 result_buf = serialize_object(result,
289 buffer_threshold=self.session.buffer_threshold,
294 buffer_threshold=self.session.buffer_threshold,
290 item_threshold=self.session.item_threshold,
295 item_threshold=self.session.item_threshold,
291 )
296 )
292
297
293 except:
298 except:
294 # invoke IPython traceback formatting
299 # invoke IPython traceback formatting
295 shell.showtraceback()
300 shell.showtraceback()
296 # FIXME - fish exception info out of shell, possibly left there by
301 # FIXME - fish exception info out of shell, possibly left there by
297 # run_code. We'll need to clean up this logic later.
302 # run_code. We'll need to clean up this logic later.
298 reply_content = {}
303 reply_content = {}
299 if shell._reply_content is not None:
304 if shell._reply_content is not None:
300 reply_content.update(shell._reply_content)
305 reply_content.update(shell._reply_content)
301 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
306 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
302 reply_content['engine_info'] = e_info
307 reply_content['engine_info'] = e_info
303 # reset after use
308 # reset after use
304 shell._reply_content = None
309 shell._reply_content = None
305
310
306 self.send_response(self.iopub_socket, u'error', reply_content,
311 self.send_response(self.iopub_socket, u'error', reply_content,
307 ident=self._topic('error'))
312 ident=self._topic('error'))
308 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
313 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
309 result_buf = []
314 result_buf = []
310
315
311 if reply_content['ename'] == 'UnmetDependency':
316 if reply_content['ename'] == 'UnmetDependency':
312 reply_metadata['dependencies_met'] = False
317 reply_metadata['dependencies_met'] = False
313 else:
318 else:
314 reply_content = {'status' : 'ok'}
319 reply_content = {'status' : 'ok'}
315
320
316 return reply_content, result_buf
321 return reply_content, result_buf
317
322
318 def do_clear(self):
323 def do_clear(self):
319 self.shell.reset(False)
324 self.shell.reset(False)
320 return dict(status='ok')
325 return dict(status='ok')
321
326
322
327
323 # This exists only for backwards compatibility - use IPythonKernel instead
328 # This exists only for backwards compatibility - use IPythonKernel instead
324
329
325 @undoc
330 @undoc
326 class Kernel(IPythonKernel):
331 class Kernel(IPythonKernel):
327 def __init__(self, *args, **kwargs):
332 def __init__(self, *args, **kwargs):
328 import warnings
333 import warnings
329 warnings.warn('Kernel is a deprecated alias of IPython.kernel.zmq.ipkernel.IPythonKernel',
334 warnings.warn('Kernel is a deprecated alias of IPython.kernel.zmq.ipkernel.IPythonKernel',
330 DeprecationWarning)
335 DeprecationWarning)
331 super(Kernel, self).__init__(*args, **kwargs) No newline at end of file
336 super(Kernel, self).__init__(*args, **kwargs)
General Comments 0
You need to be logged in to leave comments. Login now