Show More
@@ -2363,10 +2363,38 b' class InteractiveShell(SingletonConfigurable):' | |||||
2363 | # Things related to extracting values/expressions from kernel and user_ns |
|
2363 | # Things related to extracting values/expressions from kernel and user_ns | |
2364 | #------------------------------------------------------------------------- |
|
2364 | #------------------------------------------------------------------------- | |
2365 |
|
2365 | |||
2366 |
def _s |
|
2366 | def _user_obj_error(self): | |
2367 | etype, value = sys.exc_info()[:2] |
|
2367 | """return simple exception dict | |
2368 | return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value) |
|
2368 | ||
|
2369 | for use in user_variables / expressions | |||
|
2370 | """ | |||
|
2371 | ||||
|
2372 | etype, evalue, tb = self._get_exc_info() | |||
|
2373 | stb = self.InteractiveTB.get_exception_only(etype, evalue) | |||
|
2374 | ||||
|
2375 | exc_info = { | |||
|
2376 | u'status' : 'error', | |||
|
2377 | u'traceback' : stb, | |||
|
2378 | u'ename' : unicode(etype.__name__), | |||
|
2379 | u'evalue' : py3compat.safe_unicode(evalue), | |||
|
2380 | } | |||
2369 |
|
2381 | |||
|
2382 | return exc_info | |||
|
2383 | ||||
|
2384 | def _format_user_obj(self, obj): | |||
|
2385 | """format a user object to display dict | |||
|
2386 | ||||
|
2387 | for use in user_expressions / variables | |||
|
2388 | """ | |||
|
2389 | ||||
|
2390 | data, md = self.display_formatter.format(obj) | |||
|
2391 | value = { | |||
|
2392 | 'status' : 'ok', | |||
|
2393 | 'data' : data, | |||
|
2394 | 'metadata' : md, | |||
|
2395 | } | |||
|
2396 | return value | |||
|
2397 | ||||
2370 | def user_variables(self, names): |
|
2398 | def user_variables(self, names): | |
2371 | """Get a list of variable names from the user's namespace. |
|
2399 | """Get a list of variable names from the user's namespace. | |
2372 |
|
2400 | |||
@@ -2377,15 +2405,17 b' class InteractiveShell(SingletonConfigurable):' | |||||
2377 |
|
2405 | |||
2378 | Returns |
|
2406 | Returns | |
2379 | ------- |
|
2407 | ------- | |
2380 | A dict, keyed by the input names and with the repr() of each value. |
|
2408 | A dict, keyed by the input names and with the rich mime-type repr(s) of each value. | |
|
2409 | Each element will be a sub-dict of the same form as a display_data message. | |||
2381 | """ |
|
2410 | """ | |
2382 | out = {} |
|
2411 | out = {} | |
2383 | user_ns = self.user_ns |
|
2412 | user_ns = self.user_ns | |
|
2413 | ||||
2384 | for varname in names: |
|
2414 | for varname in names: | |
2385 | try: |
|
2415 | try: | |
2386 |
value = re |
|
2416 | value = self._format_user_obj(user_ns[varname]) | |
2387 | except: |
|
2417 | except: | |
2388 |
value = self._s |
|
2418 | value = self._user_obj_error() | |
2389 | out[varname] = value |
|
2419 | out[varname] = value | |
2390 | return out |
|
2420 | return out | |
2391 |
|
2421 | |||
@@ -2401,17 +2431,18 b' class InteractiveShell(SingletonConfigurable):' | |||||
2401 |
|
2431 | |||
2402 | Returns |
|
2432 | Returns | |
2403 | ------- |
|
2433 | ------- | |
2404 |
A dict, keyed like the input expressions dict, with the r |
|
2434 | A dict, keyed like the input expressions dict, with the rich mime-typed | |
2405 | value. |
|
2435 | display_data of each value. | |
2406 | """ |
|
2436 | """ | |
2407 | out = {} |
|
2437 | out = {} | |
2408 | user_ns = self.user_ns |
|
2438 | user_ns = self.user_ns | |
2409 | global_ns = self.user_global_ns |
|
2439 | global_ns = self.user_global_ns | |
|
2440 | ||||
2410 | for key, expr in expressions.iteritems(): |
|
2441 | for key, expr in expressions.iteritems(): | |
2411 | try: |
|
2442 | try: | |
2412 |
value = re |
|
2443 | value = self._format_user_obj(eval(expr, global_ns, user_ns)) | |
2413 | except: |
|
2444 | except: | |
2414 |
value = self._s |
|
2445 | value = self._user_obj_error() | |
2415 | out[key] = value |
|
2446 | out[key] = value | |
2416 | return out |
|
2447 | return out | |
2417 |
|
2448 |
@@ -15,6 +15,7 b'' | |||||
15 | # Imports |
|
15 | # Imports | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 | # Stdlib |
|
17 | # Stdlib | |
|
18 | import json | |||
18 | import os |
|
19 | import os | |
19 | import re |
|
20 | import re | |
20 | import sys |
|
21 | import sys | |
@@ -326,16 +327,6 b' class MagicsManager(Configurable):' | |||||
326 | """Return descriptive string with automagic status.""" |
|
327 | """Return descriptive string with automagic status.""" | |
327 | return self._auto_status[self.auto_magic] |
|
328 | return self._auto_status[self.auto_magic] | |
328 |
|
329 | |||
329 | def lsmagic_info(self): |
|
|||
330 | magic_list = [] |
|
|||
331 | for m_type in self.magics : |
|
|||
332 | for m_name,mgc in self.magics[m_type].items(): |
|
|||
333 | try : |
|
|||
334 | magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__}) |
|
|||
335 | except AttributeError : |
|
|||
336 | magic_list.append({'name':m_name,'type':m_type,'class':'Other'}) |
|
|||
337 | return magic_list |
|
|||
338 |
|
||||
339 | def lsmagic(self): |
|
330 | def lsmagic(self): | |
340 | """Return a dict of currently available magic functions. |
|
331 | """Return a dict of currently available magic functions. | |
341 |
|
332 |
@@ -15,6 +15,7 b' from __future__ import print_function' | |||||
15 |
|
15 | |||
16 | # Stdlib |
|
16 | # Stdlib | |
17 | import io |
|
17 | import io | |
|
18 | import json | |||
18 | import sys |
|
19 | import sys | |
19 | from pprint import pformat |
|
20 | from pprint import pformat | |
20 |
|
21 | |||
@@ -33,6 +34,55 b' from IPython.utils.warn import warn, error' | |||||
33 | # Magics class implementation |
|
34 | # Magics class implementation | |
34 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
35 |
|
36 | |||
|
37 | class MagicsDisplay(object): | |||
|
38 | def __init__(self, magics_manager): | |||
|
39 | self.magics_manager = magics_manager | |||
|
40 | ||||
|
41 | def _lsmagic(self): | |||
|
42 | """The main implementation of the %lsmagic""" | |||
|
43 | mesc = magic_escapes['line'] | |||
|
44 | cesc = magic_escapes['cell'] | |||
|
45 | mman = self.magics_manager | |||
|
46 | magics = mman.lsmagic() | |||
|
47 | out = ['Available line magics:', | |||
|
48 | mesc + (' '+mesc).join(sorted(magics['line'])), | |||
|
49 | '', | |||
|
50 | 'Available cell magics:', | |||
|
51 | cesc + (' '+cesc).join(sorted(magics['cell'])), | |||
|
52 | '', | |||
|
53 | mman.auto_status()] | |||
|
54 | return '\n'.join(out) | |||
|
55 | ||||
|
56 | def _repr_pretty_(self, p, cycle): | |||
|
57 | p.text(self._lsmagic()) | |||
|
58 | ||||
|
59 | def __str__(self): | |||
|
60 | return self._lsmagic() | |||
|
61 | ||||
|
62 | def _jsonable(self): | |||
|
63 | """turn magics dict into jsonable dict of the same structure | |||
|
64 | ||||
|
65 | replaces object instances with their class names as strings | |||
|
66 | """ | |||
|
67 | magic_dict = {} | |||
|
68 | mman = self.magics_manager | |||
|
69 | magics = mman.lsmagic() | |||
|
70 | for key, subdict in magics.items(): | |||
|
71 | d = {} | |||
|
72 | magic_dict[key] = d | |||
|
73 | for name, obj in subdict.items(): | |||
|
74 | try: | |||
|
75 | classname = obj.im_class.__name__ | |||
|
76 | except AttributeError: | |||
|
77 | classname = 'Other' | |||
|
78 | ||||
|
79 | d[name] = classname | |||
|
80 | return magic_dict | |||
|
81 | ||||
|
82 | def _repr_json_(self): | |||
|
83 | return json.dumps(self._jsonable()) | |||
|
84 | ||||
|
85 | ||||
36 | @magics_class |
|
86 | @magics_class | |
37 | class BasicMagics(Magics): |
|
87 | class BasicMagics(Magics): | |
38 | """Magics that provide central IPython functionality. |
|
88 | """Magics that provide central IPython functionality. | |
@@ -124,24 +174,10 b' class BasicMagics(Magics):' | |||||
124 | magic_escapes['cell'], name, |
|
174 | magic_escapes['cell'], name, | |
125 | magic_escapes['cell'], target)) |
|
175 | magic_escapes['cell'], target)) | |
126 |
|
176 | |||
127 | def _lsmagic(self): |
|
|||
128 | mesc = magic_escapes['line'] |
|
|||
129 | cesc = magic_escapes['cell'] |
|
|||
130 | mman = self.shell.magics_manager |
|
|||
131 | magics = mman.lsmagic() |
|
|||
132 | out = ['Available line magics:', |
|
|||
133 | mesc + (' '+mesc).join(sorted(magics['line'])), |
|
|||
134 | '', |
|
|||
135 | 'Available cell magics:', |
|
|||
136 | cesc + (' '+cesc).join(sorted(magics['cell'])), |
|
|||
137 | '', |
|
|||
138 | mman.auto_status()] |
|
|||
139 | return '\n'.join(out) |
|
|||
140 |
|
||||
141 | @line_magic |
|
177 | @line_magic | |
142 | def lsmagic(self, parameter_s=''): |
|
178 | def lsmagic(self, parameter_s=''): | |
143 | """List currently available magic functions.""" |
|
179 | """List currently available magic functions.""" | |
144 | print(self._lsmagic()) |
|
180 | return MagicsDisplay(self.shell.magics_manager) | |
145 |
|
181 | |||
146 | def _magic_docs(self, brief=False, rest=False): |
|
182 | def _magic_docs(self, brief=False, rest=False): | |
147 | """Return docstrings from magic functions.""" |
|
183 | """Return docstrings from magic functions.""" |
@@ -578,3 +578,72 b' class TestAstTransformError(unittest.TestCase):' | |||||
578 | def test__IPYTHON__(): |
|
578 | def test__IPYTHON__(): | |
579 | # This shouldn't raise a NameError, that's all |
|
579 | # This shouldn't raise a NameError, that's all | |
580 | __IPYTHON__ |
|
580 | __IPYTHON__ | |
|
581 | ||||
|
582 | ||||
|
583 | class DummyRepr(object): | |||
|
584 | def __repr__(self): | |||
|
585 | return "DummyRepr" | |||
|
586 | ||||
|
587 | def _repr_html_(self): | |||
|
588 | return "<b>dummy</b>" | |||
|
589 | ||||
|
590 | def _repr_javascript_(self): | |||
|
591 | return "console.log('hi');", {'key': 'value'} | |||
|
592 | ||||
|
593 | ||||
|
594 | def test_user_variables(): | |||
|
595 | # enable all formatters | |||
|
596 | ip.display_formatter.active_types = ip.display_formatter.format_types | |||
|
597 | ||||
|
598 | ip.user_ns['dummy'] = d = DummyRepr() | |||
|
599 | keys = set(['dummy', 'doesnotexist']) | |||
|
600 | r = ip.user_variables(keys) | |||
|
601 | ||||
|
602 | nt.assert_equal(keys, set(r.keys())) | |||
|
603 | dummy = r['dummy'] | |||
|
604 | nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys())) | |||
|
605 | nt.assert_equal(dummy['status'], 'ok') | |||
|
606 | data = dummy['data'] | |||
|
607 | metadata = dummy['metadata'] | |||
|
608 | nt.assert_equal(data.get('text/html'), d._repr_html_()) | |||
|
609 | js, jsmd = d._repr_javascript_() | |||
|
610 | nt.assert_equal(data.get('application/javascript'), js) | |||
|
611 | nt.assert_equal(metadata.get('application/javascript'), jsmd) | |||
|
612 | ||||
|
613 | dne = r['doesnotexist'] | |||
|
614 | nt.assert_equal(dne['status'], 'error') | |||
|
615 | nt.assert_equal(dne['ename'], 'KeyError') | |||
|
616 | ||||
|
617 | # back to text only | |||
|
618 | ip.display_formatter.active_types = ['text/plain'] | |||
|
619 | ||||
|
620 | def test_user_expression(): | |||
|
621 | # enable all formatters | |||
|
622 | ip.display_formatter.active_types = ip.display_formatter.format_types | |||
|
623 | query = { | |||
|
624 | 'a' : '1 + 2', | |||
|
625 | 'b' : '1/0', | |||
|
626 | } | |||
|
627 | r = ip.user_expressions(query) | |||
|
628 | import pprint | |||
|
629 | pprint.pprint(r) | |||
|
630 | nt.assert_equal(r.keys(), query.keys()) | |||
|
631 | a = r['a'] | |||
|
632 | nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys())) | |||
|
633 | nt.assert_equal(a['status'], 'ok') | |||
|
634 | data = a['data'] | |||
|
635 | metadata = a['metadata'] | |||
|
636 | nt.assert_equal(data.get('text/plain'), '3') | |||
|
637 | ||||
|
638 | b = r['b'] | |||
|
639 | nt.assert_equal(b['status'], 'error') | |||
|
640 | nt.assert_equal(b['ename'], 'ZeroDivisionError') | |||
|
641 | ||||
|
642 | # back to text only | |||
|
643 | ip.display_formatter.active_types = ['text/plain'] | |||
|
644 | ||||
|
645 | ||||
|
646 | ||||
|
647 | ||||
|
648 | ||||
|
649 |
@@ -241,7 +241,9 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
241 | content = msg['content'] |
|
241 | content = msg['content'] | |
242 | status = content['status'] |
|
242 | status = content['status'] | |
243 | if status == 'ok': |
|
243 | if status == 'ok': | |
244 |
self._max_session_history= |
|
244 | self._max_session_history = int( | |
|
245 | content['user_expressions']['hlen']['data']['text/plain'] | |||
|
246 | ) | |||
245 |
|
247 | |||
246 | def save_magic(self): |
|
248 | def save_magic(self): | |
247 | # update the session history length |
|
249 | # update the session history length |
@@ -20,15 +20,17 b' Authors:' | |||||
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
22 | # stdlib imports |
|
22 | # stdlib imports | |
23 |
import |
|
23 | import json | |
24 | import re |
|
24 | import re | |
|
25 | import sys | |||
25 | import webbrowser |
|
26 | import webbrowser | |
26 | import ast |
|
|||
27 | from threading import Thread |
|
27 | from threading import Thread | |
28 |
|
28 | |||
29 | # System library imports |
|
29 | # System library imports | |
30 | from IPython.external.qt import QtGui,QtCore |
|
30 | from IPython.external.qt import QtGui,QtCore | |
31 |
|
31 | |||
|
32 | from IPython.core.magic import magic_escapes | |||
|
33 | ||||
32 | def background(f): |
|
34 | def background(f): | |
33 | """call a function in a simple thread, to prevent blocking""" |
|
35 | """call a function in a simple thread, to prevent blocking""" | |
34 | t = Thread(target=f) |
|
36 | t = Thread(target=f) | |
@@ -615,43 +617,42 b' class MainWindow(QtGui.QMainWindow):' | |||||
615 | inner_dynamic_magic.__name__ = "dynamics_magic_s" |
|
617 | inner_dynamic_magic.__name__ = "dynamics_magic_s" | |
616 | return inner_dynamic_magic |
|
618 | return inner_dynamic_magic | |
617 |
|
619 | |||
618 |
def populate_all_magic_menu(self, |
|
620 | def populate_all_magic_menu(self, display_data=None): | |
619 |
"""Clean "All Magics..." menu and repopulate it with ` |
|
621 | """Clean "All Magics..." menu and repopulate it with `display_data` | |
620 |
|
622 | |||
621 | Parameters |
|
623 | Parameters | |
622 | ---------- |
|
624 | ---------- | |
623 | listofmagic : string, |
|
625 | display_data : dict, | |
624 | repr() of a list of strings, send back by the kernel |
|
626 | dict of display_data for the magics dict of a MagicsManager. | |
|
627 | Expects json data, as the result of %lsmagic | |||
625 |
|
628 | |||
626 | Notes |
|
|||
627 | ----- |
|
|||
628 | `listofmagic`is a repr() of list because it is fed with the result of |
|
|||
629 | a 'user_expression' |
|
|||
630 | """ |
|
629 | """ | |
631 | for k,v in self._magic_menu_dict.items(): |
|
630 | for k,v in self._magic_menu_dict.items(): | |
632 | v.clear() |
|
631 | v.clear() | |
633 | self.all_magic_menu.clear() |
|
632 | self.all_magic_menu.clear() | |
634 |
|
633 | |||
635 |
|
634 | if not display_data: | ||
636 | mlist=ast.literal_eval(listofmagic) |
|
635 | return | |
637 | for magic in mlist: |
|
636 | ||
638 | cell = (magic['type'] == 'cell') |
|
637 | if display_data['status'] != 'ok': | |
639 | name = magic['name'] |
|
638 | self.log.warn("%%lsmagic user-expression failed: %s" % display_data) | |
640 | mclass = magic['class'] |
|
639 | return | |
641 | if cell : |
|
640 | ||
642 | prefix='%%' |
|
641 | mdict = json.loads(display_data['data'].get('application/json', {})) | |
643 |
|
|
642 | ||
644 | prefix='%' |
|
643 | for mtype in sorted(mdict): | |
645 | magic_menu = self._get_magic_menu(mclass) |
|
644 | subdict = mdict[mtype] | |
646 |
|
645 | prefix = magic_escapes[mtype] | ||
647 | pmagic = '%s%s'%(prefix,name) |
|
646 | for name in sorted(subdict): | |
648 |
|
647 | mclass = subdict[name] | ||
649 | xaction = QtGui.QAction(pmagic, |
|
648 | magic_menu = self._get_magic_menu(mclass) | |
650 |
|
|
649 | pmagic = prefix + name | |
651 | triggered=self._make_dynamic_magic(pmagic) |
|
650 | xaction = QtGui.QAction(pmagic, | |
652 |
|
|
651 | self, | |
653 | magic_menu.addAction(xaction) |
|
652 | triggered=self._make_dynamic_magic(pmagic) | |
654 | self.all_magic_menu.addAction(xaction) |
|
653 | ) | |
|
654 | magic_menu.addAction(xaction) | |||
|
655 | self.all_magic_menu.addAction(xaction) | |||
655 |
|
656 | |||
656 | def update_all_magic_menu(self): |
|
657 | def update_all_magic_menu(self): | |
657 | """ Update the list of magics in the "All Magics..." Menu |
|
658 | """ Update the list of magics in the "All Magics..." Menu | |
@@ -660,7 +661,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
660 | menu with the list received back |
|
661 | menu with the list received back | |
661 |
|
662 | |||
662 | """ |
|
663 | """ | |
663 |
self.active_frontend._silent_exec_callback('get_ipython().magic |
|
664 | self.active_frontend._silent_exec_callback('get_ipython().magic("lsmagic")', | |
664 | self.populate_all_magic_menu) |
|
665 | self.populate_all_magic_menu) | |
665 |
|
666 | |||
666 | def _get_magic_menu(self,menuidentifier, menulabel=None): |
|
667 | def _get_magic_menu(self,menuidentifier, menulabel=None): |
@@ -361,7 +361,21 b' def test_user_variables():' | |||||
361 |
|
361 | |||
362 | msg_id, reply = execute(code='x=1', user_variables=['x']) |
|
362 | msg_id, reply = execute(code='x=1', user_variables=['x']) | |
363 | user_variables = reply['user_variables'] |
|
363 | user_variables = reply['user_variables'] | |
364 |
nt.assert_equal(user_variables, {u'x' |
|
364 | nt.assert_equal(user_variables, {u'x': { | |
|
365 | u'status': u'ok', | |||
|
366 | u'data': {u'text/plain': u'1'}, | |||
|
367 | u'metadata': {}, | |||
|
368 | }}) | |||
|
369 | ||||
|
370 | ||||
|
371 | def test_user_variables_fail(): | |||
|
372 | flush_channels() | |||
|
373 | ||||
|
374 | msg_id, reply = execute(code='x=1', user_variables=['nosuchname']) | |||
|
375 | user_variables = reply['user_variables'] | |||
|
376 | foo = user_variables['nosuchname'] | |||
|
377 | nt.assert_equal(foo['status'], 'error') | |||
|
378 | nt.assert_equal(foo['ename'], 'KeyError') | |||
365 |
|
379 | |||
366 |
|
380 | |||
367 | def test_user_expressions(): |
|
381 | def test_user_expressions(): | |
@@ -369,7 +383,21 b' def test_user_expressions():' | |||||
369 |
|
383 | |||
370 | msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1')) |
|
384 | msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1')) | |
371 | user_expressions = reply['user_expressions'] |
|
385 | user_expressions = reply['user_expressions'] | |
372 |
nt.assert_equal(user_expressions, {u'foo' |
|
386 | nt.assert_equal(user_expressions, {u'foo': { | |
|
387 | u'status': u'ok', | |||
|
388 | u'data': {u'text/plain': u'2'}, | |||
|
389 | u'metadata': {}, | |||
|
390 | }}) | |||
|
391 | ||||
|
392 | ||||
|
393 | def test_user_expressions_fail(): | |||
|
394 | flush_channels() | |||
|
395 | ||||
|
396 | msg_id, reply = execute(code='x=0', user_expressions=dict(foo='nosuchname')) | |||
|
397 | user_expressions = reply['user_expressions'] | |||
|
398 | foo = user_expressions['foo'] | |||
|
399 | nt.assert_equal(foo['status'], 'error') | |||
|
400 | nt.assert_equal(foo['ename'], 'NameError') | |||
373 |
|
401 | |||
374 |
|
402 | |||
375 | @dec.parametric |
|
403 | @dec.parametric |
@@ -472,27 +472,6 b' class KernelMagics(Magics):' | |||||
472 | else: |
|
472 | else: | |
473 | print("Autosave disabled") |
|
473 | print("Autosave disabled") | |
474 |
|
474 | |||
475 | def safe_unicode(e): |
|
|||
476 | """unicode(e) with various fallbacks. Used for exceptions, which may not be |
|
|||
477 | safe to call unicode() on. |
|
|||
478 | """ |
|
|||
479 | try: |
|
|||
480 | return unicode(e) |
|
|||
481 | except UnicodeError: |
|
|||
482 | pass |
|
|||
483 |
|
||||
484 | try: |
|
|||
485 | return py3compat.str_to_unicode(str(e)) |
|
|||
486 | except UnicodeError: |
|
|||
487 | pass |
|
|||
488 |
|
||||
489 | try: |
|
|||
490 | return py3compat.str_to_unicode(repr(e)) |
|
|||
491 | except UnicodeError: |
|
|||
492 | pass |
|
|||
493 |
|
||||
494 | return u'Unrecoverably corrupt evalue' |
|
|||
495 |
|
||||
496 |
|
475 | |||
497 | class ZMQInteractiveShell(InteractiveShell): |
|
476 | class ZMQInteractiveShell(InteractiveShell): | |
498 | """A subclass of InteractiveShell for ZMQ.""" |
|
477 | """A subclass of InteractiveShell for ZMQ.""" | |
@@ -572,7 +551,7 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
572 | exc_content = { |
|
551 | exc_content = { | |
573 | u'traceback' : stb, |
|
552 | u'traceback' : stb, | |
574 | u'ename' : unicode(etype.__name__), |
|
553 | u'ename' : unicode(etype.__name__), | |
575 | u'evalue' : safe_unicode(evalue) |
|
554 | u'evalue' : py3compat.safe_unicode(evalue), | |
576 | } |
|
555 | } | |
577 |
|
556 | |||
578 | dh = self.displayhook |
|
557 | dh = self.displayhook |
@@ -50,6 +50,27 b' def _modify_str_or_docstring(str_change_func):' | |||||
50 | return doc |
|
50 | return doc | |
51 | return wrapper |
|
51 | return wrapper | |
52 |
|
52 | |||
|
53 | def safe_unicode(e): | |||
|
54 | """unicode(e) with various fallbacks. Used for exceptions, which may not be | |||
|
55 | safe to call unicode() on. | |||
|
56 | """ | |||
|
57 | try: | |||
|
58 | return unicode(e) | |||
|
59 | except UnicodeError: | |||
|
60 | pass | |||
|
61 | ||||
|
62 | try: | |||
|
63 | return py3compat.str_to_unicode(str(e)) | |||
|
64 | except UnicodeError: | |||
|
65 | pass | |||
|
66 | ||||
|
67 | try: | |||
|
68 | return py3compat.str_to_unicode(repr(e)) | |||
|
69 | except UnicodeError: | |||
|
70 | pass | |||
|
71 | ||||
|
72 | return u'Unrecoverably corrupt evalue' | |||
|
73 | ||||
53 | if sys.version_info[0] >= 3: |
|
74 | if sys.version_info[0] >= 3: | |
54 | PY3 = True |
|
75 | PY3 = True | |
55 |
|
76 |
@@ -171,8 +171,9 b' Message type: ``execute_request``::' | |||||
171 | # is forced to be False. |
|
171 | # is forced to be False. | |
172 | 'store_history' : bool, |
|
172 | 'store_history' : bool, | |
173 |
|
173 | |||
174 |
# A list of variable names from the user's namespace to be retrieved. |
|
174 | # A list of variable names from the user's namespace to be retrieved. | |
175 | # returns is a JSON string of the variable's repr(), not a python object. |
|
175 | # What returns is a rich representation of each variable (dict keyed by name). | |
|
176 | # See the display_data content for the structure of the representation data. | |||
176 | 'user_variables' : list, |
|
177 | 'user_variables' : list, | |
177 |
|
178 | |||
178 | # Similarly, a dict mapping names to expressions to be evaluated in the |
|
179 | # Similarly, a dict mapping names to expressions to be evaluated in the |
General Comments 0
You need to be logged in to leave comments.
Login now