From d7db8e492a3a9e60b34f0a5520f8f1a705ee1d23 2013-05-15 03:11:29 From: MinRK Date: 2013-05-15 03:11:29 Subject: [PATCH] user_variables and user_expressions use rich repr API each key will be a rich display_data message rather than plaintext reprs. --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index df011e9..1ea9b0e 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2360,10 +2360,38 @@ class InteractiveShell(SingletonConfigurable): # Things related to extracting values/expressions from kernel and user_ns #------------------------------------------------------------------------- - def _simple_error(self): - etype, value = sys.exc_info()[:2] - return u'[ERROR] {e.__name__}: {v}'.format(e=etype, v=value) + def _user_obj_error(self): + """return simple exception dict + + for use in user_variables / expressions + """ + + etype, evalue, tb = self._get_exc_info() + stb = self.InteractiveTB.get_exception_only(etype, evalue) + + exc_info = { + u'status' : 'error', + u'traceback' : stb, + u'ename' : unicode(etype.__name__), + u'evalue' : py3compat.safe_unicode(evalue), + } + return exc_info + + def _format_user_obj(self, obj): + """format a user object to display dict + + for use in user_expressions / variables + """ + + data, md = self.display_formatter.format(obj) + value = { + 'status' : 'ok', + 'data' : data, + 'metadata' : md, + } + return value + def user_variables(self, names): """Get a list of variable names from the user's namespace. @@ -2374,15 +2402,17 @@ class InteractiveShell(SingletonConfigurable): Returns ------- - A dict, keyed by the input names and with the repr() of each value. + A dict, keyed by the input names and with the rich mime-type repr(s) of each value. + Each element will be a sub-dict of the same form as a display_data message. """ out = {} user_ns = self.user_ns + for varname in names: try: - value = repr(user_ns[varname]) + value = self._format_user_obj(user_ns[varname]) except: - value = self._simple_error() + value = self._user_obj_error() out[varname] = value return out @@ -2398,17 +2428,18 @@ class InteractiveShell(SingletonConfigurable): Returns ------- - A dict, keyed like the input expressions dict, with the repr() of each - value. + A dict, keyed like the input expressions dict, with the rich mime-typed + display_data of each value. """ out = {} user_ns = self.user_ns global_ns = self.user_global_ns + for key, expr in expressions.iteritems(): try: - value = repr(eval(expr, global_ns, user_ns)) + value = self._format_user_obj(eval(expr, global_ns, user_ns)) except: - value = self._simple_error() + value = self._user_obj_error() out[key] = value return out diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index b790b2b..c0e25a3 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -578,3 +578,72 @@ class TestAstTransformError(unittest.TestCase): def test__IPYTHON__(): # This shouldn't raise a NameError, that's all __IPYTHON__ + + +class DummyRepr(object): + def __repr__(self): + return "DummyRepr" + + def _repr_html_(self): + return "dummy" + + def _repr_javascript_(self): + return "console.log('hi');", {'key': 'value'} + + +def test_user_variables(): + # enable all formatters + ip.display_formatter.active_types = ip.display_formatter.format_types + + ip.user_ns['dummy'] = d = DummyRepr() + keys = ['dummy', 'doesnotexist'] + r = ip.user_variables(keys) + + nt.assert_equal(keys, list(r.keys())) + dummy = r['dummy'] + nt.assert_equal(['status', 'data', 'metadata'], list(dummy.keys())) + nt.assert_equal(dummy['status'], 'ok') + data = dummy['data'] + metadata = dummy['metadata'] + nt.assert_equal(data.get('text/html'), d._repr_html_()) + js, jsmd = d._repr_javascript_() + nt.assert_equal(data.get('application/javascript'), js) + nt.assert_equal(metadata.get('application/javascript'), jsmd) + + dne = r['doesnotexist'] + nt.assert_equal(dne['status'], 'error') + nt.assert_equal(dne['ename'], 'KeyError') + + # back to text only + ip.display_formatter.active_types = ['text/plain'] + +def test_user_expression(): + # enable all formatters + ip.display_formatter.active_types = ip.display_formatter.format_types + query = { + 'a' : '1 + 2', + 'b' : '1/0', + } + r = ip.user_expressions(query) + import pprint + pprint.pprint(r) + nt.assert_equal(r.keys(), query.keys()) + a = r['a'] + nt.assert_equal(['status', 'data', 'metadata'], list(a.keys())) + nt.assert_equal(a['status'], 'ok') + data = a['data'] + metadata = a['metadata'] + nt.assert_equal(data.get('text/plain'), '3') + + b = r['b'] + nt.assert_equal(b['status'], 'error') + nt.assert_equal(b['ename'], 'ZeroDivisionError') + + # back to text only + ip.display_formatter.active_types = ['text/plain'] + + + + + +