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

hpk at codespeak.net hpk at codespeak.net
Thu Jul 17 19:07:13 CEST 2008


Author: hpk
Date: Thu Jul 17 19:07:10 2008
New Revision: 56620

Added:
   py/branch/event/py/code/tbpresent.py
      - copied, changed from r56617, py/branch/event/py/test2/present.py
   py/branch/event/py/code/testing/test_tbpresent.py
      - copied, changed from r56617, py/branch/event/py/test2/testing/test_present.py
Log:
factor out traceback representation logic to py.code, 
also refactor it and write cleaner tests.



Copied: py/branch/event/py/code/tbpresent.py (from r56617, py/branch/event/py/test2/present.py)
==============================================================================
--- py/branch/event/py/test2/present.py	(original)
+++ py/branch/event/py/code/tbpresent.py	Thu Jul 17 19:07:10 2008
@@ -1,26 +1,26 @@
-
-""" This file intends to gather all methods of representing
-failures/tracebacks etc. which should be used among
-all terminal-based reporters. This methods should be general,
-to allow further use outside the pylib
+""" 
+    Present Python tracebacks in a nice way. 
 """
-
 import py
 from py.__.code import safe_repr
 from py.__.misc.terminal_helper import getout
-from py.__.test2.rep.reporter import getmodpath
 
-class FuncPresenter(object):
+class TBPresenter(object):
     """ presenting information about failing Functions and Generators. """ 
-    def __init__(self, config, out=None):
-        self.config = config
+    # for traceback entries 
+    flow_marker = ">"    
+    fail_marker = "E"
+    
+    def __init__(self, out=None, showlocals=False, style="long"):
         if out is None:
             self.stringio = py.std.StringIO.StringIO()
             out = getout(self.stringio) 
         assert hasattr(out, 'write'), out
         self.out = out
+        self.showlocals = showlocals
+        self.style = style
 
-    def repr_source(self, source, marker=">", marker_location=-1):
+    def repr_source(self, source, marker_location=-1):
         """ This one represents piece of source with possible
         marker at requested position
         """
@@ -37,18 +37,11 @@
             marker_location = len(source) - 1
         for i in range(len(source)):
             if i == marker_location:
-                prefix = marker + "   "
+                prefix = self.flow_marker + "   "
             else:
                 prefix = "    "
             self.out.line(prefix + source[i])
 
-    def repr_failure_headline(self, item):
-        """ This method represents py.test2.collect.Item info (path and module)
-        """
-        # XXX do something for non-python test items 
-        modpath = getmodpath(item)
-        self.out.sep("_", "entrypoint: %s" %(modpath))
-
     def repr_failure_explanation(self, excinfo, source):
         try:
             s = str(source.getstatement(len(source)-1))
@@ -63,7 +56,7 @@
         indent = " " * indent 
         # get the real exception information out 
         lines = excinfo.exconly(tryshort=True).split('\n')
-        self.out.line('E' + indent[:-1] + lines.pop(0))
+        self.out.line(self.fail_marker + indent[:-1] + lines.pop(0))
         for x in lines:
             self.out.line(indent + x)
 
@@ -71,11 +64,11 @@
         try:
             source = entry.getsource()
         except py.error.ENOENT:
-            source = py.code.Source("[failure to get at sourcelines from %r]\n" % entry)
+            source = "???"
         return source.deindent()
 
     def repr_locals(self, f_locals):
-        if self.config.option.showlocals:
+        if self.showlocals: 
             self.out.sep('- ', 'locals')
             for name, value in f_locals.items():
                 if name == '__builtins__': 
@@ -91,85 +84,44 @@
                         self.out.line("%-10s =\\" % (name,))
                         py.std.pprint.pprint(value, stream=self.out)
 
-    def repr_failure(self, item, excinfo):
-        self.repr_failure_headline(item) 
-        self.repr_tb(item, excinfo) 
-        
-    def repr_out_err(self, colitem): 
-        for parent in colitem.listchain(): 
-            if hasattr(parent, '_run_capture'):
-                name, obj = parent._run_capture
-                if obj: 
-                    self.out.sep("- ", "%s: recorded std%s" % (parent.name, name))
-                    self.out.line(obj)
-
     def repr_tb_entry(self, entry, excinfo=None):
-        # excinfo is None if this is the last tb entry 
+        # excinfo is not None if this is the last tb entry 
         source = self.getentrysource(entry)
         firstsourceline = entry.getfirstlinesource()
         marker_location = entry.lineno - firstsourceline
-        self.repr_source(source, '>', marker_location)
-        if excinfo: 
-            self.repr_failure_explanation(excinfo, source) 
-        self.out.line("") 
-        self.out.line("[%s:%d]" %(entry.path, entry.lineno+1))
-        self.repr_locals(entry.locals)
-
-    def repr_tb_entry_last(self, item, entry, excinfo):
-        self.repr_tb_entry(entry, excinfo) 
-        self.repr_out_err(item) 
 
-    def repr_tb(self, item, excinfo): 
-        traceback = item.prunetraceback(excinfo.traceback)
-        recursionindex = traceback.recursionindex()
-        repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle)
-        repr_tb(item, excinfo, traceback, recursionindex)
+        if self.style == "long":
+            self.repr_source(source, marker_location)
+            if excinfo: 
+                self.repr_failure_explanation(excinfo, source) 
+            self.out.line("") 
+            self.out.line("[%s:%d]" %(entry.path, entry.lineno+1))
+            self.repr_locals(entry.locals)
+        else: 
+            if self.style == "short":
+                line = source[marker_location].lstrip()
+                self.out.line('  File "%s", line %d, in %s' % (
+                    entry.path.basename, entry.lineno+1, entry.name))
+                self.out.line("    " + line) 
+            if excinfo: 
+                self.repr_exconly(excinfo, indent=4)
+
+    def repr_sep(self, sep):
+        if self.style == "long":
+            self.out.sep(sep)
 
-    def repr_tb_long(self, item, excinfo, traceback, recursionindex):
+    def repr_tb(self, excinfo): 
+        traceback = excinfo.traceback 
+        recursionindex = traceback.recursionindex()
         last = traceback[-1]
         for index, entry in py.builtin.enumerate(traceback): 
             if last != entry: 
                 self.repr_tb_entry(entry)
-                self.out.sep("_ ")
+                self.repr_sep("_ ")
             else:
-                self.repr_tb_entry_last(item, entry, excinfo) 
-                self.out.sep("_")
+                self.repr_tb_entry(entry, excinfo) 
+                self.repr_sep("_")
             if index == recursionindex:
                 self.out.line("Recursion detected (same locals & position)")
                 self.out.sep("!")
                 break
-
-    def repr_tb_short(self, item, excinfo, traceback, recursionindex): 
-        # XXX refactor
-        self.out.line()
-        last = traceback[-1]
-        for index, entry in py.builtin.enumerate(traceback):
-            path = entry.path.basename
-            firstsourceline = entry.getfirstlinesource()
-            relline = entry.lineno - firstsourceline
-            self.out.line('  File "%s", line %d, in %s' % (
-                path, entry.lineno+1, entry.name))
-            try:
-                source = entry.getsource().lines
-                source = source[relline].lstrip()
-            except (IndexError, py.error.ENOENT):
-                source = None
-            else:
-                self.out.line("    " + source) 
-            if entry == last:
-                self.repr_exconly(excinfo, indent=4)
-            self.repr_locals(entry.locals) 
-
-            # trailing info 
-            if entry == last:
-                self.repr_out_err(item)
-                self.out.sep("_")
-            else: 
-                if index == recursionindex:
-                    self.out.line("Recursion detected (same locals & position)")
-                    self.out.sep("!")
-                    break 
-
-    # the following is only used by the combination '--pdb --tb=no'
-    repr_tb_no = repr_tb_short 
-

Copied: py/branch/event/py/code/testing/test_tbpresent.py (from r56617, py/branch/event/py/test2/testing/test_present.py)
==============================================================================
--- py/branch/event/py/test2/testing/test_present.py	(original)
+++ py/branch/event/py/code/testing/test_tbpresent.py	Thu Jul 17 19:07:10 2008
@@ -1,36 +1,27 @@
 
 import py
-from py.__.test2 import present, repevent
-import suptest, setupdata
-import re, sys
+import re
+from py.__.code.tbpresent import TBPresenter
 
-
-class TestPresenter: 
+class TestTracebackPresenter: 
     def setup_class(cls):
-        cls.tmpdir = py.test2.ensuretemp(cls.__name__) 
+        cls.clstmpdir = py.test2.ensuretemp(cls.__name__) 
 
-    def getpresenter(self, cmdlinearg=None):
-        args = [self.tmpdir]
-        if cmdlinearg:
-            args.append(cmdlinearg)
-        config = py.test2.config._reparse(args)
-        return present.FuncPresenter(config)
+    def setup_method(self, method):
+        self.tmpdir = self.clstmpdir.ensure(method.__name__, dir=1)
 
-    def gentest(self, check, **options):
-        print "using config options", options
-        p = self.getpresenter()
-        for name, value in options.items():
-            setattr(p.config.option, name, value)
-        check(p)
+    def getpresenter(self, **kwargs):
+        return TBPresenter(**kwargs)
 
     def test_repr_source(self):
+        pr = self.getpresenter()
         source = py.code.Source("""
             def f(x):
                 pass
         """).strip()
-        p = self.getpresenter()
-        p.repr_source(source, "|", 0)
-        lines = p.stringio.getvalue().split("\n")
+        pr.flow_marker = "|"
+        pr.repr_source(source, 0)
+        lines = pr.stringio.getvalue().split("\n")
         assert len(lines) == 3
         assert lines[0].startswith("|")
         assert lines[0].find("def f(x)") != -1
@@ -47,134 +38,152 @@
                 e = py.code.ExceptionInfo()
             return e
     
-        p = self.getpresenter()
+        pr = self.getpresenter()
         source = py.code.Source(f)
         e = f()
-        p.repr_failure_explanation(e, source)
-        assert p.stringio.getvalue().startswith("E   ")
+        pr.repr_failure_explanation(e, source)
+        assert pr.stringio.getvalue().startswith("E   ")
 
     def test_repr_local(self):
-        p = self.getpresenter("--showlocals") 
+        p = self.getpresenter(showlocals=True)
         loc = locals()
         p.repr_locals(loc) 
         result = p.stringio.getvalue()
         for key in loc.keys(): 
             assert result.find(key) != -1 
 
-    def test_repr_failure_simple(self):
-        item, excinfo = suptest.getfailing("""
-            def test_one():
-                # failingsourcemarker 
-                assert 42 == 43
+    def importasmod(self, source):
+        source = py.code.Source(source)
+        modpath = self.tmpdir.join("mod.py")
+        self.tmpdir.ensure("__init__.py")
+        modpath.write(source)
+        return modpath.pyimport()
+
+    def test_repr_tbentry(self):
+        mod = self.importasmod("""
+            def func1():
+                raise ValueError("hello")
+            def entry():
+                func1()
         """)
+        excinfo = py.test.raises(ValueError, mod.entry)
         p = self.getpresenter()
-        p.repr_failure(item, excinfo)
+        p.repr_tb_entry(excinfo.traceback[-2])
         s = p.stringio.getvalue()
-        print s
-        assert re.search("entrypoint:.*\.test_one", s)
-        assert s.find("# failingsourcemarker") != -1
-        assert re.search(r"E.*assert 42 == 43", s)
-        assert re.search(r">.*assert 42 == 43", s) 
+        lines = s.split("\n")
 
-    def test_repr_failure_recursive_funcs(self):
-        item, excinfo = suptest.getfailing("""
-            def rec2(x):
-                return rec1(x+1)
-            def rec1(x):
-                return rec2(x-1)
-            def test_one():
-                rec1(42)
-        """)
-        def check(p): 
-            p.repr_failure(item, excinfo)
-            s = p.stringio.getvalue()
-            print s
-            assert re.search(".*return rec1.*x\+1", s)
-            assert re.search(".*return rec2.*x-1.*", s)
-            assert re.search("Recursion detected", s)
+        # test intermittent entries 
 
-        self.gentest(check, fulltrace=True)
-        self.gentest(check, fulltrace=False)
-        self.gentest(check, tbstyle='short')
-        self.gentest(check, showlocals=True)
-
-    def test_repr_failing_setup(self):
-        item, excinfo = suptest.getfailing("""
-            def setup_module(mod):
-                xyz 
-            def test_one():
-                pass 
-        """)
-        def check(p): 
-            p.repr_failure(item, excinfo)
-            s = p.stringio.getvalue()
-            print s
-            assert re.search("   xyz", s) 
-            assert re.search("NameError:.*xyz", s) 
-
-        self.gentest(check, tbstyle="short")
-        self.gentest(check, fulltrace=True)
-        self.gentest(check, showlocals=True)
-
-    def test_repr_failing_generator_itself(self):
-        sorter = suptest.events_from_runsource("""
-            def test_gen():
-                def check(x):
-                    assert x
-                xyz
-                yield check, 0
-        """)
-        l = sorter.getfailedcollections()
-        assert len(l) == 1
-        ev = l[0]
-        print ev
-        s = ev.collector.repr_failure(ev.excinfo)
+        assert lines[0] == "    def entry():"
+        assert lines[1] == ">       func1()"
+        assert not lines[2]
+        assert lines[3] == "[%s:5]" %(mod.__file__,)
+
+        # test last entry 
+        p = self.getpresenter()
+        p.repr_tb_entry(excinfo.traceback[-1], excinfo)
+        s = p.stringio.getvalue()
+        lines = s.split("\n")
         print s
-        i = s.find("def ")
-        assert i != -1
-        assert s[i:].startswith("def test_gen():")
-        assert s.find("NameError: ") != -1
-
-    def test_repr_failing_generated_test(self):
-        item, excinfo = suptest.getfailing("""
-            def test_gen():
-                def check(x):
-                    assert x
-                yield check, 0
-        """)
-        s = item.repr_failure(excinfo)
+        assert lines[0] == "    def func1():"
+        assert lines[1] == '>       raise ValueError("hello")'
+        assert lines[2] == "E       ValueError: hello"
+        assert not lines[3]
+        assert lines[4] == "[%s:3]" %(mod.__file__,)
+        
+
+    def test_repr_tbentry_short(self):
+        mod = self.importasmod("""
+            def func1():
+                raise ValueError("hello")
+            def entry():
+                func1()
+        """)
+        excinfo = py.test.raises(ValueError, mod.entry)
+        p = self.getpresenter(style="short")
+        p.repr_tb_entry(excinfo.traceback[-2])
+        s = p.stringio.getvalue()
+        lines = s.split("\n")
+        basename = py.path.local(mod.__file__).basename
+        assert lines[0] == '  File "%s", line 5, in entry' % basename 
+        assert lines[1] == '    func1()' 
+        assert not lines[2] 
+
+        # test last entry 
         print s
+        p = self.getpresenter(style="short")
+        p.repr_tb_entry(excinfo.traceback[-1], excinfo)
+        s = p.stringio.getvalue()
         lines = s.split("\n")
-        assert lines[2].find("test_gen[0] -> check(0,)") != -1
-        assert lines[3].find("def check(x):") != -1
-        item._config.option.fulltrace = True
-        s = item.repr_failure(excinfo) 
+        assert lines[0] == '  File "%s", line 3, in func1' % basename 
+        assert lines[1] == '    raise ValueError("hello")'
+        assert lines[2] == 'E   ValueError: hello'
+        assert not lines[3] 
+
+    def test_repr_tbentry_no(self):
+        mod = self.importasmod("""
+            def func1():
+                raise ValueError("hello")
+            def entry():
+                func1()
+        """)
+        excinfo = py.test.raises(ValueError, mod.entry)
+        p = self.getpresenter(style="no")
+        p.repr_tb_entry(excinfo.traceback[-2])
+        s = p.stringio.getvalue()
+        assert not s
+        p = self.getpresenter(style="no")
+        p.repr_tb_entry(excinfo.traceback[-1], excinfo)
+        s = p.stringio.getvalue()
         lines = s.split("\n")
-        assert lines[2].find("test_gen[0] -> check(0,)") == -1
+        assert lines[0] == 'E   ValueError: hello'
 
-    def test_repr_tb_short(self):
-        item, excinfo = suptest.getfailing("""
+
+    def test_repr_tb(self):
+        mod = self.importasmod("""
             def f(x):
-                assert x 
-            def test_f():
+                raise ValueError(x)
+            def entry():
                 f(0)
         """)
-        item._config.option.tbstyle = "short" 
-        s = item.repr_failure(excinfo)
-        print s
-        index = -1 
-        basename = item.fspath.basename 
-        lines = s.split("\n")[3:]
-        for line in (
-              '  File "%s", line 5, in test_f' % basename, 
-              '    f(0)', 
-              '  File "%s", line 3, in f' % basename, 
-              '    assert x',
-              'E   assert 0'
-        ):
-            actual = lines.pop(0)
-            actual = actual.rstrip()
-            if line != actual:
-                print "expected:", repr(line)
-                print "got     :", repr(actual)
-                assert 0
+        p = self.getpresenter(style="short")
+        excinfo = py.test.raises(ValueError, mod.entry)
+        l = []
+        p.repr_tb_entry = lambda entry, excinfo=None: l.append((entry,excinfo))
+        p.repr_sep = lambda sep: l.append(sep)
+        s = p.repr_tb(excinfo)
+        print l
+        assert l[-1] == "_"
+        entry, excinfo2 = l[-2]
+        assert excinfo == excinfo2
+        assert entry == excinfo.traceback[-1]
+        assert l[-3] == "_ "
+        entry, excinfo2 = l[-4]
+        assert excinfo2 is None
+        assert entry == excinfo.traceback[-2]
+        
+    def test_repr_tb_recursion(self):
+        mod = self.importasmod("""
+            def rec2(x):
+                return rec1(x+1)
+            def rec1(x):
+                return rec2(x-1)
+            def entry():
+                rec1(42)
+        """)
+        excinfo = py.test.raises(RuntimeError, mod.entry)
+
+        for style in ("short", "long"):
+            p = self.getpresenter(style="short")
+            l = []
+            p.repr_tb_entry = lambda entry, excinfo=None: l.append((entry,excinfo))
+            p.repr_sep = lambda sep: l.append(sep)
+            p.repr_tb(excinfo)
+            s = p.stringio.getvalue()
+            print l
+            #assert re.search(".*return rec1.*x\+1", s)
+            #assert re.search(".*return rec2.*x-1.*", s)
+            assert len(l) < 20 
+            assert re.search("Recursion detected", s)
+            assert l[-1] == "_ "
+            assert l[-2][0].lineno == 4



More information about the pytest-commit mailing list