* refine and rename pycollect related hooks
* refine runtest/test function call protocol --HG-- branch : trunk
This commit is contained in:
parent
a59d602bce
commit
771438fde5
|
@ -91,12 +91,11 @@ def pytest_configure(config):
|
||||||
def pytest_unconfigure(config):
|
def pytest_unconfigure(config):
|
||||||
gr_twisted.switch(None)
|
gr_twisted.switch(None)
|
||||||
|
|
||||||
def pytest_pyfunc_call(pyfuncitem, *args, **kwargs):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
args = args or pyfuncitem._args # generator tests
|
|
||||||
# XXX1 kwargs?
|
# XXX1 kwargs?
|
||||||
# XXX2 we want to delegate actual call to next plugin
|
# XXX2 we want to delegate actual call to next plugin
|
||||||
# (which may want to produce test coverage, etc.)
|
# (which may want to produce test coverage, etc.)
|
||||||
res = gr_twisted.switch(lambda: pyfuncitem.obj(*args))
|
res = gr_twisted.switch(lambda: pyfuncitem.call())
|
||||||
if res:
|
if res:
|
||||||
res.raiseException()
|
res.raiseException()
|
||||||
return True # indicates that we performed the function call
|
return True # indicates that we performed the function call
|
||||||
|
|
|
@ -46,8 +46,8 @@ for early mismatch reporting and minimizes version incompatibilites.
|
||||||
|
|
||||||
.. _`original definition of the hook`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/hookspec.py
|
.. _`original definition of the hook`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/hookspec.py
|
||||||
|
|
||||||
"runtest" hooks
|
generic "runtest" hooks
|
||||||
-------------------
|
------------------------------
|
||||||
|
|
||||||
Each test item is usually executed by calling the following three hooks::
|
Each test item is usually executed by calling the following three hooks::
|
||||||
|
|
||||||
|
@ -101,6 +101,26 @@ The call object contains information about a performed call::
|
||||||
.. _`pytest_terminal plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_terminal.py
|
.. _`pytest_terminal plugin`: http://bitbucket.org/hpk42/py-trunk/src/tip/py/test/plugin/pytest_terminal.py
|
||||||
|
|
||||||
|
|
||||||
|
generic collection hooks
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
XXX
|
||||||
|
|
||||||
|
Python module and test function hooks
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
For influencing the collection of objects in Python modules
|
||||||
|
you can use the following hook:
|
||||||
|
|
||||||
|
pytest_pycollect_makeitem(collector, name, obj)
|
||||||
|
|
||||||
|
This hook will be called for each Python object in a collected
|
||||||
|
Python module. The return value is a custom `collection node`_.
|
||||||
|
|
||||||
|
.. XXX or ``False`` if you want to indicate that the given item should not be collected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Included default plugins
|
Included default plugins
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
@ -114,6 +134,8 @@ Additionally you can check out some more contributed plugins here
|
||||||
|
|
||||||
|
|
||||||
.. _`collection process`:
|
.. _`collection process`:
|
||||||
|
.. _`collection node`:
|
||||||
|
|
||||||
|
|
||||||
Test Collection process
|
Test Collection process
|
||||||
======================================================
|
======================================================
|
||||||
|
|
|
@ -425,11 +425,11 @@ class Item(Node):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
""" deprecated, here because subclasses might call it. """
|
""" deprecated, here because subclasses might call it. """
|
||||||
return self.execute(self.obj, *self._args)
|
return self.execute(self.obj)
|
||||||
|
|
||||||
def execute(self, obj, *args):
|
def execute(self, obj):
|
||||||
""" deprecated, here because subclasses might call it. """
|
""" deprecated, here because subclasses might call it. """
|
||||||
return obj(*args)
|
return obj()
|
||||||
|
|
||||||
def reportinfo(self):
|
def reportinfo(self):
|
||||||
return self.fspath, None, ""
|
return self.fspath, None, ""
|
||||||
|
|
|
@ -34,9 +34,7 @@ def pytest_deselected(items):
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# collection hooks
|
# collection hooks
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
def pytest_make_collect_report(collector):
|
|
||||||
""" perform a collection and return a collection. """
|
|
||||||
pytest_make_collect_report.firstresult = True
|
|
||||||
|
|
||||||
def pytest_collect_file(path, parent):
|
def pytest_collect_file(path, parent):
|
||||||
""" return Collection node or None. """
|
""" return Collection node or None. """
|
||||||
|
@ -50,25 +48,37 @@ pytest_collect_recurse.firstresult = True
|
||||||
def pytest_collect_directory(path, parent):
|
def pytest_collect_directory(path, parent):
|
||||||
""" return Collection node or None. """
|
""" return Collection node or None. """
|
||||||
|
|
||||||
def pytest_pycollect_obj(collector, name, obj):
|
|
||||||
""" return custom item/collector for a python object in a module, or None. """
|
|
||||||
pytest_pycollect_obj.firstresult = True
|
|
||||||
|
|
||||||
def pytest_generate_tests(metafunc):
|
|
||||||
""" generate (multiple) parametrized calls to a test function."""
|
|
||||||
|
|
||||||
def pytest_collectstart(collector):
|
def pytest_collectstart(collector):
|
||||||
""" collector starts collecting. """
|
""" collector starts collecting. """
|
||||||
|
|
||||||
def pytest_collectreport(rep):
|
def pytest_collectreport(rep):
|
||||||
""" collector finished collecting. """
|
""" collector finished collecting. """
|
||||||
|
|
||||||
|
def pytest_make_collect_report(collector):
|
||||||
|
""" perform a collection and return a collection. """
|
||||||
|
pytest_make_collect_report.firstresult = True
|
||||||
|
|
||||||
# XXX rename to item_collected()? meaning in distribution context?
|
# XXX rename to item_collected()? meaning in distribution context?
|
||||||
def pytest_itemstart(item, node=None):
|
def pytest_itemstart(item, node=None):
|
||||||
""" test item gets collected. """
|
""" test item gets collected. """
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# runtest related hooks
|
# Python test function related hooks
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
|
""" return custom item/collector for a python object in a module, or None. """
|
||||||
|
pytest_pycollect_makeitem.firstresult = True
|
||||||
|
|
||||||
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
|
""" perform function call with the given function arguments. """
|
||||||
|
pytest_pyfunc_call.firstresult = True
|
||||||
|
|
||||||
|
def pytest_generate_tests(metafunc):
|
||||||
|
""" generate (multiple) parametrized calls to a test function."""
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# generic runtest related hooks
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
def pytest_runtest_setup(item):
|
def pytest_runtest_setup(item):
|
||||||
""" called before pytest_runtest_call(). """
|
""" called before pytest_runtest_call(). """
|
||||||
|
@ -83,10 +93,6 @@ def pytest_runtest_protocol(item):
|
||||||
""" run given test item and return test report. """
|
""" run given test item and return test report. """
|
||||||
pytest_runtest_protocol.firstresult = True
|
pytest_runtest_protocol.firstresult = True
|
||||||
|
|
||||||
def pytest_pyfunc_call(pyfuncitem, args, kwargs):
|
|
||||||
""" return True if we consumed/did the call to the python function item. """
|
|
||||||
pytest_pyfunc_call.firstresult = True
|
|
||||||
|
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
""" make ItemTestReport for the specified test outcome. """
|
""" make ItemTestReport for the specified test outcome. """
|
||||||
pytest_runtest_makereport.firstresult = True
|
pytest_runtest_makereport.firstresult = True
|
||||||
|
@ -95,7 +101,7 @@ def pytest_runtest_logreport(rep):
|
||||||
""" process item test report. """
|
""" process item test report. """
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# reporting hooks (invoked from pytest_terminal.py)
|
# generic reporting hooks (invoked from pytest_terminal.py)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
def pytest_report_teststatus(rep):
|
def pytest_report_teststatus(rep):
|
||||||
""" return shortletter and verbose word. """
|
""" return shortletter and verbose word. """
|
||||||
|
@ -117,6 +123,7 @@ def pytest_doctest_prepare_content(content):
|
||||||
""" return processed content for a given doctest"""
|
""" return processed content for a given doctest"""
|
||||||
pytest_doctest_prepare_content.firstresult = True
|
pytest_doctest_prepare_content.firstresult = True
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# misc hooks
|
# misc hooks
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -133,8 +140,6 @@ def pytest_internalerror(excrepr):
|
||||||
def pytest_trace(category, msg):
|
def pytest_trace(category, msg):
|
||||||
""" called for debug info. """
|
""" called for debug info. """
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# distributed testing
|
# distributed testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -2,9 +2,14 @@
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def pytest_pyfunc_call(__call__, pyfuncitem, args, kwargs):
|
def pytest_pyfunc_call(__call__, pyfuncitem):
|
||||||
if not __call__.execute(firstresult=True):
|
if not __call__.execute(firstresult=True):
|
||||||
pyfuncitem.obj(*args, **kwargs)
|
testfunction = pyfuncitem.obj
|
||||||
|
if pyfuncitem._isyieldedfunction():
|
||||||
|
testfunction(*pyfuncitem._args)
|
||||||
|
else:
|
||||||
|
funcargs = pyfuncitem.funcargs
|
||||||
|
testfunction(**funcargs)
|
||||||
|
|
||||||
def pytest_collect_file(path, parent):
|
def pytest_collect_file(path, parent):
|
||||||
ext = path.ext
|
ext = path.ext
|
||||||
|
|
|
@ -29,8 +29,8 @@ class Execnetcleanup:
|
||||||
l.append(gw)
|
l.append(gw)
|
||||||
#for gw in l:
|
#for gw in l:
|
||||||
# gw.join()
|
# gw.join()
|
||||||
#
|
|
||||||
def pytest_pyfunc_call(self, __call__, pyfuncitem, args, kwargs):
|
def pytest_pyfunc_call(self, __call__, pyfuncitem):
|
||||||
if self._gateways is not None:
|
if self._gateways is not None:
|
||||||
gateways = self._gateways[:]
|
gateways = self._gateways[:]
|
||||||
res = __call__.execute(firstresult=True)
|
res = __call__.execute(firstresult=True)
|
||||||
|
|
|
@ -22,8 +22,8 @@ def pytest_funcarg__capfd(request):
|
||||||
request.addfinalizer(capture.finalize)
|
request.addfinalizer(capture.finalize)
|
||||||
return capture
|
return capture
|
||||||
|
|
||||||
def pytest_pyfunc_call(pyfuncitem, args, kwargs):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
for funcarg, value in kwargs.items():
|
for funcarg, value in pyfuncitem.funcargs.items():
|
||||||
if funcarg == "capsys" or funcarg == "capfd":
|
if funcarg == "capsys" or funcarg == "capfd":
|
||||||
value.reset()
|
value.reset()
|
||||||
|
|
||||||
|
|
|
@ -271,7 +271,7 @@ class LinkCheckerMaker(py.test.collect.Collector):
|
||||||
if tryfn.startswith('http:') or tryfn.startswith('https'):
|
if tryfn.startswith('http:') or tryfn.startswith('https'):
|
||||||
if self.config.getvalue("urlcheck"):
|
if self.config.getvalue("urlcheck"):
|
||||||
yield CheckLink(name, parent=self,
|
yield CheckLink(name, parent=self,
|
||||||
args=(tryfn, path, lineno, timeout), callobj=urlcheck)
|
args=(tryfn, path, lineno, timeout), checkfunc=urlcheck)
|
||||||
elif tryfn.startswith('webcal:'):
|
elif tryfn.startswith('webcal:'):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -282,16 +282,19 @@ class LinkCheckerMaker(py.test.collect.Collector):
|
||||||
checkfn = tryfn
|
checkfn = tryfn
|
||||||
if checkfn.strip() and (1 or checkfn.endswith('.html')):
|
if checkfn.strip() and (1 or checkfn.endswith('.html')):
|
||||||
yield CheckLink(name, parent=self,
|
yield CheckLink(name, parent=self,
|
||||||
args=(tryfn, path, lineno), callobj=localrefcheck)
|
args=(tryfn, path, lineno), checkfunc=localrefcheck)
|
||||||
|
|
||||||
class CheckLink(py.test.collect.Function):
|
class CheckLink(py.test.collect.Item):
|
||||||
def reportinfo(self, basedir=None):
|
def __init__(self, name, parent, args, checkfunc):
|
||||||
return (self.fspath, self._args[2], "checklink: %s" % self._args[0])
|
super(CheckLink, self).__init__(name, parent)
|
||||||
|
self.args = args
|
||||||
|
self.checkfunc = checkfunc
|
||||||
|
|
||||||
def setup(self):
|
def runtest(self):
|
||||||
pass
|
return self.checkfunc(*self.args)
|
||||||
def teardown(self):
|
|
||||||
pass
|
def reportinfo(self, basedir=None):
|
||||||
|
return (self.fspath, self.args[2], "checklink: %s" % self.args[0])
|
||||||
|
|
||||||
def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN):
|
def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN):
|
||||||
old = py.std.socket.getdefaulttimeout()
|
old = py.std.socket.getdefaulttimeout()
|
||||||
|
|
|
@ -13,7 +13,7 @@ this code is somewhat derived from Guido Wesdorps
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def pytest_pycollect_obj(collector, name, obj):
|
def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
if py.std.inspect.isclass(obj) and issubclass(obj, py.std.unittest.TestCase):
|
if py.std.inspect.isclass(obj) and issubclass(obj, py.std.unittest.TestCase):
|
||||||
return UnitTestCase(name, parent=collector)
|
return UnitTestCase(name, parent=collector)
|
||||||
|
|
||||||
|
|
|
@ -119,9 +119,9 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector):
|
||||||
return self.join(name)
|
return self.join(name)
|
||||||
|
|
||||||
def makeitem(self, name, obj):
|
def makeitem(self, name, obj):
|
||||||
res = self.config.hook.pytest_pycollect_obj(
|
res = self.config.hook.pytest_pycollect_makeitem(
|
||||||
collector=self, name=name, obj=obj)
|
collector=self, name=name, obj=obj)
|
||||||
if res:
|
if res is not None:
|
||||||
return res
|
return res
|
||||||
if (self.classnamefilter(name)) and \
|
if (self.classnamefilter(name)) and \
|
||||||
py.std.inspect.isclass(obj):
|
py.std.inspect.isclass(obj):
|
||||||
|
@ -314,11 +314,11 @@ class Function(FunctionMixin, py.test.collect.Item):
|
||||||
and executing a Python callable test object.
|
and executing a Python callable test object.
|
||||||
"""
|
"""
|
||||||
_genid = None
|
_genid = None
|
||||||
def __init__(self, name, parent=None, args=(),
|
def __init__(self, name, parent=None, args=None,
|
||||||
callspec=None, callobj=_dummy):
|
callspec=None, callobj=_dummy):
|
||||||
super(Function, self).__init__(name, parent)
|
super(Function, self).__init__(name, parent)
|
||||||
self._args = args
|
self._args = args
|
||||||
if args:
|
if self._isyieldedfunction():
|
||||||
assert not callspec, "yielded functions (deprecated) cannot have funcargs"
|
assert not callspec, "yielded functions (deprecated) cannot have funcargs"
|
||||||
else:
|
else:
|
||||||
if callspec is not None:
|
if callspec is not None:
|
||||||
|
@ -331,6 +331,9 @@ class Function(FunctionMixin, py.test.collect.Item):
|
||||||
if callobj is not _dummy:
|
if callobj is not _dummy:
|
||||||
self._obj = callobj
|
self._obj = callobj
|
||||||
|
|
||||||
|
def _isyieldedfunction(self):
|
||||||
|
return self._args is not None
|
||||||
|
|
||||||
def readkeywords(self):
|
def readkeywords(self):
|
||||||
d = super(Function, self).readkeywords()
|
d = super(Function, self).readkeywords()
|
||||||
d.update(self.obj.func_dict)
|
d.update(self.obj.func_dict)
|
||||||
|
@ -338,9 +341,7 @@ class Function(FunctionMixin, py.test.collect.Item):
|
||||||
|
|
||||||
def runtest(self):
|
def runtest(self):
|
||||||
""" execute the underlying test function. """
|
""" execute the underlying test function. """
|
||||||
kwargs = getattr(self, 'funcargs', {})
|
self.config.hook.pytest_pyfunc_call(pyfuncitem=self)
|
||||||
self.config.hook.pytest_pyfunc_call(
|
|
||||||
pyfuncitem=self, args=self._args, kwargs=kwargs)
|
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
super(Function, self).setup()
|
super(Function, self).setup()
|
||||||
|
|
|
@ -264,10 +264,10 @@ class TestFunction:
|
||||||
item = testdir.getitem("def test_func(): raise ValueError")
|
item = testdir.getitem("def test_func(): raise ValueError")
|
||||||
config = item.config
|
config = item.config
|
||||||
class MyPlugin1:
|
class MyPlugin1:
|
||||||
def pytest_pyfunc_call(self, pyfuncitem, *args, **kwargs):
|
def pytest_pyfunc_call(self, pyfuncitem):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
class MyPlugin2:
|
class MyPlugin2:
|
||||||
def pytest_pyfunc_call(self, pyfuncitem, *args, **kwargs):
|
def pytest_pyfunc_call(self, pyfuncitem):
|
||||||
return True
|
return True
|
||||||
config.pluginmanager.register(MyPlugin1())
|
config.pluginmanager.register(MyPlugin1())
|
||||||
config.pluginmanager.register(MyPlugin2())
|
config.pluginmanager.register(MyPlugin2())
|
||||||
|
|
Loading…
Reference in New Issue