merge samuele's metainfo() branch

also fix a test after broken rename

--HG--
branch : trunk
This commit is contained in:
holger krekel 2009-05-12 19:09:27 +02:00
commit 286460b94e
12 changed files with 132 additions and 53 deletions

View File

@ -133,6 +133,7 @@ initpkg(__name__,
'code.Frame' : ('./code/frame.py', 'Frame'), 'code.Frame' : ('./code/frame.py', 'Frame'),
'code.ExceptionInfo' : ('./code/excinfo.py', 'ExceptionInfo'), 'code.ExceptionInfo' : ('./code/excinfo.py', 'ExceptionInfo'),
'code.Traceback' : ('./code/traceback2.py', 'Traceback'), 'code.Traceback' : ('./code/traceback2.py', 'Traceback'),
'code.getfslineno' : ('./code/source.py', 'getfslineno'),
# backports and additions of builtins # backports and additions of builtins
'builtin.__doc__' : ('./builtin/__init__.py', '__doc__'), 'builtin.__doc__' : ('./builtin/__init__.py', '__doc__'),

View File

@ -217,6 +217,26 @@ def compile_(source, filename=None, mode='exec', flags=
return co return co
def getfslineno(obj):
try:
code = py.code.Code(obj)
except TypeError:
# fallback to
fn = (py.std.inspect.getsourcefile(obj) or
py.std.inspect.getfile(obj))
fspath = fn and py.path.local(fn) or None
if fspath:
try:
_, lineno = findsource(obj)
except IOError:
lineno = None
else:
lineno = None
else:
fspath = code.path
lineno = code.firstlineno
return fspath, lineno
# #
# helper functions # helper functions
# #

View File

@ -355,3 +355,27 @@ def test_findsource___source__():
assert 'if 1:' in str(src) assert 'if 1:' in str(src)
assert src[lineno] == " def x():" assert src[lineno] == " def x():"
def test_getfslineno():
from py.code import getfslineno
def f(x):
pass
fspath, lineno = getfslineno(f)
fname = __file__
if fname.lower().endswith('.pyc'):
fname = fname[:-1]
assert fspath == py.path.local(fname)
assert lineno == f.func_code.co_firstlineno-1 # see findsource
class A(object):
pass
fspath, lineno = getfslineno(A)
_, A_lineno = py.std.inspect.findsource(A)
assert fspath == py.path.local(fname)
assert lineno == A_lineno

View File

@ -439,7 +439,7 @@ class Item(Node):
""" deprecated, here because subclasses might call it. """ """ deprecated, here because subclasses might call it. """
return obj(*args) return obj(*args)
def metainfo(self): def reportinfo(self):
return self.fspath, None, "" return self.fspath, None, ""
def warnoldcollect(function=None): def warnoldcollect(function=None):

View File

@ -111,7 +111,7 @@ class FuncargRequest:
name = name[len(self._argprefix):] name = name[len(self._argprefix):]
if name not in available: if name not in available:
available.append(name) available.append(name)
fspath, lineno, msg = self._pyfuncitem.metainfo() fspath, lineno, msg = self._pyfuncitem.reportinfo()
line = "%s:%s" %(fspath, lineno) line = "%s:%s" %(fspath, lineno)
msg = "funcargument %r not found for: %s" %(self.argname, line) msg = "funcargument %r not found for: %s" %(self.argname, line)
msg += "\n available funcargs: %s" %(", ".join(available),) msg += "\n available funcargs: %s" %(", ".join(available),)

View File

@ -99,6 +99,12 @@ class PluginHooks:
def pytest_terminal_summary(self, terminalreporter): def pytest_terminal_summary(self, terminalreporter):
""" add additional section in terminal summary reporting. """ """ add additional section in terminal summary reporting. """
def pytest_report_iteminfo(self, item):
""" return (fspath, lineno, name) for the item.
the information is used for result display and to sort tests
"""
pytest_report_iteminfo.firstresult = True
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# doctest hooks # doctest hooks
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -54,6 +54,9 @@ class DefaultPlugin:
Directory = parent.config.getvalue('Directory', path) Directory = parent.config.getvalue('Directory', path)
return Directory(path, parent=parent) return Directory(path, parent=parent)
def pytest_report_iteminfo(self, item):
return item.reportinfo()
def pytest_addoption(self, parser): def pytest_addoption(self, parser):
group = parser.addgroup("general", "test collection and failure interaction options") group = parser.addgroup("general", "test collection and failure interaction options")
group._addoption('-v', '--verbose', action="count", group._addoption('-v', '--verbose', action="count",
@ -248,3 +251,16 @@ def test_dist_options(testdir):
config = testdir.parseconfigure("-d") config = testdir.parseconfigure("-d")
assert config.option.dist == "load" assert config.option.dist == "load"
def test_pytest_report_iteminfo():
plugin = DefaultPlugin()
class FakeItem(object):
def reportinfo(self):
return "-reportinfo-"
res = plugin.pytest_report_iteminfo(FakeItem())
assert res == "-reportinfo-"

View File

@ -64,7 +64,7 @@ class ReSTSyntaxTest(py.test.collect.Item):
super(ReSTSyntaxTest, self).__init__(*args, **kwargs) super(ReSTSyntaxTest, self).__init__(*args, **kwargs)
self.project = project self.project = project
def metainfo(self): def reportinfo(self):
return self.fspath, None, "syntax check" return self.fspath, None, "syntax check"
def runtest(self): def runtest(self):
@ -196,7 +196,7 @@ class ReSTSyntaxTest(py.test.collect.Item):
#return [] # no need to rebuild #return [] # no need to rebuild
class DoctestText(py.test.collect.Item): class DoctestText(py.test.collect.Item):
def metainfo(self): def reportinfo(self):
return self.fspath, None, "doctest" return self.fspath, None, "doctest"
def runtest(self): def runtest(self):
@ -282,7 +282,7 @@ class LinkCheckerMaker(py.test.collect.Collector):
args=(tryfn, path, lineno), callobj=localrefcheck) args=(tryfn, path, lineno), callobj=localrefcheck)
class CheckLink(py.test.collect.Function): class CheckLink(py.test.collect.Function):
def metainfo(self, basedir=None): def reportinfo(self, basedir=None):
return (self.fspath, self._args[2], "checklink: %s" % self._args[0]) return (self.fspath, self._args[2], "checklink: %s" % self._args[0])
def setup(self): def setup(self):

View File

@ -149,19 +149,19 @@ class TerminalReporter:
# for dist-testing situations itemstart means we # for dist-testing situations itemstart means we
# queued the item for sending, not interesting (unless debugging) # queued the item for sending, not interesting (unless debugging)
if self.config.option.debug: if self.config.option.debug:
line = self._metainfoline(item) line = self._reportinfoline(item)
extra = "" extra = ""
if node: if node:
extra = "-> " + str(node.gateway.id) extra = "-> " + str(node.gateway.id)
self.write_ensure_prefix(line, extra) self.write_ensure_prefix(line, extra)
else: else:
if self.config.option.verbose: if self.config.option.verbose:
line = self._metainfoline(item) line = self._reportinfoline(item)
self.write_ensure_prefix(line, "") self.write_ensure_prefix(line, "")
else: else:
# ensure that the path is printed before the # ensure that the path is printed before the
# 1st test of a module starts running # 1st test of a module starts running
fspath, lineno, msg = item.metainfo() fspath, lineno, msg = self._getreportinfo(item)
self.write_fspath_result(fspath, "") self.write_fspath_result(fspath, "")
def pytest_itemtestreport(self, rep): def pytest_itemtestreport(self, rep):
@ -173,10 +173,10 @@ class TerminalReporter:
markup = {} markup = {}
self.stats.setdefault(cat, []).append(rep) self.stats.setdefault(cat, []).append(rep)
if not self.config.option.verbose: if not self.config.option.verbose:
fspath, lineno, msg = rep.colitem.metainfo() fspath, lineno, msg = self._getreportinfo(rep.colitem)
self.write_fspath_result(fspath, letter) self.write_fspath_result(fspath, letter)
else: else:
line = self._metainfoline(rep.colitem) line = self._reportinfoline(rep.colitem)
if not hasattr(rep, 'node'): if not hasattr(rep, 'node'):
self.write_ensure_prefix(line, word, **markup) self.write_ensure_prefix(line, word, **markup)
else: else:
@ -254,8 +254,8 @@ class TerminalReporter:
for rootdir in rootdirs: for rootdir in rootdirs:
self.write_line("### Watching: %s" %(rootdir,), bold=True) self.write_line("### Watching: %s" %(rootdir,), bold=True)
def _metainfoline(self, item): def _reportinfoline(self, item):
fspath, lineno, msg = item.metainfo() fspath, lineno, msg = self._getreportinfo(item)
if fspath: if fspath:
fspath = self.curdir.bestrelpath(fspath) fspath = self.curdir.bestrelpath(fspath)
if lineno is not None: if lineno is not None:
@ -267,16 +267,26 @@ class TerminalReporter:
elif fspath and lineno: elif fspath and lineno:
line = "%(fspath)s:%(lineno)s" line = "%(fspath)s:%(lineno)s"
else: else:
line = "[nometainfo]" line = "[noreportinfo]"
return line % locals() + " " return line % locals() + " "
def _getfailureheadline(self, rep): def _getfailureheadline(self, rep):
if isinstance(rep.colitem, py.test.collect.Collector): if isinstance(rep.colitem, py.test.collect.Collector):
return str(rep.colitem.fspath) return str(rep.colitem.fspath)
else: else:
fspath, lineno, msg = rep.colitem.metainfo() fspath, lineno, msg = self._getreportinfo(rep.colitem)
return msg return msg
def _getreportinfo(self, item):
try:
return item.__reportinfo
except AttributeError:
pass
reportinfo = item.config.hook.pytest_report_iteminfo(item=item)
# cache on item
item.__reportinfo = reportinfo
return reportinfo
# #
# summaries for testrunfinish # summaries for testrunfinish
# #
@ -579,11 +589,11 @@ class TestTerminal:
"*test_show_path_before_running_test.py*" "*test_show_path_before_running_test.py*"
]) ])
def test_itemreport_metainfo(self, testdir, linecomp): def test_itemreport_reportinfo(self, testdir, linecomp):
testdir.makeconftest(""" testdir.makeconftest("""
import py import py
class Function(py.test.collect.Function): class Function(py.test.collect.Function):
def metainfo(self): def reportinfo(self):
return "ABCDE", 42, "custom" return "ABCDE", 42, "custom"
""") """)
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")
@ -599,6 +609,25 @@ class TestTerminal:
"*ABCDE:43: custom*" "*ABCDE:43: custom*"
]) ])
def test_itemreport_pytest_report_iteminfo(self, testdir, linecomp):
item = testdir.getitem("def test_func(): pass")
class Plugin:
def pytest_report_iteminfo(self, item):
return "FGHJ", 42, "custom"
item.config.pluginmanager.register(Plugin())
tr = TerminalReporter(item.config, file=linecomp.stringio)
item.config.pluginmanager.register(tr)
tr.config.hook.pytest_itemstart(item=item)
linecomp.assert_contains_lines([
"*FGHJ "
])
tr.config.option.verbose = True
tr.config.hook.pytest_itemstart(item=item)
linecomp.assert_contains_lines([
"*FGHJ:43: custom*"
])
def pseudo_keyboard_interrupt(self, testdir, linecomp, verbose=False): def pseudo_keyboard_interrupt(self, testdir, linecomp, verbose=False):
modcol = testdir.getmodulecol(""" modcol = testdir.getmodulecol("""
def test_foobar(): def test_foobar():

View File

@ -18,7 +18,6 @@ a tree of collectors and test items that this modules provides::
""" """
import py import py
from py.__.test.collect import configproperty, warnoldcollect from py.__.test.collect import configproperty, warnoldcollect
from py.__.code.source import findsource
pydir = py.path.local(py.__file__).dirpath() pydir = py.path.local(py.__file__).dirpath()
from py.__.test import funcargs from py.__.test import funcargs
@ -65,37 +64,21 @@ class PyobjMixin(object):
s = ".".join(parts) s = ".".join(parts)
return s.replace(".[", "[") return s.replace(".[", "[")
def getfslineno(self): def _getfslineno(self):
try: try:
return self._fslineno return self._fslineno
except AttributeError: except AttributeError:
pass pass
obj = self.obj obj = self.obj
# let decorators etc specify a sane ordering # xxx let decorators etc specify a sane ordering
if hasattr(obj, 'place_as'): if hasattr(obj, 'place_as'):
obj = obj.place_as obj = obj.place_as
try:
code = py.code.Code(obj)
except TypeError:
# fallback to
fn = (py.std.inspect.getsourcefile(obj) or
py.std.inspect.getfile(obj))
fspath = fn and py.path.local(fn) or None
if fspath:
try:
_, lineno = findsource(obj)
except IOError:
lineno = None
else:
lineno = None
else:
fspath = code.path
lineno = code.firstlineno
self._fslineno = fspath, lineno
return fspath, lineno
def metainfo(self): self._fslineno = py.code.getfslineno(obj)
fspath, lineno = self.getfslineno() return self._fslineno
def reportinfo(self):
fspath, lineno = self._getfslineno()
modpath = self.getmodpath() modpath = self.getmodpath()
return fspath, lineno, modpath return fspath, lineno, modpath
@ -229,7 +212,7 @@ class Class(PyCollectorMixin, py.test.collect.Collector):
teardown_class(self.obj) teardown_class(self.obj)
def _getsortvalue(self): def _getsortvalue(self):
return self.getfslineno() return self._getfslineno()
class Instance(PyCollectorMixin, py.test.collect.Collector): class Instance(PyCollectorMixin, py.test.collect.Collector):
def _getobj(self): def _getobj(self):
@ -254,7 +237,7 @@ class FunctionMixin(PyobjMixin):
""" """
def _getsortvalue(self): def _getsortvalue(self):
return self.getfslineno() return self._getfslineno()
def setup(self): def setup(self):
""" perform setup for this test function. """ """ perform setup for this test function. """

View File

@ -76,7 +76,7 @@ def forked_run_report(item, pdb=None):
return report_process_crash(item, result) return report_process_crash(item, result)
def report_process_crash(item, result): def report_process_crash(item, result):
path, lineno = item.getfslineno() path, lineno = item._getfslineno()
longrepr = [ longrepr = [
("X", "CRASHED"), ("X", "CRASHED"),
("%s:%s: CRASHED with signal %d" %(path, lineno, result.signal)), ("%s:%s: CRASHED with signal %d" %(path, lineno, result.signal)),

View File

@ -217,7 +217,7 @@ class TestGenerator:
class TestFunction: class TestFunction:
def test_getmodulecollector(self, testdir): def test_getmodulecollector(self, testdir):
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")
modcol = item.getmodulecollector() modcol = item._getparent(py.test.collect.Module)
assert isinstance(modcol, py.test.collect.Module) assert isinstance(modcol, py.test.collect.Module)
assert hasattr(modcol.obj, 'test_func') assert hasattr(modcol.obj, 'test_func')
@ -346,28 +346,28 @@ class TestConftestCustomization:
assert colitems[0].name == "check_method" assert colitems[0].name == "check_method"
class TestMetaInfo: class TestReportinfo:
def test_func_metainfo(self, testdir): def test_func_reportinfo(self, testdir):
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")
fspath, lineno, modpath = item.metainfo() fspath, lineno, modpath = item.reportinfo()
assert fspath == item.fspath assert fspath == item.fspath
assert lineno == 0 assert lineno == 0
assert modpath == "test_func" assert modpath == "test_func"
def test_class_metainfo(self, testdir): def test_class_reportinfo(self, testdir):
modcol = testdir.getmodulecol(""" modcol = testdir.getmodulecol("""
# lineno 0 # lineno 0
class TestClass: class TestClass:
def test_hello(self): pass def test_hello(self): pass
""") """)
classcol = modcol.collect_by_name("TestClass") classcol = modcol.collect_by_name("TestClass")
fspath, lineno, msg = classcol.metainfo() fspath, lineno, msg = classcol.reportinfo()
assert fspath == modcol.fspath assert fspath == modcol.fspath
assert lineno == 1 assert lineno == 1
assert msg == "TestClass" assert msg == "TestClass"
def test_generator_metainfo(self, testdir): def test_generator_reportinfo(self, testdir):
modcol = testdir.getmodulecol(""" modcol = testdir.getmodulecol("""
# lineno 0 # lineno 0
def test_gen(): def test_gen():
@ -376,13 +376,13 @@ class TestMetaInfo:
yield check, 3 yield check, 3
""") """)
gencol = modcol.collect_by_name("test_gen") gencol = modcol.collect_by_name("test_gen")
fspath, lineno, modpath = gencol.metainfo() fspath, lineno, modpath = gencol.reportinfo()
assert fspath == modcol.fspath assert fspath == modcol.fspath
assert lineno == 1 assert lineno == 1
assert modpath == "test_gen" assert modpath == "test_gen"
genitem = gencol.collect()[0] genitem = gencol.collect()[0]
fspath, lineno, modpath = genitem.metainfo() fspath, lineno, modpath = genitem.reportinfo()
assert fspath == modcol.fspath assert fspath == modcol.fspath
assert lineno == 2 assert lineno == 2
assert modpath == "test_gen[0]" assert modpath == "test_gen[0]"