[py-svn] py-trunk commit bb9c3511e28c: * improve and test --tb=short reporting

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Sat May 22 16:16:05 CEST 2010


# HG changeset patch -- Bitbucket.org
# Project py-trunk
# URL http://bitbucket.org/hpk42/py-trunk/overview
# User holger krekel <holger at merlinux.eu>
# Date 1274537904 -7200
# Node ID bb9c3511e28c0b886df4ddc31573e105aea08cf4
# Parent  998d3278c0e1425e618d0ea22b681048acdb2252
* improve and test --tb=short reporting
* show --tb=short tracebacks for importing test modules

--- a/py/_plugin/pytest_runner.py
+++ b/py/_plugin/pytest_runner.py
@@ -188,7 +188,11 @@ class CollectReport(BaseReport):
             self.passed = True
             self.result = result 
         else:
-            self.longrepr = self.collector._repr_failure_py(excinfo)
+            style = "short"
+            if collector.config.getvalue("fulltrace"):
+                style = "long"
+            self.longrepr = self.collector._repr_failure_py(excinfo, 
+                style=style)
             if excinfo.errisinstance(py.test.skip.Exception):
                 self.skipped = True
                 self.reason = str(excinfo.value)

--- a/CHANGELOG
+++ b/CHANGELOG
@@ -37,7 +37,9 @@ New features
 Fixes / Maintenance 
 ++++++++++++++++++++++
 
-- improve tracebacks presentation: 
+- improved traceback presentation: 
+  - improved and unified reporting for "--tb=short" option
+  - Errors during test module imports are much shorter, (using --tb=short style)
   - raises shows shorter more relevant tracebacks
 
 - improve support for raises and other dynamically compiled code by

--- a/testing/plugin/test_pytest_terminal.py
+++ b/testing/plugin/test_pytest_terminal.py
@@ -626,6 +626,35 @@ def test_terminalreporter_reportopt_conf
         "*1 passed*"
     ])
 
+def test_tbstyle_short(testdir):
+    p = testdir.makepyfile("""
+        def pytest_funcarg__arg(request):
+            return 42
+        def test_opt(arg):
+            x = 0
+            assert x
+    """)
+    result = testdir.runpytest("--tb=short")
+    s = result.stdout.str()
+    assert 'arg = 42' not in s
+    assert 'x = 0' not in s
+    result.stdout.fnmatch_lines([
+        "*%s:5*" % p.basename,
+        ">*assert x",
+        "E*assert*",
+    ])
+    result = testdir.runpytest()
+    s = result.stdout.str()
+    assert 'x = 0' in s
+    assert 'assert x' in s
+
+def test_trace_reporting(testdir):
+    result = testdir.runpytest("--traceconfig")
+    result.stdout.fnmatch_lines([
+        "*active plugins*"
+    ])
+    assert result.ret == 0
+
 def test_trace_reporting(testdir):
     result = testdir.runpytest("--traceconfig")
     result.stdout.fnmatch_lines([

--- a/py/_code/code.py
+++ b/py/_code/code.py
@@ -416,7 +416,7 @@ class FormattedExcinfo(object):
                 args.append((argname, self._saferepr(argvalue)))
             return ReprFuncArgs(args)
 
-    def get_source(self, source, line_index=-1, excinfo=None):
+    def get_source(self, source, line_index=-1, excinfo=None, short=False):
         """ return formatted and marked up source lines. """
         lines = []
         if source is None:
@@ -428,6 +428,8 @@ class FormattedExcinfo(object):
             if i == line_index:
                 prefix = self.flow_marker + "   "
             else:
+                if short:
+                    continue
                 prefix = "    "
             line = prefix + source[i]
             lines.append(line)
@@ -482,24 +484,26 @@ class FormattedExcinfo(object):
             line_index = entry.lineno - max(entry.getfirstlinesource(), 0)
 
         lines = []
-        if self.style == "long":
-            reprargs = self.repr_args(entry) 
-            lines.extend(self.get_source(source, line_index, excinfo))
-            message = excinfo and excinfo.typename or ""
+        if self.style in ("short", "long"):
+            short = self.style == "short"
+            reprargs = None
+            if not short:
+                reprargs = self.repr_args(entry) 
+            s = self.get_source(source, line_index, excinfo, short=short)
+            lines.extend(s)
+            if short:
+                message = "in %s" %(entry.name)
+            else:
+                message = excinfo and excinfo.typename or ""
             path = self._makepath(entry.path)
             filelocrepr = ReprFileLocation(path, entry.lineno+1, message)
-            localsrepr =  self.repr_locals(entry.locals)
-            return ReprEntry(lines, reprargs, localsrepr, filelocrepr)
-        else: 
-            if self.style == "short":
-                line = source[line_index].lstrip()
-                basename = os.path.basename(entry.frame.code.filename)
-                lines.append('  File "%s", line %d, in %s' % (
-                    basename, entry.lineno+1, entry.name))
-                lines.append("    " + line) 
-            if excinfo: 
-                lines.extend(self.get_exconly(excinfo, indent=4))
-            return ReprEntry(lines, None, None, None)
+            localsrepr = None
+            if not short:
+                localsrepr =  self.repr_locals(entry.locals)
+            return ReprEntry(lines, reprargs, localsrepr, filelocrepr, short)
+        if excinfo: 
+            lines.extend(self.get_exconly(excinfo, indent=4))
+        return ReprEntry(lines, None, None, None, False)
 
     def _makepath(self, path):
         if not self.abspath:
@@ -595,13 +599,21 @@ class ReprTraceback(TerminalRepr):
 class ReprEntry(TerminalRepr):
     localssep = "_ "
 
-    def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr):
+    def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, short):
         self.lines = lines
         self.reprfuncargs = reprfuncargs
         self.reprlocals = reprlocals 
         self.reprfileloc = filelocrepr
+        self.short = short
 
     def toterminal(self, tw):
+        if self.short:
+            self.reprfileloc.toterminal(tw)
+            for line in self.lines:
+                red = line.startswith("E   ") 
+                tw.line(line, bold=True, red=red)
+            #tw.line("")
+            return
         if self.reprfuncargs:
             self.reprfuncargs.toterminal(tw)
         for line in self.lines:

--- a/testing/test_pycollect.py
+++ b/testing/test_pycollect.py
@@ -484,3 +484,28 @@ class TestTracebackCutting:
         assert out.find("conftest.py:2: ValueError") != -1
         numentries = out.count("_ _ _ _") # separator for traceback entries
         assert numentries >3
+
+    def test_traceback_error_during_import(self, testdir):
+        testdir.makepyfile("""
+            x = 1
+            x = 2
+            x = 17
+            asd 
+        """)
+        result = testdir.runpytest()
+        assert result.ret != 0
+        out = result.stdout.str()
+        assert "x = 1" not in out
+        assert "x = 2" not in out
+        result.stdout.fnmatch_lines([
+            ">*asd*",
+            "E*NameError*",
+        ])
+        result = testdir.runpytest("--fulltrace")
+        out = result.stdout.str()
+        assert "x = 1" in out
+        assert "x = 2" in out
+        result.stdout.fnmatch_lines([
+            ">*asd*",
+            "E*NameError*",
+        ])

--- a/py/_test/pycollect.py
+++ b/py/_test/pycollect.py
@@ -253,7 +253,7 @@ class FunctionMixin(PyobjMixin):
             traceback = ntraceback.filter()
         return traceback 
 
-    def _repr_failure_py(self, excinfo):
+    def _repr_failure_py(self, excinfo, style="long"):
         if excinfo.errisinstance(funcargs.FuncargRequest.LookupError):
             fspath, lineno, msg = self.reportinfo()
             lines, _ = inspect.getsourcelines(self.obj)
@@ -261,11 +261,13 @@ class FunctionMixin(PyobjMixin):
                 if line.strip().startswith('def'):
                     return FuncargLookupErrorRepr(fspath, lineno,
             lines[:i+1], str(excinfo.value))
-        return super(FunctionMixin, self)._repr_failure_py(excinfo)
+        return super(FunctionMixin, self)._repr_failure_py(excinfo, 
+            style=style)
 
     def repr_failure(self, excinfo, outerr=None):
         assert outerr is None, "XXX outerr usage is deprecated"
-        return self._repr_failure_py(excinfo)
+        return self._repr_failure_py(excinfo, 
+            style=self.config.getvalue("tbstyle"))
 
     shortfailurerepr = "F"
 

--- a/py/_test/collect.py
+++ b/py/_test/collect.py
@@ -172,14 +172,15 @@ class Node(object):
     def _prunetraceback(self, traceback):
         return traceback 
 
-    def _repr_failure_py(self, excinfo):
+    def _repr_failure_py(self, excinfo, style=None):
         excinfo.traceback = self._prunetraceback(excinfo.traceback)
         # XXX should excinfo.getrepr record all data and toterminal()
         # process it? 
-        if self.config.option.tbstyle == "short":
-            style = "short"
-        else:
-            style = "long"
+        if style is None:
+            if self.config.option.tbstyle == "short":
+                style = "short"
+            else:
+                style = "long"
         return excinfo.getrepr(funcargs=True, 
                                showlocals=self.config.option.showlocals,
                                style=style)

--- a/testing/code/test_excinfo.py
+++ b/testing/code/test_excinfo.py
@@ -463,16 +463,18 @@ raise ValueError()
         reprtb = p.repr_traceback_entry(excinfo.traceback[-2])
         lines = reprtb.lines
         basename = py.path.local(mod.__file__).basename
-        assert lines[0] == '  File "%s", line 5, in entry' % basename 
-        assert lines[1] == '    func1()' 
+        assert lines[0] == '>       func1()'
+        assert basename in str(reprtb.reprfileloc.path)
+        assert reprtb.reprfileloc.lineno == 5
 
         # test last entry 
         p = FormattedExcinfo(style="short")
         reprtb = p.repr_traceback_entry(excinfo.traceback[-1], excinfo)
         lines = reprtb.lines
-        assert lines[0] == '  File "%s", line 3, in func1' % basename 
-        assert lines[1] == '    raise ValueError("hello")'
-        assert lines[2] == '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
 
     def test_repr_tracebackentry_no(self, importasmod):
         mod = importasmod("""
@@ -525,12 +527,10 @@ raise ValueError()
         last_lines = last_reprtb.lines
         monkeypatch.undo()
         basename = py.path.local(mod.__file__).basename
-        assert lines[0] == '  File "%s", line 5, in entry' % basename
-        assert lines[1] == '    func1()' 
+        assert lines[0] == '>       func1()'
 
-        assert last_lines[0] == '  File "%s", line 3, in func1' % basename
-        assert last_lines[1] == '    raise ValueError("hello")'
-        assert last_lines[2] == '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("""



More information about the pytest-commit mailing list