[py-svn] r57030 - in py/branch/event/py/code: . testing

hpk at codespeak.net hpk at codespeak.net
Wed Aug 6 16:54:00 CEST 2008


Author: hpk
Date: Wed Aug  6 16:53:59 2008
New Revision: 57030

Modified:
   py/branch/event/py/code/excinfo.py
   py/branch/event/py/code/testing/test_excinfo.py
Log:
provide optional nicely formatted info on function args in tracebacks


Modified: py/branch/event/py/code/excinfo.py
==============================================================================
--- py/branch/event/py/code/excinfo.py	(original)
+++ py/branch/event/py/code/excinfo.py	Wed Aug  6 16:53:59 2008
@@ -47,13 +47,14 @@
         """ return True if the exception is an instance of exc """
         return isinstance(self.value, exc) 
 
-    def getrepr(self, showlocals=False, style="long", tbfilter=True):
+    def getrepr(self, showlocals=False, style="long", tbfilter=True, funcargs=False):
         """ return str()able representation of this exception info.
             showlocals: show locals per traceback entry 
             style: long|short|no traceback style 
             tbfilter: hide entries (where __tracebackhide__ is true)
         """
-        fmt = FormattedExcinfo(showlocals=showlocals, style=style, tbfilter=tbfilter)
+        fmt = FormattedExcinfo(showlocals=showlocals, style=style, 
+                               tbfilter=tbfilter, funcargs=funcargs)
         return fmt.repr_excinfo(self)
 
     def __str__(self):
@@ -67,10 +68,11 @@
     flow_marker = ">"    
     fail_marker = "E"
     
-    def __init__(self, showlocals=False, style="long", tbfilter=True):
+    def __init__(self, showlocals=False, style="long", tbfilter=True, funcargs=False):
         self.showlocals = showlocals
         self.style = style
         self.tbfilter = tbfilter
+        self.funcargs = funcargs
 
     def _getindent(self, source):
         # figure out indent for given source 
@@ -92,6 +94,13 @@
     def _saferepr(self, obj):
         return safe_repr._repr(obj)
 
+    def repr_args(self, entry):
+        if self.funcargs:
+            args = []
+            for argname, argvalue in entry.frame.getargs():
+                args.append((argname, self._saferepr(argvalue)))
+            return ReprFuncArgs(args)
+
     def get_source(self, source, line_index=-1, excinfo=None):
         """ return formatted and marked up source lines. """
         lines = []
@@ -148,14 +157,15 @@
         source = self._getentrysource(entry)
         line_index = entry.lineno - entry.getfirstlinesource()
 
+        lines = []
         if self.style == "long":
-            lines = self.get_source(source, line_index, excinfo)
+            reprargs = self.repr_args(entry) 
+            lines.extend(self.get_source(source, line_index, excinfo))
             message = excinfo and excinfo.exconly() or ""
             filelocrepr = ReprFileLocation(entry.path, entry.lineno+1, message)
             localsrepr =  self.repr_locals(entry.locals)
-            return ReprEntry(lines, localsrepr, filelocrepr)
+            return ReprEntry(lines, reprargs, localsrepr, filelocrepr)
         else: 
-            lines = []
             if self.style == "short":
                 line = source[line_index].lstrip()
                 lines.append('  File "%s", line %d, in %s' % (
@@ -163,7 +173,7 @@
                 lines.append("    " + line) 
             if excinfo: 
                 lines.extend(self.get_exconly(excinfo, indent=4))
-            return ReprEntry(lines, None, None)
+            return ReprEntry(lines, None, None, None)
 
     def repr_traceback(self, excinfo): 
         traceback = excinfo.traceback 
@@ -233,12 +243,15 @@
 class ReprEntry(Repr):
     localssep = "_ "
 
-    def __init__(self, lines, reprlocals, filelocrepr):
+    def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr):
         self.lines = lines
+        self.reprfuncargs = reprfuncargs
         self.reprlocals = reprlocals 
         self.reprfileloc = filelocrepr
 
     def toterminal(self, tw):
+        if self.reprfuncargs:
+            self.reprfuncargs.toterminal(tw)
         for line in self.lines:
             tw.line(line)
         if self.reprlocals:
@@ -275,3 +288,25 @@
     def toterminal(self, tw):
         for line in self.lines:
             tw.line(line)
+
+class ReprFuncArgs(Repr):
+    def __init__(self, args):
+        self.args = args
+
+    def toterminal(self, tw):
+        if self.args:
+            linesofar = ""
+            for name, value in self.args:
+                ns = "%s = %s" %(name, value)
+                if len(ns) + len(linesofar) + 2 > tw.fullwidth:
+                    if linesofar:
+                        tw.line(linesofar)
+                    linesofar =  ns 
+                else:
+                    if linesofar:
+                        linesofar += ", " + ns
+                    else:
+                        linesofar = ns
+            if linesofar:
+                tw.line(linesofar)
+            tw.line("")

Modified: py/branch/event/py/code/testing/test_excinfo.py
==============================================================================
--- py/branch/event/py/code/testing/test_excinfo.py	(original)
+++ py/branch/event/py/code/testing/test_excinfo.py	Wed Aug  6 16:53:59 2008
@@ -8,6 +8,7 @@
         self.lines.append((sep, line))
     def line(self, line):
         self.lines.append(line)
+    fullwidth = 80
 
 def test_excinfo_simple():
     try:
@@ -303,6 +304,30 @@
         assert loc.lineno == 3
         #assert loc.message == "ValueError: hello"
 
+    def test_repr_tracebackentry_lines(self):
+        mod = self.importasmod("""
+            def func1(m, x, y, z):
+                raise ValueError("hello\\nworld")
+        """)
+        excinfo = py.test.raises(ValueError, mod.func1, "m"*90, 5, 13, "z"*120)
+        excinfo.traceback = excinfo.traceback.filter()
+        entry = excinfo.traceback[-1]
+        p = FormattedExcinfo(funcargs=True)
+        reprfuncargs = p.repr_args(entry)
+        assert reprfuncargs.args[0] == ('m', repr("m"*90))
+        assert reprfuncargs.args[1] == ('x', '5')
+        assert reprfuncargs.args[2] == ('y', '13')
+        assert reprfuncargs.args[3] == ('z', repr("z" * 120))
+
+        p = FormattedExcinfo(funcargs=True)
+        repr_entry = p.repr_traceback_entry(entry)
+        assert repr_entry.reprfuncargs.args == reprfuncargs.args
+        tw = TWMock()
+        repr_entry.toterminal(tw)
+        assert tw.lines[0] == "m = " + repr('m' * 90)
+        assert tw.lines[1] == "x = 5, y = 13"
+        assert tw.lines[2] == "z = " + repr('z' * 120)
+
     def test_repr_tracebackentry_short(self):
         mod = self.importasmod("""
             def func1():
@@ -428,7 +453,7 @@
         lines = reprentry.lines
         assert lines[-1] == "E       assert 1 == 2"
 
-    def test_reprexcinfo__formatrepr(self):
+    def test_reprexcinfo_getrepr(self):
         mod = self.importasmod("""
             def f(x):
                 raise ValueError(x)
@@ -483,13 +508,19 @@
             repr = excinfo.getrepr(**kw)
             repr.toterminal(tw)
             assert tw.stringio.getvalue()
-            
+           
+        for combo in self.allcombos():
+            yield format_and_str, combo
+
+    def allcombos(self): 
         for style in ("long", "short", "no"):
             for showlocals in (True, False):
                 for tbfilter in (True, False):
-                    kw = {'style': style, 
-                          'showlocals': showlocals, 
-                          'tbfilter': tbfilter
-                    }
-                    yield format_and_str, kw
+                    for funcargs in (True, False):
+                        kw = {'style': style, 
+                              'showlocals': showlocals, 
+                              'funcargs': funcargs, 
+                              'tbfilter': tbfilter
+                        }
+                        yield kw
             



More information about the pytest-commit mailing list