diff --git a/py/code/excinfo.py b/py/code/excinfo.py index edd30fece..d38735a7b 100644 --- a/py/code/excinfo.py +++ b/py/code/excinfo.py @@ -96,10 +96,10 @@ class FormattedExcinfo(object): def _getentrysource(self, entry): source = entry.getsource() - if source is None: - source = py.code.Source("???") - return source.deindent() - + if source is not None: + source = source.deindent() + return source + def _saferepr(self, obj): return safe_repr._repr(obj) @@ -166,7 +166,11 @@ class FormattedExcinfo(object): def repr_traceback_entry(self, entry, excinfo=None): # excinfo is not None if this is the last tb entry source = self._getentrysource(entry) - line_index = entry.lineno - entry.getfirstlinesource() + if source is None: + source = py.code.Source("???") + line_index = 0 + else: + line_index = entry.lineno - entry.getfirstlinesource() lines = [] if self.style == "long": diff --git a/py/code/testing/test_excinfo.py b/py/code/testing/test_excinfo.py index bed7dcb52..349f6fa82 100644 --- a/py/code/testing/test_excinfo.py +++ b/py/code/testing/test_excinfo.py @@ -305,6 +305,65 @@ class TestFormattedExcinfo: repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" + def test_repr_many_line_source_not_existing(self): + pr = FormattedExcinfo() + co = compile(""" +a = 1 +raise ValueError() +""", "", "exec") + try: + exec co + except ValueError: + excinfo = py.code.ExceptionInfo() + repr = pr.repr_excinfo(excinfo) + assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" + + def test_repr_source_failing_fullsource(self): + pr = FormattedExcinfo() + + class FakeCode(object): + path = '?' + firstlineno = 5 + + @property + def fullsource(self): + raise fail + + class FakeFrame(object): + code = FakeCode() + f_locals = {} + + class FakeTracebackEntry(py.code.Traceback.Entry): + def __init__(self, tb): + self.frame = FakeFrame() + self.lineno = 5+3 + + class Traceback(py.code.Traceback): + Entry = FakeTracebackEntry + + class FakeExcinfo(py.code.ExceptionInfo): + typename = "Foo" + def __init__(self): + pass + + def exconly(self, tryshort): + return "EXC" + + excinfo = FakeExcinfo() + class FakeRawTB(object): + tb_next = None + tb = FakeRawTB() + excinfo.traceback = Traceback(tb) + + fail = IOError() + repr = pr.repr_excinfo(excinfo) + assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" + + fail = py.error.ENOENT + repr = pr.repr_excinfo(excinfo) + assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" + + def test_repr_local(self): p = FormattedExcinfo(showlocals=True) loc = {'y': 5, 'z': 7, 'x': 3, '__builtins__': __builtins__} @@ -581,4 +640,3 @@ class TestFormattedExcinfo: 'tbfilter': tbfilter } yield kw - diff --git a/py/code/traceback2.py b/py/code/traceback2.py index bf901162f..35a3e084d 100644 --- a/py/code/traceback2.py +++ b/py/code/traceback2.py @@ -50,8 +50,11 @@ class TracebackEntry(object): return self.frame.code.firstlineno def getsource(self): - """ return failing source code. """ - source = self.frame.code.fullsource + """ return failing source code. """ + try: + source = self.frame.code.fullsource + except (IOError, py.error.ENOENT): + return None if source is None: try: sourcelines, lineno = py.std.inspect.findsource(self.frame.code.raw)