import py from time import time as now Item = py.test.Item from py.__.test.terminal.out import getout from py.__.test.representation import Presenter 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 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.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, Item.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.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 " % ( 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 = { Item.Passed: '.', Item.Skipped: 's', Item.Failed: 'F', } namemap = { Item.Passed: 'ok', Item.Skipped: 'SKIP', Item.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, py.test.Item.Failed): return "FAILED TO LOAD MODULE" elif isinstance(outcome, py.test.Item.Skipped): return "skipped" elif not isinstance(outcome, (list, py.test.Item.Passed)): return "?" # -------------------- # summary information # -------------------- def summaryline(self): outlist = [] sum = 0 for typ in Item.Passed, Item.Failed, Item.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(Item.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(Item.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)