[Pytest-commit] commit/py: hpk42: make short-style tracebacks more like native and allow callers

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Sun Jun 29 13:42:47 CEST 2014


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.


More information about the pytest-commit mailing list