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