From 467b5b29e00121ced861c9e8efd7f7b0433a6593 2011-11-11 01:58:56 From: Fernando Perez Date: 2011-11-11 01:58:56 Subject: [PATCH] Catch errors raised by user objects when accessing attributes. When analyzing the line with prefilter, we look into whether objects have a 'rewrite' attribute. While this is off-spec, we've seen in the wild objects that raise something other than AttributeError on attribute access. Now we catch all exceptions in this codepath. Closes #988. --- diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 3dcf386..278709d 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -812,7 +812,14 @@ class AutoHandler(PrefilterHandler): return line force_auto = isinstance(obj, IPyAutocall) - auto_rewrite = getattr(obj, 'rewrite', True) + + # User objects sometimes raise exceptions on attribute access other + # than AttributeError (we've seen it in the past), so it's safest to be + # ultra-conservative here and catch all. + try: + auto_rewrite = obj.rewrite + except Exception: + auto_rewrite = True if esc == ESC_QUOTE: # Auto-quote splitting on whitespace diff --git a/IPython/core/tests/test_prefilter.py b/IPython/core/tests/test_prefilter.py index 3739271..1d562a1 100644 --- a/IPython/core/tests/test_prefilter.py +++ b/IPython/core/tests/test_prefilter.py @@ -35,6 +35,7 @@ def test_prefilter(): for raw, correct in pairs: yield nt.assert_equals(ip.prefilter(raw), correct) + @dec.parametric def test_autocall_binops(): """See https://github.com/ipython/ipython/issues/81""" @@ -49,10 +50,11 @@ def test_autocall_binops(): ip.magic('autocall 0') del ip.user_ns['f'] + @dec.parametric -def test_issue114(): +def test_issue_114(): """Check that multiline string literals don't expand as magic - see http://github.com/ipython/ipython/issues/#issue/114""" + see http://github.com/ipython/ipython/issues/114""" template = '"""\n%s\n"""' # Store the current value of multi_line_specials and turn it off before @@ -66,3 +68,27 @@ def test_issue114(): yield nt.assert_equals(ip.prefilter(raw), raw) finally: ip.prefilter_manager.multi_line_specials = msp + + +def test_prefilter_attribute_errors(): + """Capture exceptions thrown by user objects on attribute access. + + See http://github.com/ipython/ipython/issues/988.""" + + class X(object): + def __getattr__(self, k): + raise ValueError('broken object') + def __call__(self, x): + return x + + # Create a callable broken object + ip.user_ns['x'] = X() + ip.magic('autocall 2') + try: + # Even if x throws an attribute error when looking at its rewrite + # attribute, we should not crash. So the test here is simply making + # the prefilter call and not having an exception. + ip.prefilter('x 1') + finally: + del ip.user_ns['x'] + ip.magic('autocall 0')