parent
2f8a1aed6e
commit
e7a2e53108
146
_pytest/core.py
146
_pytest/core.py
|
@ -233,14 +233,7 @@ class PluginManager(object):
|
||||||
|
|
||||||
def make_hook_caller(self, name, plugins):
|
def make_hook_caller(self, name, plugins):
|
||||||
caller = getattr(self.hook, name)
|
caller = getattr(self.hook, name)
|
||||||
assert not caller.historic
|
return caller.clone(plugins=plugins)
|
||||||
hc = HookCaller(caller.name, plugins, firstresult=caller.firstresult,
|
|
||||||
argnames=caller.argnames)
|
|
||||||
for plugin in hc.plugins:
|
|
||||||
meth = getattr(plugin, name, None)
|
|
||||||
if meth is not None:
|
|
||||||
hc.add_method(meth)
|
|
||||||
return hc
|
|
||||||
|
|
||||||
def register(self, plugin, name=None):
|
def register(self, plugin, name=None):
|
||||||
""" Register a plugin with the given name and ensure that all its
|
""" Register a plugin with the given name and ensure that all its
|
||||||
|
@ -278,23 +271,15 @@ class PluginManager(object):
|
||||||
names = []
|
names = []
|
||||||
for name in dir(module_or_class):
|
for name in dir(module_or_class):
|
||||||
if name.startswith(self._prefix):
|
if name.startswith(self._prefix):
|
||||||
specfunc = module_or_class.__dict__[name]
|
|
||||||
firstresult = getattr(specfunc, 'firstresult', False)
|
|
||||||
historic = getattr(specfunc, 'historic', False)
|
|
||||||
hc = getattr(self.hook, name, None)
|
hc = getattr(self.hook, name, None)
|
||||||
argnames = varnames(specfunc, startindex=isclass)
|
|
||||||
if hc is None:
|
if hc is None:
|
||||||
hc = HookCaller(name, [], firstresult=firstresult,
|
hc = HookCaller(name, module_or_class)
|
||||||
historic=historic,
|
|
||||||
argnames=argnames)
|
|
||||||
setattr(self.hook, name, hc)
|
setattr(self.hook, name, hc)
|
||||||
else:
|
else:
|
||||||
# plugins registered this hook without knowing the spec
|
# plugins registered this hook without knowing the spec
|
||||||
hc.setspec(firstresult=firstresult, argnames=argnames,
|
hc.setspec(module_or_class)
|
||||||
historic=historic)
|
for plugin in hc._plugins:
|
||||||
for plugin in hc.plugins:
|
self._verify_hook(hc, plugin)
|
||||||
self._verify_hook(hc, specfunc, plugin)
|
|
||||||
hc.add_method(getattr(plugin, name))
|
|
||||||
names.append(name)
|
names.append(name)
|
||||||
if not names:
|
if not names:
|
||||||
raise ValueError("did not find new %r hooks in %r"
|
raise ValueError("did not find new %r hooks in %r"
|
||||||
|
@ -330,21 +315,17 @@ class PluginManager(object):
|
||||||
if hook is None:
|
if hook is None:
|
||||||
if self._excludefunc is not None and self._excludefunc(name):
|
if self._excludefunc is not None and self._excludefunc(name):
|
||||||
continue
|
continue
|
||||||
hook = HookCaller(name, [plugin])
|
hook = HookCaller(name)
|
||||||
setattr(self.hook, name, hook)
|
setattr(self.hook, name, hook)
|
||||||
elif hook.pre:
|
elif hook.has_spec():
|
||||||
# there is only a pre non-specced stub
|
self._verify_hook(hook, plugin)
|
||||||
hook.plugins.append(plugin)
|
|
||||||
else:
|
|
||||||
# we have a hook spec, can verify early
|
|
||||||
self._verify_hook(hook, method, plugin)
|
|
||||||
hook.plugins.append(plugin)
|
|
||||||
hook.add_method(method)
|
|
||||||
hook._apply_history(method)
|
hook._apply_history(method)
|
||||||
|
hook.add_plugin(plugin)
|
||||||
hookcallers.append(hook)
|
hookcallers.append(hook)
|
||||||
return hookcallers
|
return hookcallers
|
||||||
|
|
||||||
def _verify_hook(self, hook, method, plugin):
|
def _verify_hook(self, hook, plugin):
|
||||||
|
method = getattr(plugin, hook.name)
|
||||||
for arg in varnames(method):
|
for arg in varnames(method):
|
||||||
if arg not in hook.argnames:
|
if arg not in hook.argnames:
|
||||||
pluginname = self._get_canonical_name(plugin)
|
pluginname = self._get_canonical_name(plugin)
|
||||||
|
@ -359,8 +340,8 @@ class PluginManager(object):
|
||||||
for name in self.hook.__dict__:
|
for name in self.hook.__dict__:
|
||||||
if name.startswith(self._prefix):
|
if name.startswith(self._prefix):
|
||||||
hook = getattr(self.hook, name)
|
hook = getattr(self.hook, name)
|
||||||
if hook.pre:
|
if not hook.has_spec():
|
||||||
for plugin in hook.plugins:
|
for plugin in hook._plugins:
|
||||||
method = getattr(plugin, hook.name)
|
method = getattr(plugin, hook.name)
|
||||||
if not getattr(method, "optionalhook", False):
|
if not getattr(method, "optionalhook", False):
|
||||||
raise PluginValidationError(
|
raise PluginValidationError(
|
||||||
|
@ -448,80 +429,91 @@ class HookRelay:
|
||||||
|
|
||||||
|
|
||||||
class HookCaller(object):
|
class HookCaller(object):
|
||||||
def __init__(self, name, plugins, argnames=None, firstresult=None,
|
def __init__(self, name, specmodule_or_class=None):
|
||||||
historic=False):
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.plugins = plugins
|
self._plugins = []
|
||||||
if argnames is not None:
|
self._wrappers = []
|
||||||
argnames = ["__multicall__"] + list(argnames)
|
self._nonwrappers = []
|
||||||
self.historic = historic
|
if specmodule_or_class is not None:
|
||||||
self.argnames = argnames
|
self.setspec(specmodule_or_class)
|
||||||
self.firstresult = firstresult
|
|
||||||
self.wrappers = []
|
|
||||||
self.nonwrappers = []
|
|
||||||
if self.historic:
|
|
||||||
self._call_history = []
|
|
||||||
|
|
||||||
def clone(self):
|
def has_spec(self):
|
||||||
|
return hasattr(self, "_specmodule_or_class")
|
||||||
|
|
||||||
|
def clone(self, plugins=None):
|
||||||
|
assert not self.is_historic()
|
||||||
hc = object.__new__(HookCaller)
|
hc = object.__new__(HookCaller)
|
||||||
hc.name = self.name
|
hc.name = self.name
|
||||||
hc.plugins = self.plugins
|
|
||||||
hc.historic = self.historic
|
|
||||||
hc.argnames = self.argnames
|
hc.argnames = self.argnames
|
||||||
hc.firstresult = self.firstresult
|
hc.firstresult = self.firstresult
|
||||||
hc.wrappers = list(self.wrappers)
|
if plugins is None:
|
||||||
hc.nonwrappers = list(self.nonwrappers)
|
hc._plugins = self._plugins
|
||||||
|
hc._wrappers = list(self._wrappers)
|
||||||
|
hc._nonwrappers = list(self._nonwrappers)
|
||||||
|
else:
|
||||||
|
hc._plugins, hc._wrappers, hc._nonwrappers = [], [], []
|
||||||
|
for plugin in plugins:
|
||||||
|
if hasattr(plugin, hc.name):
|
||||||
|
hc.add_plugin(plugin)
|
||||||
return hc
|
return hc
|
||||||
|
|
||||||
@property
|
def setspec(self, specmodule_or_class):
|
||||||
def pre(self):
|
assert not self.has_spec()
|
||||||
return self.argnames is None
|
self._specmodule_or_class = specmodule_or_class
|
||||||
|
specfunc = getattr(specmodule_or_class, self.name)
|
||||||
|
self.argnames = ["__multicall__"] + list(varnames(
|
||||||
|
specfunc, startindex=inspect.isclass(specmodule_or_class)
|
||||||
|
))
|
||||||
|
assert "self" not in self.argnames # sanity check
|
||||||
|
self.firstresult = getattr(specfunc, 'firstresult', False)
|
||||||
|
if hasattr(specfunc, "historic"):
|
||||||
|
self._call_history = []
|
||||||
|
|
||||||
def setspec(self, argnames, firstresult, historic):
|
def is_historic(self):
|
||||||
assert self.pre
|
return hasattr(self, "_call_history")
|
||||||
assert "self" not in argnames # sanity check
|
|
||||||
self.argnames = ["__multicall__"] + list(argnames)
|
|
||||||
self.firstresult = firstresult
|
|
||||||
self.historic = historic
|
|
||||||
|
|
||||||
def remove_plugin(self, plugin):
|
def remove_plugin(self, plugin):
|
||||||
self.plugins.remove(plugin)
|
self._plugins.remove(plugin)
|
||||||
meth = getattr(plugin, self.name)
|
meth = getattr(plugin, self.name)
|
||||||
try:
|
try:
|
||||||
self.nonwrappers.remove(meth)
|
self._nonwrappers.remove(meth)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.wrappers.remove(meth)
|
self._wrappers.remove(meth)
|
||||||
|
|
||||||
|
def add_plugin(self, plugin):
|
||||||
|
self._plugins.append(plugin)
|
||||||
|
self.add_method(getattr(plugin, self.name))
|
||||||
|
|
||||||
def add_method(self, meth):
|
def add_method(self, meth):
|
||||||
assert not self.pre
|
|
||||||
if hasattr(meth, 'hookwrapper'):
|
if hasattr(meth, 'hookwrapper'):
|
||||||
assert not self.historic
|
assert not self.is_historic()
|
||||||
self.wrappers.append(meth)
|
self._wrappers.append(meth)
|
||||||
elif hasattr(meth, 'trylast'):
|
elif hasattr(meth, 'trylast'):
|
||||||
self.nonwrappers.insert(0, meth)
|
self._nonwrappers.insert(0, meth)
|
||||||
elif hasattr(meth, 'tryfirst'):
|
elif hasattr(meth, 'tryfirst'):
|
||||||
self.nonwrappers.append(meth)
|
self._nonwrappers.append(meth)
|
||||||
else:
|
else:
|
||||||
if not self.nonwrappers or not hasattr(self.nonwrappers[-1], "tryfirst"):
|
nonwrappers = self._nonwrappers
|
||||||
self.nonwrappers.append(meth)
|
if not nonwrappers or not hasattr(nonwrappers[-1], "tryfirst"):
|
||||||
|
nonwrappers.append(meth)
|
||||||
else:
|
else:
|
||||||
for i in reversed(range(len(self.nonwrappers)-1)):
|
for i in reversed(range(len(nonwrappers)-1)):
|
||||||
if hasattr(self.nonwrappers[i], "tryfirst"):
|
if hasattr(nonwrappers[i], "tryfirst"):
|
||||||
continue
|
continue
|
||||||
self.nonwrappers.insert(i+1, meth)
|
nonwrappers.insert(i+1, meth)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.nonwrappers.insert(0, meth)
|
nonwrappers.insert(0, meth)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<HookCaller %r>" %(self.name,)
|
return "<HookCaller %r>" %(self.name,)
|
||||||
|
|
||||||
def __call__(self, **kwargs):
|
def __call__(self, **kwargs):
|
||||||
assert not self.historic
|
assert not self.is_historic()
|
||||||
return self._docall(self.nonwrappers + self.wrappers, kwargs)
|
return self._docall(self._nonwrappers + self._wrappers, kwargs)
|
||||||
|
|
||||||
def callextra(self, methods, **kwargs):
|
def callextra(self, methods, **kwargs):
|
||||||
assert not self.historic
|
assert not self.is_historic()
|
||||||
hc = self.clone()
|
hc = self.clone()
|
||||||
for method in methods:
|
for method in methods:
|
||||||
hc.add_method(method)
|
hc.add_method(method)
|
||||||
|
@ -532,10 +524,10 @@ class HookCaller(object):
|
||||||
|
|
||||||
def call_historic(self, kwargs, proc=None):
|
def call_historic(self, kwargs, proc=None):
|
||||||
self._call_history.append((kwargs, proc))
|
self._call_history.append((kwargs, proc))
|
||||||
self._docall(self.nonwrappers + self.wrappers, kwargs)
|
self._docall(self._nonwrappers + self._wrappers, kwargs)
|
||||||
|
|
||||||
def _apply_history(self, method):
|
def _apply_history(self, method):
|
||||||
if hasattr(self, "_call_history"):
|
if self.is_historic():
|
||||||
for kwargs, proc in self._call_history:
|
for kwargs, proc in self._call_history:
|
||||||
args = [kwargs[argname] for argname in varnames(method)]
|
args = [kwargs[argname] for argname in varnames(method)]
|
||||||
res = method(*args)
|
res = method(*args)
|
||||||
|
|
|
@ -356,7 +356,7 @@ def test_load_initial_conftest_last_ordering(testdir):
|
||||||
m = My()
|
m = My()
|
||||||
pm.register(m)
|
pm.register(m)
|
||||||
hc = pm.hook.pytest_load_initial_conftests
|
hc = pm.hook.pytest_load_initial_conftests
|
||||||
l = hc.nonwrappers + hc.wrappers
|
l = hc._nonwrappers + hc._wrappers
|
||||||
assert l[-1].__module__ == "_pytest.capture"
|
assert l[-1].__module__ == "_pytest.capture"
|
||||||
assert l[-2] == m.pytest_load_initial_conftests
|
assert l[-2] == m.pytest_load_initial_conftests
|
||||||
assert l[-3].__module__ == "_pytest.config"
|
assert l[-3].__module__ == "_pytest.config"
|
||||||
|
|
|
@ -180,7 +180,7 @@ class TestAddMethodOrdering:
|
||||||
@addmeth()
|
@addmeth()
|
||||||
def he_method3():
|
def he_method3():
|
||||||
pass
|
pass
|
||||||
assert hc.nonwrappers == [he_method1, he_method2, he_method3]
|
assert hc._nonwrappers == [he_method1, he_method2, he_method3]
|
||||||
|
|
||||||
def test_adding_nonwrappers_trylast(self, hc, addmeth):
|
def test_adding_nonwrappers_trylast(self, hc, addmeth):
|
||||||
@addmeth()
|
@addmeth()
|
||||||
|
@ -194,7 +194,7 @@ class TestAddMethodOrdering:
|
||||||
@addmeth()
|
@addmeth()
|
||||||
def he_method1_b():
|
def he_method1_b():
|
||||||
pass
|
pass
|
||||||
assert hc.nonwrappers == [he_method1, he_method1_middle, he_method1_b]
|
assert hc._nonwrappers == [he_method1, he_method1_middle, he_method1_b]
|
||||||
|
|
||||||
def test_adding_nonwrappers_trylast2(self, hc, addmeth):
|
def test_adding_nonwrappers_trylast2(self, hc, addmeth):
|
||||||
@addmeth()
|
@addmeth()
|
||||||
|
@ -208,7 +208,7 @@ class TestAddMethodOrdering:
|
||||||
@addmeth(trylast=True)
|
@addmeth(trylast=True)
|
||||||
def he_method1():
|
def he_method1():
|
||||||
pass
|
pass
|
||||||
assert hc.nonwrappers == [he_method1, he_method1_middle, he_method1_b]
|
assert hc._nonwrappers == [he_method1, he_method1_middle, he_method1_b]
|
||||||
|
|
||||||
def test_adding_nonwrappers_tryfirst(self, hc, addmeth):
|
def test_adding_nonwrappers_tryfirst(self, hc, addmeth):
|
||||||
@addmeth(tryfirst=True)
|
@addmeth(tryfirst=True)
|
||||||
|
@ -222,7 +222,7 @@ class TestAddMethodOrdering:
|
||||||
@addmeth()
|
@addmeth()
|
||||||
def he_method1_b():
|
def he_method1_b():
|
||||||
pass
|
pass
|
||||||
assert hc.nonwrappers == [he_method1_middle, he_method1_b, he_method1]
|
assert hc._nonwrappers == [he_method1_middle, he_method1_b, he_method1]
|
||||||
|
|
||||||
def test_adding_nonwrappers_trylast(self, hc, addmeth):
|
def test_adding_nonwrappers_trylast(self, hc, addmeth):
|
||||||
@addmeth()
|
@addmeth()
|
||||||
|
@ -240,7 +240,7 @@ class TestAddMethodOrdering:
|
||||||
@addmeth(trylast=True)
|
@addmeth(trylast=True)
|
||||||
def he_method1_d():
|
def he_method1_d():
|
||||||
pass
|
pass
|
||||||
assert hc.nonwrappers == [he_method1_d, he_method1_b, he_method1_a, he_method1_c]
|
assert hc._nonwrappers == [he_method1_d, he_method1_b, he_method1_a, he_method1_c]
|
||||||
|
|
||||||
def test_adding_wrappers_ordering(self, hc, addmeth):
|
def test_adding_wrappers_ordering(self, hc, addmeth):
|
||||||
@addmeth(hookwrapper=True)
|
@addmeth(hookwrapper=True)
|
||||||
|
@ -255,8 +255,8 @@ class TestAddMethodOrdering:
|
||||||
def he_method3():
|
def he_method3():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert hc.nonwrappers == [he_method1_middle]
|
assert hc._nonwrappers == [he_method1_middle]
|
||||||
assert hc.wrappers == [he_method1, he_method3]
|
assert hc._wrappers == [he_method1, he_method3]
|
||||||
|
|
||||||
def test_hookspec_opts(self, pm):
|
def test_hookspec_opts(self, pm):
|
||||||
class HookSpec:
|
class HookSpec:
|
||||||
|
|
Loading…
Reference in New Issue