make pytest_plugin_registered a historic hook

--HG--
branch : more_plugin
This commit is contained in:
holger krekel 2015-04-25 13:38:30 +02:00
parent e7a2e53108
commit 4e116ed503
5 changed files with 39 additions and 49 deletions

View File

@ -122,8 +122,8 @@ class PytestPluginManager(PluginManager):
if ret:
if not conftest:
self._globalplugins.append(plugin)
self.hook.pytest_plugin_registered(plugin=plugin,
manager=self)
self.hook.pytest_plugin_registered.call_historic(
kwargs=dict(plugin=plugin, manager=self))
return ret
def unregister(self, plugin):
@ -707,8 +707,8 @@ class Config(object):
def do_setns(dic):
import pytest
setns(pytest, dic)
self.hook.pytest_namespace.call_historic({}, proc=do_setns)
self.hook.pytest_addoption.call_historic(dict(parser=self._parser))
self.hook.pytest_namespace.call_historic(do_setns, {})
self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))
def add_cleanup(self, func):
""" Add a function to be called when the config object gets out of
@ -718,7 +718,7 @@ class Config(object):
def _do_configure(self):
assert not self._configured
self._configured = True
self.hook.pytest_configure.call_historic(dict(config=self))
self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
def _ensure_unconfigure(self):
if self._configured:
@ -840,7 +840,8 @@ class Config(object):
assert not hasattr(self, 'args'), (
"can only parse cmdline args at most once per Config object")
self._origargs = args
self.hook.pytest_addhooks.call_historic(dict(pluginmanager=self.pluginmanager))
self.hook.pytest_addhooks.call_historic(
kwargs=dict(pluginmanager=self.pluginmanager))
self._preparse(args)
# XXX deprecated hook:
self.hook.pytest_cmdline_preparse(config=self, args=args)

View File

@ -2,7 +2,7 @@
PluginManager, basic initialization and tracing.
"""
import sys
import inspect
from inspect import isfunction, ismethod, isclass, formatargspec, getargspec
import py
py3 = sys.version_info > (3,0)
@ -267,7 +267,6 @@ class PluginManager(object):
def addhooks(self, module_or_class):
""" add new hook definitions from the given module_or_class using
the prefix/excludefunc with which the PluginManager was initialized. """
isclass = int(inspect.isclass(module_or_class))
names = []
for name in dir(module_or_class):
if name.startswith(self._prefix):
@ -394,17 +393,17 @@ def varnames(func, startindex=None):
return cache["_varnames"]
except KeyError:
pass
if inspect.isclass(func):
if isclass(func):
try:
func = func.__init__
except AttributeError:
return ()
startindex = 1
else:
if not inspect.isfunction(func) and not inspect.ismethod(func):
if not isfunction(func) and not ismethod(func):
func = getattr(func, '__call__', func)
if startindex is None:
startindex = int(inspect.ismethod(func))
startindex = int(ismethod(func))
rawcode = py.code.getrawcode(func)
try:
@ -461,10 +460,9 @@ class HookCaller(object):
assert not self.has_spec()
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
argnames = varnames(specfunc, startindex=isclass(specmodule_or_class))
assert "self" not in argnames # sanity check
self.argnames = ["__multicall__"] + list(argnames)
self.firstresult = getattr(specfunc, 'firstresult', False)
if hasattr(specfunc, "historic"):
self._call_history = []
@ -512,27 +510,26 @@ class HookCaller(object):
assert not self.is_historic()
return self._docall(self._nonwrappers + self._wrappers, kwargs)
def callextra(self, methods, **kwargs):
def call_extra(self, methods, kwargs):
assert not self.is_historic()
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()
def call_historic(self, kwargs, proc=None):
self._call_history.append((kwargs, proc))
def call_historic(self, proc=None, kwargs=None):
self._call_history.append((kwargs or {}, proc))
self._docall(self._nonwrappers + self._wrappers, kwargs)
def _apply_history(self, method):
if self.is_historic():
for kwargs, proc in self._call_history:
args = [kwargs[argname] for argname in varnames(method)]
res = method(*args)
if proc is not None:
proc(res)
res = self._docall([method], kwargs)
if res and proc is not None:
proc(res[0])
def _docall(self, methods, kwargs):
return MultiCall(methods, kwargs, firstresult=self.firstresult).execute()
class PluginValidationError(Exception):
@ -542,5 +539,5 @@ class PluginValidationError(Exception):
def formatdef(func):
return "%s%s" % (
func.__name__,
inspect.formatargspec(*inspect.getargspec(func))
formatargspec(*getargspec(func))
)

View File

@ -19,6 +19,11 @@ def pytest_namespace():
time.
"""
@hookspec_opts(historic=True)
def pytest_plugin_registered(plugin, manager):
""" a new pytest plugin got registered. """
@hookspec_opts(historic=True)
def pytest_addoption(parser):
"""register argparse-style options and ini-style config values.
@ -259,9 +264,6 @@ def pytest_doctest_prepare_content(content):
# error handling and internal debugging hooks
# -------------------------------------------------------------------------
def pytest_plugin_registered(plugin, manager):
""" a new pytest plugin got registered. """
def pytest_internalerror(excrepr, excinfo):
""" called for internal errors. """

View File

@ -381,7 +381,8 @@ class PyCollector(PyobjMixin, pytest.Collector):
if hasattr(cls, "pytest_generate_tests"):
methods.append(cls().pytest_generate_tests)
if methods:
self.ihook.pytest_generate_tests.callextra(methods, metafunc=metafunc)
self.ihook.pytest_generate_tests.call_extra(methods,
dict(metafunc=metafunc))
else:
self.ihook.pytest_generate_tests(metafunc=metafunc)
@ -1623,7 +1624,6 @@ class FixtureManager:
self.session = session
self.config = session.config
self._arg2fixturedefs = {}
self._seenplugins = set()
self._holderobjseen = set()
self._arg2finish = {}
self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]
@ -1648,11 +1648,7 @@ class FixtureManager:
node)
return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs)
### XXX this hook should be called for historic events like pytest_configure
### so that we don't have to do the below pytest_configure hook
def pytest_plugin_registered(self, plugin):
if plugin in self._seenplugins:
return
nodeid = None
try:
p = py.path.local(plugin.__file__)
@ -1667,13 +1663,6 @@ class FixtureManager:
if p.sep != "/":
nodeid = nodeid.replace(p.sep, "/")
self.parsefactories(plugin, nodeid)
self._seenplugins.add(plugin)
@pytest.hookimpl_opts(tryfirst=True)
def pytest_configure(self, config):
plugins = config.pluginmanager.getplugins()
for plugin in plugins:
self.pytest_plugin_registered(plugin)
def _getautousenames(self, nodeid):
""" return a tuple of fixture names to be used. """

View File

@ -111,7 +111,7 @@ class TestPluginManager:
l.append(arg*10)
pm.register(Plugin2())
assert l == [1, 10]
pm.hook.he_method1.call_historic(dict(arg=12))
pm.hook.he_method1.call_historic(kwargs=dict(arg=12))
assert l == [1, 10, 120, 12]
def test_with_result_memorized(self, pm):
@ -122,7 +122,7 @@ class TestPluginManager:
pm.addhooks(Hooks)
he_method1 = pm.hook.he_method1
he_method1.call_historic(proc=lambda res: l.append(res), kwargs=dict(arg=1))
he_method1.call_historic(lambda res: l.append(res), dict(arg=1))
l = []
class Plugin:
def he_method1(self, arg):
@ -140,7 +140,7 @@ class TestPluginManager:
def he_method1(arg):
return arg * 10
l = pm.hook.he_method1.callextra([he_method1], arg=1)
l = pm.hook.he_method1.call_extra([he_method1], dict(arg=1))
assert l == [10]
@ -323,7 +323,8 @@ class TestPytestPluginInteractions:
""")
config = get_plugin_manager().config
pm = config.pluginmanager
pm.hook.pytest_addhooks.call_historic(dict(pluginmanager=config.pluginmanager))
pm.hook.pytest_addhooks.call_historic(
kwargs=dict(pluginmanager=config.pluginmanager))
config.pluginmanager._importconftest(conf)
#print(config.pluginmanager.getplugins())
res = config.hook.pytest_myhook(xyz=10)
@ -399,10 +400,10 @@ class TestPytestPluginInteractions:
pytestpm = get_plugin_manager() # fully initialized with plugins
saveindent = []
class api1:
def pytest_plugin_registered(self, plugin):
def pytest_plugin_registered(self):
saveindent.append(pytestpm.trace.root.indent)
class api2:
def pytest_plugin_registered(self, plugin):
def pytest_plugin_registered(self):
saveindent.append(pytestpm.trace.root.indent)
raise ValueError()
l = []
@ -412,7 +413,7 @@ class TestPytestPluginInteractions:
p = api1()
pytestpm.register(p)
assert pytestpm.trace.root.indent == indent
assert len(l) == 2
assert len(l) >= 2
assert 'pytest_plugin_registered' in l[0]
assert 'finish' in l[1]