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