* 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):
|
||||
gr_twisted.switch(None)
|
||||
|
||||
def pytest_pyfunc_call(pyfuncitem, *args, **kwargs):
|
||||
args = args or pyfuncitem._args # generator tests
|
||||
def pytest_pyfunc_call(pyfuncitem):
|
||||
# XXX1 kwargs?
|
||||
# XXX2 we want to delegate actual call to next plugin
|
||||
# (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:
|
||||
res.raiseException()
|
||||
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
|
||||
|
||||
"runtest" hooks
|
||||
-------------------
|
||||
generic "runtest" 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
|
||||
|
||||
|
||||
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
|
||||
=============================
|
||||
|
||||
|
@ -114,6 +134,8 @@ Additionally you can check out some more contributed plugins here
|
|||
|
||||
|
||||
.. _`collection process`:
|
||||
.. _`collection node`:
|
||||
|
||||
|
||||
Test Collection process
|
||||
======================================================
|
||||
|
|
|
@ -425,11 +425,11 @@ class Item(Node):
|
|||
|
||||
def run(self):
|
||||
""" 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. """
|
||||
return obj(*args)
|
||||
return obj()
|
||||
|
||||
def reportinfo(self):
|
||||
return self.fspath, None, ""
|
||||
|
|
|
@ -34,9 +34,7 @@ def pytest_deselected(items):
|
|||
# ------------------------------------------------------------------------------
|
||||
# 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):
|
||||
""" return Collection node or None. """
|
||||
|
@ -50,25 +48,37 @@ pytest_collect_recurse.firstresult = True
|
|||
def pytest_collect_directory(path, parent):
|
||||
""" 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):
|
||||
""" collector starts collecting. """
|
||||
|
||||
def pytest_collectreport(rep):
|
||||
""" 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?
|
||||
def pytest_itemstart(item, node=None):
|
||||
""" 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):
|
||||
""" called before pytest_runtest_call(). """
|
||||
|
@ -83,10 +93,6 @@ def pytest_runtest_protocol(item):
|
|||
""" run given test item and return test report. """
|
||||
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):
|
||||
""" make ItemTestReport for the specified test outcome. """
|
||||
pytest_runtest_makereport.firstresult = True
|
||||
|
@ -95,7 +101,7 @@ def pytest_runtest_logreport(rep):
|
|||
""" process item test report. """
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# reporting hooks (invoked from pytest_terminal.py)
|
||||
# generic reporting hooks (invoked from pytest_terminal.py)
|
||||
# ------------------------------------------------------------------------------
|
||||
def pytest_report_teststatus(rep):
|
||||
""" return shortletter and verbose word. """
|
||||
|
@ -117,6 +123,7 @@ def pytest_doctest_prepare_content(content):
|
|||
""" return processed content for a given doctest"""
|
||||
pytest_doctest_prepare_content.firstresult = True
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# misc hooks
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -133,8 +140,6 @@ def pytest_internalerror(excrepr):
|
|||
def pytest_trace(category, msg):
|
||||
""" called for debug info. """
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# distributed testing
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
|
||||
import py
|
||||
|
||||
def pytest_pyfunc_call(__call__, pyfuncitem, args, kwargs):
|
||||
def pytest_pyfunc_call(__call__, pyfuncitem):
|
||||
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):
|
||||
ext = path.ext
|
||||
|
|
|
@ -29,8 +29,8 @@ class Execnetcleanup:
|
|||
l.append(gw)
|
||||
#for gw in l:
|
||||
# gw.join()
|
||||
#
|
||||
def pytest_pyfunc_call(self, __call__, pyfuncitem, args, kwargs):
|
||||
|
||||
def pytest_pyfunc_call(self, __call__, pyfuncitem):
|
||||
if self._gateways is not None:
|
||||
gateways = self._gateways[:]
|
||||
res = __call__.execute(firstresult=True)
|
||||
|
|
|
@ -22,8 +22,8 @@ def pytest_funcarg__capfd(request):
|
|||
request.addfinalizer(capture.finalize)
|
||||
return capture
|
||||
|
||||
def pytest_pyfunc_call(pyfuncitem, args, kwargs):
|
||||
for funcarg, value in kwargs.items():
|
||||
def pytest_pyfunc_call(pyfuncitem):
|
||||
for funcarg, value in pyfuncitem.funcargs.items():
|
||||
if funcarg == "capsys" or funcarg == "capfd":
|
||||
value.reset()
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ class LinkCheckerMaker(py.test.collect.Collector):
|
|||
if tryfn.startswith('http:') or tryfn.startswith('https'):
|
||||
if self.config.getvalue("urlcheck"):
|
||||
yield CheckLink(name, parent=self,
|
||||
args=(tryfn, path, lineno, timeout), callobj=urlcheck)
|
||||
args=(tryfn, path, lineno, timeout), checkfunc=urlcheck)
|
||||
elif tryfn.startswith('webcal:'):
|
||||
continue
|
||||
else:
|
||||
|
@ -282,16 +282,19 @@ class LinkCheckerMaker(py.test.collect.Collector):
|
|||
checkfn = tryfn
|
||||
if checkfn.strip() and (1 or checkfn.endswith('.html')):
|
||||
yield CheckLink(name, parent=self,
|
||||
args=(tryfn, path, lineno), callobj=localrefcheck)
|
||||
args=(tryfn, path, lineno), checkfunc=localrefcheck)
|
||||
|
||||
class CheckLink(py.test.collect.Function):
|
||||
def reportinfo(self, basedir=None):
|
||||
return (self.fspath, self._args[2], "checklink: %s" % self._args[0])
|
||||
class CheckLink(py.test.collect.Item):
|
||||
def __init__(self, name, parent, args, checkfunc):
|
||||
super(CheckLink, self).__init__(name, parent)
|
||||
self.args = args
|
||||
self.checkfunc = checkfunc
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
def teardown(self):
|
||||
pass
|
||||
def runtest(self):
|
||||
return self.checkfunc(*self.args)
|
||||
|
||||
def reportinfo(self, basedir=None):
|
||||
return (self.fspath, self.args[2], "checklink: %s" % self.args[0])
|
||||
|
||||
def urlcheck(tryfn, path, lineno, TIMEOUT_URLOPEN):
|
||||
old = py.std.socket.getdefaulttimeout()
|
||||
|
|
|
@ -13,7 +13,7 @@ this code is somewhat derived from Guido Wesdorps
|
|||
"""
|
||||
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):
|
||||
return UnitTestCase(name, parent=collector)
|
||||
|
||||
|
|
|
@ -119,9 +119,9 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector):
|
|||
return self.join(name)
|
||||
|
||||
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)
|
||||
if res:
|
||||
if res is not None:
|
||||
return res
|
||||
if (self.classnamefilter(name)) and \
|
||||
py.std.inspect.isclass(obj):
|
||||
|
@ -314,11 +314,11 @@ class Function(FunctionMixin, py.test.collect.Item):
|
|||
and executing a Python callable test object.
|
||||
"""
|
||||
_genid = None
|
||||
def __init__(self, name, parent=None, args=(),
|
||||
def __init__(self, name, parent=None, args=None,
|
||||
callspec=None, callobj=_dummy):
|
||||
super(Function, self).__init__(name, parent)
|
||||
self._args = args
|
||||
if args:
|
||||
if self._isyieldedfunction():
|
||||
assert not callspec, "yielded functions (deprecated) cannot have funcargs"
|
||||
else:
|
||||
if callspec is not None:
|
||||
|
@ -331,6 +331,9 @@ class Function(FunctionMixin, py.test.collect.Item):
|
|||
if callobj is not _dummy:
|
||||
self._obj = callobj
|
||||
|
||||
def _isyieldedfunction(self):
|
||||
return self._args is not None
|
||||
|
||||
def readkeywords(self):
|
||||
d = super(Function, self).readkeywords()
|
||||
d.update(self.obj.func_dict)
|
||||
|
@ -338,9 +341,7 @@ class Function(FunctionMixin, py.test.collect.Item):
|
|||
|
||||
def runtest(self):
|
||||
""" execute the underlying test function. """
|
||||
kwargs = getattr(self, 'funcargs', {})
|
||||
self.config.hook.pytest_pyfunc_call(
|
||||
pyfuncitem=self, args=self._args, kwargs=kwargs)
|
||||
self.config.hook.pytest_pyfunc_call(pyfuncitem=self)
|
||||
|
||||
def setup(self):
|
||||
super(Function, self).setup()
|
||||
|
|
|
@ -264,10 +264,10 @@ class TestFunction:
|
|||
item = testdir.getitem("def test_func(): raise ValueError")
|
||||
config = item.config
|
||||
class MyPlugin1:
|
||||
def pytest_pyfunc_call(self, pyfuncitem, *args, **kwargs):
|
||||
def pytest_pyfunc_call(self, pyfuncitem):
|
||||
raise ValueError
|
||||
class MyPlugin2:
|
||||
def pytest_pyfunc_call(self, pyfuncitem, *args, **kwargs):
|
||||
def pytest_pyfunc_call(self, pyfuncitem):
|
||||
return True
|
||||
config.pluginmanager.register(MyPlugin1())
|
||||
config.pluginmanager.register(MyPlugin2())
|
||||
|
|
Loading…
Reference in New Issue