From 6426b41dfee5f3db147831ddd71f71909b39daf8 2012-08-02 09:36:17 From: Bussonnier Matthias Date: 2012-08-02 09:36:17 Subject: [PATCH] Merge pull request #2232 from takluyver/i1456 Reapply monkeypatch to inspect.findsource() --- diff --git a/IPython/core/tests/test_ultratb.py b/IPython/core/tests/test_ultratb.py new file mode 100644 index 0000000..b235116 --- /dev/null +++ b/IPython/core/tests/test_ultratb.py @@ -0,0 +1,51 @@ +"""Tests for IPython.core.ultratb +""" + +import os.path +import unittest + +from IPython.testing import tools as tt +from IPython.utils.syspathcontext import prepended_to_syspath +from IPython.utils.tempdir import TemporaryDirectory + +ip = get_ipython() + +file_1 = """1 +2 +3 +def f(): + 1/0 +""" + +file_2 = """def f(): + 1/0 +""" + +class ChangedPyFileTest(unittest.TestCase): + def test_changing_py_file(self): + """Traceback produced if the line where the error occurred is missing? + + https://github.com/ipython/ipython/issues/1456 + """ + with TemporaryDirectory() as td: + fname = os.path.join(td, "foo.py") + with open(fname, "w") as f: + f.write(file_1) + + with prepended_to_syspath(td): + ip.run_cell("import foo") + + with tt.AssertPrints("ZeroDivisionError"): + ip.run_cell("foo.f()") + + # Make the file shorter, so the line of the error is missing. + with open(fname, "w") as f: + f.write(file_2) + + # For some reason, this was failing on the *second* call after + # changing the file, so we call f() twice. + with tt.AssertNotPrints("Internal Python error", channel='stderr'): + with tt.AssertPrints("ZeroDivisionError"): + ip.run_cell("foo.f()") + with tt.AssertPrints("ZeroDivisionError"): + ip.run_cell("foo.f()") diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 1228a2e..513e5cf 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -126,15 +126,10 @@ def inspect_error(): error('Internal Python error in the inspect module.\n' 'Below is the traceback from this internal error.\n') - -# N.B. This function is a monkeypatch we are currently not applying. -# It was written some time ago, to fix an apparent Python bug with -# codeobj.co_firstlineno . Unfortunately, we don't know under what conditions -# the bug occurred, so we can't tell if it has been fixed. If it reappears, we -# will apply the monkeypatch again. Also, note that findsource() is not called -# by our code at this time - we don't know if it was when the monkeypatch was -# written, or if the monkeypatch is needed for some other code (like a debugger). -# For the discussion about not applying it, see gh-1229. TK, Jan 2011. +# This function is a monkeypatch we apply to the Python inspect module. We have +# now found when it's needed (see discussion on issue gh-1456), and we have a +# test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if +# the monkeypatch is not applied. TK, Aug 2012. def findsource(object): """Return the entire source file and starting line number for an object. @@ -210,10 +205,8 @@ def findsource(object): return lines, lnum raise IOError('could not find code object') -# Not applying the monkeypatch - see above the function for details. TK, Jan 2012 -# Monkeypatch inspect to apply our bugfix. This code only works with py25 -#if sys.version_info[:2] >= (2,5): -# inspect.findsource = findsource +# Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5 +inspect.findsource = findsource def fix_frame_records_filenames(records): """Try to fix the filenames in each record from inspect.getinnerframes(). diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index 79ca7f3..48a2869 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -306,7 +306,10 @@ else: super(MyStringIO, self).write(s) notprinted_msg = """Did not find {0!r} in printed output (on {1}): -{2!r}""" +------- +{2!s} +------- +""" class AssertPrints(object): """Context manager for testing that code prints certain text. @@ -337,7 +340,13 @@ class AssertPrints(object): printed = self.buffer.getvalue() assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed) return False - + +printed_msg = """Found {0!r} in printed output (on {1}): +------- +{2!s} +------- +""" + class AssertNotPrints(AssertPrints): """Context manager for checking that certain output *isn't* produced. @@ -346,7 +355,7 @@ class AssertNotPrints(AssertPrints): self.tee.flush() setattr(sys, self.channel, self.orig_stream) printed = self.buffer.getvalue() - assert self.s not in printed, notprinted_msg.format(self.s, self.channel, printed) + assert self.s not in printed, printed_msg.format(self.s, self.channel, printed) return False @contextmanager