Kill a hack for explicit isinstance(). We've got just two methods, so doing full getmro doesn't seem to make too much sense. Anyway this changes semantics slightly, so now we rely on exact inheritance rather than name (I don't have good answer for those) --HG-- branch : trunk
295 lines
11 KiB
Python
295 lines
11 KiB
Python
import py
|
|
|
|
from time import time as now
|
|
from py.__.test.terminal.out import getout
|
|
from py.__.test.representation import Presenter
|
|
from py.__.test.outcome import Skipped, Passed, Failed
|
|
|
|
def getrelpath(source, dest):
|
|
base = source.common(dest)
|
|
if not base:
|
|
return None
|
|
# with posix local paths '/' is always a common base
|
|
relsource = source.relto(base)
|
|
reldest = dest.relto(base)
|
|
n = relsource.count(source.sep)
|
|
target = dest.sep.join(('..', )*n + (reldest, ))
|
|
return target
|
|
|
|
from py.__.test.session import Session
|
|
|
|
class TerminalSession(Session):
|
|
def __init__(self, config, file=None):
|
|
super(TerminalSession, self).__init__(config)
|
|
if file is None:
|
|
file = py.std.sys.stdout
|
|
self._file = file
|
|
self.out = getout(file)
|
|
self._opencollectors = []
|
|
self.presenter = Presenter(self.out, config)
|
|
|
|
# ---------------------
|
|
# PROGRESS information
|
|
# ---------------------
|
|
|
|
def start(self, colitem):
|
|
super(TerminalSession, self).start(colitem)
|
|
if self.config.option.collectonly:
|
|
cols = self._opencollectors
|
|
self.out.line(' ' * len(cols) + repr(colitem))
|
|
cols.append(colitem)
|
|
else:
|
|
cls = getattr(colitem, '__class__', None)
|
|
if cls is None:
|
|
return
|
|
if issubclass(cls, py.test.collect.Module):
|
|
self.start_Module(colitem)
|
|
elif issubclass(cls, py.test.collect.Item):
|
|
self.start_Item(colitem)
|
|
#for typ in py.std.inspect.getmro(cls):
|
|
# meth = getattr(self, 'start_%s' % typ.__name__, None)
|
|
# if meth:
|
|
# meth(colitem)
|
|
# break
|
|
colitem.start = py.std.time.time()
|
|
|
|
def start_Module(self, colitem):
|
|
if self.config.option.verbose == 0:
|
|
abbrev_fn = getrelpath(py.path.local('.xxx.'), colitem.fspath)
|
|
self.out.write('%s' % (abbrev_fn, ))
|
|
else:
|
|
self.out.line()
|
|
self.out.line("+ testmodule: %s" % colitem.fspath)
|
|
|
|
def startiteration(self, colitem, subitems):
|
|
if (isinstance(colitem, py.test.collect.Module)
|
|
and self.config.option.verbose == 0
|
|
and not self.config.option.collectonly):
|
|
try:
|
|
sum = 0
|
|
for sub in subitems:
|
|
sum += len(list(colitem.join(sub)._tryiter()))
|
|
except (SystemExit, KeyboardInterrupt):
|
|
raise
|
|
except:
|
|
self.out.write('[?]')
|
|
else:
|
|
self.out.write('[%d] ' % sum)
|
|
return self.out.line
|
|
|
|
def start_Item(self, colitem):
|
|
if self.config.option.verbose >= 1:
|
|
if isinstance(colitem, py.test.collect.Item):
|
|
realpath, lineno = colitem._getpathlineno()
|
|
location = "%s:%d" % (realpath.basename, lineno+1)
|
|
self.out.write("%-20s %s " % (location, colitem._getmodpath()))
|
|
|
|
def finish(self, colitem, outcome):
|
|
end = now()
|
|
super(TerminalSession, self).finish(colitem, outcome)
|
|
if self.config.option.collectonly:
|
|
cols = self._opencollectors
|
|
last = cols.pop()
|
|
#assert last == colitem, "expected %r, got %r" %(last, colitem)
|
|
return
|
|
colitem.elapsedtime = end - colitem.start
|
|
if self.config.option.usepdb:
|
|
if isinstance(outcome, Failed):
|
|
print "dispatching to ppdb", colitem
|
|
self.repr_failure(colitem, outcome)
|
|
import pdb
|
|
self.out.write('\n%s\n' % (outcome.excinfo.exconly(),))
|
|
pdb.post_mortem(outcome.excinfo._excinfo[2])
|
|
if isinstance(colitem, py.test.collect.Module):
|
|
resultstring = self.repr_progress_module_result(colitem, outcome)
|
|
if resultstring:
|
|
self.out.line(" - " + resultstring)
|
|
if isinstance(colitem, py.test.collect.Item):
|
|
if self.config.option.verbose >= 1:
|
|
resultstring = self.repr_progress_long_result(colitem, outcome)
|
|
resultstring += " (%.2f)" % (colitem.elapsedtime,)
|
|
self.out.line(resultstring)
|
|
else:
|
|
c = self.repr_progress_short_result(colitem, outcome)
|
|
self.out.write(c)
|
|
|
|
|
|
# -------------------
|
|
# HEADER information
|
|
# -------------------
|
|
def header(self, colitems):
|
|
super(TerminalSession, self).header(colitems)
|
|
self.out.sep("=", "test process starts")
|
|
option = self.config.option
|
|
modes = []
|
|
for name in 'looponfailing', 'exitfirst', 'nomagic':
|
|
if getattr(option, name):
|
|
modes.append(name)
|
|
#if self._isremoteoption._fromremote:
|
|
# modes.insert(0, 'child process')
|
|
#else:
|
|
# modes.insert(0, 'inprocess')
|
|
#mode = "/".join(modes)
|
|
#self.out.line("testing-mode: %s" % mode)
|
|
self.out.line("executable: %s (%s)" %
|
|
(py.std.sys.executable, repr_pythonversion()))
|
|
rev = py.__package__.getrev()
|
|
self.out.line("using py lib: %s <rev %s>" % (
|
|
py.path.local(py.__file__).dirpath(), rev))
|
|
|
|
if self.config.option.traceconfig or self.config.option.verbose:
|
|
|
|
for x in colitems:
|
|
self.out.line("test target: %s" %(x.fspath,))
|
|
|
|
conftestmodules = self.config._conftest.getconftestmodules(None)
|
|
for i,x in py.builtin.enumerate(conftestmodules):
|
|
self.out.line("initial conf %d: %s" %(i, x.__file__))
|
|
|
|
#for i, x in py.builtin.enumerate(py.test.config.configpaths):
|
|
# self.out.line("initial testconfig %d: %s" %(i, x))
|
|
#additional = py.test.config.getfirst('additionalinfo')
|
|
#if additional:
|
|
# for key, descr in additional():
|
|
# self.out.line("%s: %s" %(key, descr))
|
|
self.out.line()
|
|
self.starttime = now()
|
|
|
|
# -------------------
|
|
# FOOTER information
|
|
# -------------------
|
|
|
|
def footer(self, colitems):
|
|
super(TerminalSession, self).footer(colitems)
|
|
self.endtime = now()
|
|
self.out.line()
|
|
self.skippedreasons()
|
|
self.failures()
|
|
self.summaryline()
|
|
|
|
# --------------------
|
|
# progress information
|
|
# --------------------
|
|
typemap = {
|
|
Passed: '.',
|
|
Skipped: 's',
|
|
Failed: 'F',
|
|
}
|
|
namemap = {
|
|
Passed: 'ok',
|
|
Skipped: 'SKIP',
|
|
Failed: 'FAIL',
|
|
}
|
|
|
|
def repr_progress_short_result(self, item, outcome):
|
|
for outcometype, char in self.typemap.items():
|
|
if isinstance(outcome, outcometype):
|
|
return char
|
|
else:
|
|
#raise TypeError, "not an Outomce instance: %r" % (outcome,)
|
|
return '?'
|
|
|
|
def repr_progress_long_result(self, item, outcome):
|
|
for outcometype, char in self.namemap.items():
|
|
if isinstance(outcome, outcometype):
|
|
return char
|
|
else:
|
|
#raise TypeError, "not an Outcome instance: %r" % (outcome,)
|
|
return 'UNKNOWN'
|
|
|
|
def repr_progress_module_result(self, item, outcome):
|
|
if isinstance(outcome, Failed):
|
|
return "FAILED TO LOAD MODULE"
|
|
elif isinstance(outcome, Skipped):
|
|
return "skipped"
|
|
elif not isinstance(outcome, (list, Passed)):
|
|
return "?"
|
|
|
|
# --------------------
|
|
# summary information
|
|
# --------------------
|
|
def summaryline(self):
|
|
outlist = []
|
|
sum = 0
|
|
for typ in Passed, Failed, Skipped:
|
|
l = self.getitemoutcomepairs(typ)
|
|
if l:
|
|
outlist.append('%d %s' % (len(l), typ.__name__.lower()))
|
|
sum += len(l)
|
|
elapsed = self.endtime-self.starttime
|
|
status = "%s" % ", ".join(outlist)
|
|
self.out.sep('=', 'tests finished: %s in %4.2f seconds' %
|
|
(status, elapsed))
|
|
|
|
def getlastvisible(self, sourcetraceback):
|
|
traceback = sourcetraceback[:]
|
|
while traceback:
|
|
entry = traceback.pop()
|
|
try:
|
|
x = entry.frame.eval("__tracebackhide__")
|
|
except:
|
|
x = False
|
|
if not x:
|
|
return entry
|
|
else:
|
|
return sourcetraceback[-1]
|
|
|
|
def skippedreasons(self):
|
|
texts = {}
|
|
for colitem, outcome in self.getitemoutcomepairs(Skipped):
|
|
raisingtb = self.getlastvisible(outcome.excinfo.traceback)
|
|
fn = raisingtb.frame.code.path
|
|
lineno = raisingtb.lineno
|
|
d = texts.setdefault(outcome.excinfo.exconly(), {})
|
|
d[(fn,lineno)] = outcome
|
|
|
|
if texts:
|
|
self.out.line()
|
|
self.out.sep('_', 'reasons for skipped tests')
|
|
for text, dict in texts.items():
|
|
for (fn, lineno), outcome in dict.items():
|
|
self.out.line('Skipped in %s:%d' %(fn, lineno+1))
|
|
self.out.line("reason: %s" % text)
|
|
self.out.line()
|
|
|
|
def failures(self):
|
|
if self.config.option.tbstyle == 'no':
|
|
return # skip the detailed failure reports altogether
|
|
l = self.getitemoutcomepairs(Failed)
|
|
if l:
|
|
self.out.sep('_')
|
|
for colitem, outcome in l:
|
|
self.repr_failure(colitem, outcome)
|
|
|
|
def repr_failure(self, item, outcome):
|
|
excinfo = outcome.excinfo
|
|
traceback = excinfo.traceback
|
|
#print "repr_failures sees item", item
|
|
#print "repr_failures sees traceback"
|
|
#py.std.pprint.pprint(traceback)
|
|
if item and not self.config.option.fulltrace:
|
|
path, firstlineno = item._getpathlineno()
|
|
ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
|
|
if ntraceback == traceback:
|
|
ntraceback = ntraceback.cut(path=path)
|
|
traceback = ntraceback.filter()
|
|
if not traceback:
|
|
self.out.line("empty traceback from item %r" % (item,))
|
|
return
|
|
handler = getattr(self.presenter, 'repr_failure_tb%s' % self.config.option.tbstyle)
|
|
handler(item, excinfo, traceback, lambda : self.repr_out_err(item))
|
|
|
|
def repr_out_err(self, colitem):
|
|
for parent in colitem.listchain():
|
|
for name, obj in zip(['out', 'err'], parent._getouterr()):
|
|
if obj:
|
|
self.out.sep("- ", "%s: recorded std%s" % (parent.name, name))
|
|
self.out.line(obj)
|
|
|
|
def repr_pythonversion():
|
|
v = py.std.sys.version_info
|
|
try:
|
|
return "%s.%s.%s-%s-%s" % v
|
|
except ValueError:
|
|
return str(v)
|