[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