deprecate and warn about __multicall__ usage in hooks, refine docs about hook ordering,
make hookwrappers respect tryfirst/trylast --HG-- branch : more_plugin
This commit is contained in:
@@ -9,7 +9,7 @@ import py
|
||||
# DON't import pytest here because it causes import cycle troubles
|
||||
import sys, os
|
||||
from _pytest import hookspec # the extension point definitions
|
||||
from _pytest.core import PluginManager, hookimpl_opts
|
||||
from _pytest.core import PluginManager, hookimpl_opts, varnames
|
||||
|
||||
# pytest startup
|
||||
#
|
||||
@@ -117,6 +117,18 @@ class PytestPluginManager(PluginManager):
|
||||
self.trace.root.setwriter(err.write)
|
||||
self.enable_tracing()
|
||||
|
||||
|
||||
def _verify_hook(self, hook, plugin):
|
||||
super(PytestPluginManager, self)._verify_hook(hook, plugin)
|
||||
method = getattr(plugin, hook.name)
|
||||
if "__multicall__" in varnames(method):
|
||||
fslineno = py.code.getfslineno(method)
|
||||
warning = dict(code="I1",
|
||||
fslocation=fslineno,
|
||||
message="%r hook uses deprecated __multicall__ "
|
||||
"argument" % (hook.name))
|
||||
self._warnings.append(warning)
|
||||
|
||||
def register(self, plugin, name=None):
|
||||
ret = super(PytestPluginManager, self).register(plugin, name)
|
||||
if ret:
|
||||
@@ -138,7 +150,10 @@ class PytestPluginManager(PluginManager):
|
||||
"trylast: mark a hook implementation function such that the "
|
||||
"plugin machinery will try to call it last/as late as possible.")
|
||||
for warning in self._warnings:
|
||||
config.warn(code="I1", message=warning)
|
||||
if isinstance(warning, dict):
|
||||
config.warn(**warning)
|
||||
else:
|
||||
config.warn(code="I1", message=warning)
|
||||
|
||||
#
|
||||
# internal API for local conftest plugin handling
|
||||
@@ -712,10 +727,10 @@ class Config(object):
|
||||
fin = self._cleanup.pop()
|
||||
fin()
|
||||
|
||||
def warn(self, code, message):
|
||||
def warn(self, code, message, fslocation=None):
|
||||
""" generate a warning for this test session. """
|
||||
self.hook.pytest_logwarning(code=code, message=message,
|
||||
fslocation=None, nodeid=None)
|
||||
fslocation=fslocation, nodeid=None)
|
||||
|
||||
def get_terminal_writer(self):
|
||||
return self.pluginmanager.get_plugin("terminalreporter")._tw
|
||||
|
||||
@@ -408,6 +408,12 @@ class PluginManager(object):
|
||||
class MultiCall:
|
||||
""" execute a call into multiple python functions/methods. """
|
||||
|
||||
# XXX note that the __multicall__ argument is supported only
|
||||
# for pytest compatibility reasons. It was never officially
|
||||
# supported there and is explicitely deprecated since 2.8
|
||||
# so we can remove it soon, allowing to avoid the below recursion
|
||||
# in execute() and simplify/speed up the execute loop.
|
||||
|
||||
def __init__(self, methods, kwargs, firstresult=False):
|
||||
self.methods = methods
|
||||
self.kwargs = kwargs
|
||||
@@ -527,20 +533,20 @@ class HookCaller(object):
|
||||
|
||||
def _add_method(self, meth):
|
||||
if hasattr(meth, 'hookwrapper'):
|
||||
self._wrappers.append(meth)
|
||||
elif hasattr(meth, 'trylast'):
|
||||
self._nonwrappers.insert(0, meth)
|
||||
elif hasattr(meth, 'tryfirst'):
|
||||
self._nonwrappers.append(meth)
|
||||
methods = self._wrappers
|
||||
else:
|
||||
# find the last nonwrapper which is not tryfirst marked
|
||||
nonwrappers = self._nonwrappers
|
||||
i = len(nonwrappers) - 1
|
||||
while i >= 0 and hasattr(nonwrappers[i], "tryfirst"):
|
||||
i -= 1
|
||||
methods = self._nonwrappers
|
||||
|
||||
# and insert right in front of the tryfirst ones
|
||||
nonwrappers.insert(i+1, meth)
|
||||
if hasattr(meth, 'trylast'):
|
||||
methods.insert(0, meth)
|
||||
elif hasattr(meth, 'tryfirst'):
|
||||
methods.append(meth)
|
||||
else:
|
||||
# find last non-tryfirst method
|
||||
i = len(methods) - 1
|
||||
while i >= 0 and hasattr(methods[i], "tryfirst"):
|
||||
i -= 1
|
||||
methods.insert(i + 1, meth)
|
||||
|
||||
def __repr__(self):
|
||||
return "<HookCaller %r>" %(self.name,)
|
||||
|
||||
@@ -164,6 +164,8 @@ class TerminalReporter:
|
||||
|
||||
def pytest_logwarning(self, code, fslocation, message, nodeid):
|
||||
warnings = self.stats.setdefault("warnings", [])
|
||||
if isinstance(fslocation, tuple):
|
||||
fslocation = "%s:%d" % fslocation
|
||||
warning = WarningReport(code=code, fslocation=fslocation,
|
||||
message=message, nodeid=nodeid)
|
||||
warnings.append(warning)
|
||||
|
||||
Reference in New Issue
Block a user