diff --git a/_pytest/core.py b/_pytest/core.py index 015999e08..9a644a42e 100644 --- a/_pytest/core.py +++ b/_pytest/core.py @@ -447,7 +447,7 @@ class HookRelay: self.trace = pm.trace.root.get("hook") -class HookCaller: +class HookCaller(object): def __init__(self, name, plugins, argnames=None, firstresult=None, historic=False): self.name = name @@ -462,6 +462,17 @@ class HookCaller: if self.historic: self._call_history = [] + def clone(self): + hc = object.__new__(HookCaller) + hc.name = self.name + hc.plugins = self.plugins + hc.historic = self.historic + hc.argnames = self.argnames + hc.firstresult = self.firstresult + hc.wrappers = list(self.wrappers) + hc.nonwrappers = list(self.nonwrappers) + return hc + @property def pre(self): return self.argnames is None @@ -511,8 +522,10 @@ class HookCaller: def callextra(self, methods, **kwargs): assert not self.historic - return self._docall(self.nonwrappers + methods + self.wrappers, - kwargs) + hc = self.clone() + for method in methods: + hc.add_method(method) + return hc(**kwargs) def _docall(self, methods, kwargs): return MultiCall(methods, kwargs, firstresult=self.firstresult).execute() @@ -521,10 +534,11 @@ class HookCaller: self._call_history.append((kwargs, proc)) self._docall(self.nonwrappers + self.wrappers, kwargs) - def _apply_history(self, meth): + def _apply_history(self, method): if hasattr(self, "_call_history"): for kwargs, proc in self._call_history: - res = MultiCall([meth], kwargs, firstresult=True).execute() + args = [kwargs[argname] for argname in varnames(method)] + res = method(*args) if proc is not None: proc(res) diff --git a/_pytest/python.py b/_pytest/python.py index 74ba77068..bc64d6fa3 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -375,13 +375,15 @@ class PyCollector(PyobjMixin, pytest.Collector): fixtureinfo = fm.getfixtureinfo(self, funcobj, cls) metafunc = Metafunc(funcobj, fixtureinfo, self.config, cls=cls, module=module) - try: - methods = [module.pytest_generate_tests] - except AttributeError: - methods = [] + methods = [] + if hasattr(module, "pytest_generate_tests"): + methods.append(module.pytest_generate_tests) if hasattr(cls, "pytest_generate_tests"): methods.append(cls().pytest_generate_tests) - self.ihook.pytest_generate_tests.callextra(methods, metafunc=metafunc) + if methods: + self.ihook.pytest_generate_tests.callextra(methods, metafunc=metafunc) + else: + self.ihook.pytest_generate_tests(metafunc=metafunc) Function = self._getcustomclass("Function") if not metafunc._calls: diff --git a/testing/test_core.py b/testing/test_core.py index 2368be6d7..304cff0cd 100644 --- a/testing/test_core.py +++ b/testing/test_core.py @@ -129,7 +129,18 @@ class TestPluginManager: return arg * 10 pm.register(Plugin()) + assert l == [10] + def test_call_extra(self, pm): + class Hooks: + def he_method1(self, arg): + pass + pm.addhooks(Hooks) + + def he_method1(arg): + return arg * 10 + + l = pm.hook.he_method1.callextra([he_method1], arg=1) assert l == [10]