1 new commit in py: https://bitbucket.org/hpk42/py/commits/6698f8b49b78/ Changeset: 6698f8b49b78 User: hpk42 Date: 2014-06-29 13:00:28 Summary: make short-style tracebacks more like native and allow callers (in particular pytest) to set tb-style on a per-traceback entry basis Affected #: 5 files
diff -r c769b9203321f3a00aaa37f0d77f98320f92ceea -r 6698f8b49b78c6489c932ce95ebda8dac2a3655d CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,11 @@ methods to allow adding information in the boxed process. Thanks Marc Schlaich. +- refactor traceback generation in light of pytest issue 364 + (shortening tracebacks). you can now set a new traceback style + on a per-entry basis such that a caller can force entries to be + isplayed as short or long entries. + 1.4.20 ================================================== diff -r c769b9203321f3a00aaa37f0d77f98320f92ceea -r 6698f8b49b78c6489c932ce95ebda8dac2a3655d py/__init__.py --- a/py/__init__.py +++ b/py/__init__.py @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2013 """ -__version__ = '1.4.21.dev1' +__version__ = '1.4.21.dev2' from py import _apipkg diff -r c769b9203321f3a00aaa37f0d77f98320f92ceea -r 6698f8b49b78c6489c932ce95ebda8dac2a3655d py/_code/code.py --- a/py/_code/code.py +++ b/py/_code/code.py @@ -133,12 +133,17 @@ class TracebackEntry(object): """ a single entry in a traceback """ + _repr_style = None exprinfo = None def __init__(self, rawentry): self._rawentry = rawentry self.lineno = rawentry.tb_lineno - 1 + def set_repr_style(self, mode): + assert mode in ("short", "long") + self._repr_style = mode + @property def frame(self): return py.code.Frame(self._rawentry.tb_frame) @@ -470,17 +475,17 @@ line_index = 0 if line_index < 0: line_index += len(source) - for i in range(len(source)): - if i == line_index: - prefix = self.flow_marker + " " - else: - if short: - continue - prefix = " " - line = prefix + source[i] - lines.append(line) + space_prefix = " " + if short: + lines.append(space_prefix + source.lines[line_index].strip()) + else: + for line in source.lines[:line_index]: + lines.append(space_prefix + line) + lines.append(self.flow_marker + " " + source.lines[line_index]) + for line in source.lines[line_index+1:]: + lines.append(space_prefix + line) if excinfo is not None: - indent = self._getindent(source) + indent = 4 if short else self._getindent(source) lines.extend(self.get_exconly(excinfo, indent=indent, markall=True)) return lines @@ -520,7 +525,6 @@ return ReprLocals(lines) def repr_traceback_entry(self, entry, excinfo=None): - # excinfo is not None if this is the last tb entry source = self._getentrysource(entry) if source is None: source = py.code.Source("???") @@ -530,11 +534,12 @@ line_index = entry.lineno - max(entry.getfirstlinesource(), 0) lines = [] - if self.style in ("short", "long"): - short = self.style == "short" - reprargs = None - if not short: - reprargs = self.repr_args(entry) + style = entry._repr_style + if style is None: + style = self.style + if style in ("short", "long"): + short = style == "short" + reprargs = self.repr_args(entry) if not short else None s = self.get_source(source, line_index, excinfo, short=short) lines.extend(s) if short: @@ -546,10 +551,10 @@ localsrepr = None if not short: localsrepr = self.repr_locals(entry.locals) - return ReprEntry(lines, reprargs, localsrepr, filelocrepr, short) + return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style) if excinfo: lines.extend(self.get_exconly(excinfo, indent=4)) - return ReprEntry(lines, None, None, None, False) + return ReprEntry(lines, None, None, None, style) def _makepath(self, path): if not self.abspath: @@ -628,14 +633,18 @@ self.style = style def toterminal(self, tw): - sepok = False - for entry in self.reprentries: - if self.style == "long": - if sepok: + # the entries might have different styles + last_style = None + for i, entry in enumerate(self.reprentries): + if entry.style == "long": + tw.line("") + entry.toterminal(tw) + if i < len(self.reprentries) - 1: + next_entry = self.reprentries[i+1] + if entry.style == "long" or \ + entry.style == "short" and next_entry.style == "long": tw.sep(self.entrysep) - tw.line("") - sepok = True - entry.toterminal(tw) + if self.extraline: tw.line(self.extraline) @@ -646,6 +655,8 @@ self.extraline = None class ReprEntryNative(TerminalRepr): + style = "native" + def __init__(self, tblines): self.lines = tblines @@ -655,15 +666,15 @@ class ReprEntry(TerminalRepr): localssep = "_ " - def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, short): + def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, style): self.lines = lines self.reprfuncargs = reprfuncargs self.reprlocals = reprlocals self.reprfileloc = filelocrepr - self.short = short + self.style = style def toterminal(self, tw): - if self.short: + if self.style == "short": self.reprfileloc.toterminal(tw) for line in self.lines: red = line.startswith("E ") @@ -680,7 +691,8 @@ tw.line("") self.reprlocals.toterminal(tw) if self.reprfileloc: - tw.line("") + if self.lines: + tw.line("") self.reprfileloc.toterminal(tw) def __str__(self): diff -r c769b9203321f3a00aaa37f0d77f98320f92ceea -r 6698f8b49b78c6489c932ce95ebda8dac2a3655d setup.py --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.21.dev1', + version='1.4.21.dev2', url='http://pylib.readthedocs.org/', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff -r c769b9203321f3a00aaa37f0d77f98320f92ceea -r 6698f8b49b78c6489c932ce95ebda8dac2a3655d testing/code/test_excinfo.py --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -547,7 +547,7 @@ reprtb = p.repr_traceback_entry(excinfo.traceback[-2]) lines = reprtb.lines basename = py.path.local(mod.__file__).basename - assert lines[0] == '> func1()' + assert lines[0] == ' func1()' assert basename in str(reprtb.reprfileloc.path) assert reprtb.reprfileloc.lineno == 5 @@ -555,8 +555,8 @@ p = FormattedExcinfo(style="short") reprtb = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) lines = reprtb.lines - assert lines[0] == '> raise ValueError("hello")' - assert lines[1] == 'E ValueError: hello' + assert lines[0] == ' raise ValueError("hello")' + assert lines[1] == 'E ValueError: hello' assert basename in str(reprtb.reprfileloc.path) assert reprtb.reprfileloc.lineno == 3 @@ -611,10 +611,10 @@ last_lines = last_reprtb.lines monkeypatch.undo() basename = py.path.local(mod.__file__).basename - assert lines[0] == '> func1()' + assert lines[0] == ' func1()' - assert last_lines[0] == '> raise ValueError("hello")' - assert last_lines[1] == 'E ValueError: hello' + assert last_lines[0] == ' raise ValueError("hello")' + assert last_lines[1] == 'E ValueError: hello' def test_repr_traceback_and_excinfo(self, importasmod): mod = importasmod(""" @@ -819,3 +819,40 @@ # python 2.4 fails to get the source line for the assert if py.std.sys.version_info >= (2, 5): assert s.count('assert 0') == 2 + + def test_traceback_repr_style(self, importasmod): + mod = importasmod(""" + def f(): + g() + def g(): + h() + def h(): + i() + def i(): + raise ValueError() + """) + excinfo = py.test.raises(ValueError, mod.f) + excinfo.traceback = excinfo.traceback.filter() + excinfo.traceback[1].set_repr_style("short") + excinfo.traceback[2].set_repr_style("short") + r = excinfo.getrepr(style="long") + tw = TWMock() + r.toterminal(tw) + for line in tw.lines: print (line) + assert tw.lines[0] == "" + assert tw.lines[1] == " def f():" + assert tw.lines[2] == "> g()" + assert tw.lines[3] == "" + assert tw.lines[4].endswith("mod.py:3: ") + assert tw.lines[5] == ("_ ", None) + assert tw.lines[6].endswith("in g") + assert tw.lines[7] == " h()" + assert tw.lines[8].endswith("in h") + assert tw.lines[9] == " i()" + assert tw.lines[10] == ("_ ", None) + assert tw.lines[11] == "" + assert tw.lines[12] == " def i():" + assert tw.lines[13] == "> raise ValueError()" + assert tw.lines[14] == "E ValueError" + assert tw.lines[15] == "" + assert tw.lines[16].endswith("mod.py:9: ValueError") Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org https://mail.python.org/mailman/listinfo/pytest-commit