removed unnccessary indirections in the PluginManager,
also fixed a bug in _core.varnames(), which probably considerably speeds up hook calls. --HG-- branch : trunk
This commit is contained in:
parent
270deb015e
commit
3a5d28f3fe
189
pytest/_core.py
189
pytest/_core.py
|
@ -1,23 +1,26 @@
|
||||||
|
import sys, os
|
||||||
|
import inspect
|
||||||
import py
|
import py
|
||||||
|
from pytest import hookspec
|
||||||
|
|
||||||
assert py.__version__.split(".")[:2] >= ['2', '0'], ("installation problem: "
|
assert py.__version__.split(".")[:2] >= ['2', '0'], ("installation problem: "
|
||||||
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
||||||
|
|
||||||
import sys, os
|
|
||||||
|
|
||||||
default_plugins = (
|
default_plugins = (
|
||||||
"config session terminal python runner pdb capture mark skipping tmpdir "
|
"config session terminal python runner pdb capture mark skipping tmpdir "
|
||||||
"monkeypatch recwarn pastebin unittest helpconfig nose assertion genscript "
|
"monkeypatch recwarn pastebin unittest helpconfig nose assertion genscript "
|
||||||
"junitxml doctest").split()
|
"junitxml doctest").split()
|
||||||
|
|
||||||
|
IMPORTPREFIX = "pytest_"
|
||||||
|
|
||||||
class PluginManager(object):
|
class PluginManager(object):
|
||||||
def __init__(self):
|
def __init__(self, load=False):
|
||||||
from pytest import hookspec
|
|
||||||
self.registry = Registry()
|
|
||||||
self._name2plugin = {}
|
self._name2plugin = {}
|
||||||
|
self._plugins = []
|
||||||
self._hints = []
|
self._hints = []
|
||||||
self.hook = HookRelay([hookspec], registry=self.registry)
|
self.hook = HookRelay([hookspec], pm=self)
|
||||||
self.register(self)
|
self.register(self)
|
||||||
|
if load:
|
||||||
for spec in default_plugins:
|
for spec in default_plugins:
|
||||||
self.import_plugin(spec)
|
self.import_plugin(spec)
|
||||||
|
|
||||||
|
@ -31,19 +34,22 @@ class PluginManager(object):
|
||||||
|
|
||||||
def register(self, plugin, name=None, prepend=False):
|
def register(self, plugin, name=None, prepend=False):
|
||||||
assert not self.isregistered(plugin), plugin
|
assert not self.isregistered(plugin), plugin
|
||||||
assert not self.registry.isregistered(plugin), plugin
|
assert not self.isregistered(plugin), plugin
|
||||||
name = self._getpluginname(plugin, name)
|
name = self._getpluginname(plugin, name)
|
||||||
if name in self._name2plugin:
|
if name in self._name2plugin:
|
||||||
return False
|
return False
|
||||||
self._name2plugin[name] = plugin
|
self._name2plugin[name] = plugin
|
||||||
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
||||||
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
|
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
|
||||||
self.registry.register(plugin, prepend=prepend)
|
if not prepend:
|
||||||
|
self._plugins.append(plugin)
|
||||||
|
else:
|
||||||
|
self._plugins.insert(0, plugin)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def unregister(self, plugin):
|
def unregister(self, plugin):
|
||||||
self.hook.pytest_plugin_unregistered(plugin=plugin)
|
self.hook.pytest_plugin_unregistered(plugin=plugin)
|
||||||
self.registry.unregister(plugin)
|
self._plugins.remove(plugin)
|
||||||
for name, value in list(self._name2plugin.items()):
|
for name, value in list(self._name2plugin.items()):
|
||||||
if value == plugin:
|
if value == plugin:
|
||||||
del self._name2plugin[name]
|
del self._name2plugin[name]
|
||||||
|
@ -59,7 +65,7 @@ class PluginManager(object):
|
||||||
self.hook._addhooks(spec, prefix="pytest_")
|
self.hook._addhooks(spec, prefix="pytest_")
|
||||||
|
|
||||||
def getplugins(self):
|
def getplugins(self):
|
||||||
return list(self.registry)
|
return list(self._plugins)
|
||||||
|
|
||||||
def skipifmissing(self, name):
|
def skipifmissing(self, name):
|
||||||
if not self.hasplugin(name):
|
if not self.hasplugin(name):
|
||||||
|
@ -68,10 +74,9 @@ class PluginManager(object):
|
||||||
def hasplugin(self, name):
|
def hasplugin(self, name):
|
||||||
try:
|
try:
|
||||||
self.getplugin(name)
|
self.getplugin(name)
|
||||||
|
return True
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def getplugin(self, name):
|
def getplugin(self, name):
|
||||||
try:
|
try:
|
||||||
|
@ -145,35 +150,15 @@ class PluginManager(object):
|
||||||
self.register(mod, modname)
|
self.register(mod, modname)
|
||||||
self.consider_module(mod)
|
self.consider_module(mod)
|
||||||
|
|
||||||
def pytest_terminal_summary(self, terminalreporter):
|
def pytest_plugin_registered(self, plugin):
|
||||||
tw = terminalreporter._tw
|
dic = self.call_plugin(plugin, "pytest_namespace", {}) or {}
|
||||||
if terminalreporter.config.option.traceconfig:
|
if dic:
|
||||||
for hint in self._hints:
|
self._setns(py.test, dic)
|
||||||
tw.line("hint: %s" % hint)
|
if hasattr(self, '_config'):
|
||||||
|
self.call_plugin(plugin, "pytest_addoption",
|
||||||
#
|
{'parser': self._config._parser})
|
||||||
#
|
self.call_plugin(plugin, "pytest_configure",
|
||||||
# API for interacting with registered and instantiated plugin objects
|
{'config': self._config})
|
||||||
#
|
|
||||||
#
|
|
||||||
def listattr(self, attrname, plugins=None):
|
|
||||||
return self.registry.listattr(attrname, plugins=plugins)
|
|
||||||
|
|
||||||
def notify_exception(self, excinfo=None):
|
|
||||||
if excinfo is None:
|
|
||||||
excinfo = py.code.ExceptionInfo()
|
|
||||||
excrepr = excinfo.getrepr(funcargs=True, showlocals=True)
|
|
||||||
res = self.hook.pytest_internalerror(excrepr=excrepr)
|
|
||||||
if not py.builtin.any(res):
|
|
||||||
for line in str(excrepr).split("\n"):
|
|
||||||
sys.stderr.write("INTERNALERROR> %s\n" %line)
|
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
def do_addoption(self, parser):
|
|
||||||
mname = "pytest_addoption"
|
|
||||||
methods = self.registry.listattr(mname, reverse=True)
|
|
||||||
mc = MultiCall(methods, {'parser': parser})
|
|
||||||
mc.execute()
|
|
||||||
|
|
||||||
def _setns(self, obj, dic):
|
def _setns(self, obj, dic):
|
||||||
for name, value in dic.items():
|
for name, value in dic.items():
|
||||||
|
@ -191,20 +176,16 @@ class PluginManager(object):
|
||||||
setattr(obj, name, value)
|
setattr(obj, name, value)
|
||||||
obj.__all__.append(name)
|
obj.__all__.append(name)
|
||||||
|
|
||||||
def pytest_plugin_registered(self, plugin):
|
def pytest_terminal_summary(self, terminalreporter):
|
||||||
dic = self.call_plugin(plugin, "pytest_namespace", {}) or {}
|
tw = terminalreporter._tw
|
||||||
if dic:
|
if terminalreporter.config.option.traceconfig:
|
||||||
self._setns(py.test, dic)
|
for hint in self._hints:
|
||||||
if hasattr(self, '_config'):
|
tw.line("hint: %s" % hint)
|
||||||
self.call_plugin(plugin, "pytest_addoption",
|
|
||||||
{'parser': self._config._parser})
|
|
||||||
self.call_plugin(plugin, "pytest_configure",
|
|
||||||
{'config': self._config})
|
|
||||||
|
|
||||||
def call_plugin(self, plugin, methname, kwargs):
|
def do_addoption(self, parser):
|
||||||
return MultiCall(
|
mname = "pytest_addoption"
|
||||||
methods=self.listattr(methname, plugins=[plugin]),
|
methods = reversed(self.listattr(mname))
|
||||||
kwargs=kwargs, firstresult=True).execute()
|
MultiCall(methods, {'parser': parser}).execute()
|
||||||
|
|
||||||
def do_configure(self, config):
|
def do_configure(self, config):
|
||||||
assert not hasattr(self, '_config')
|
assert not hasattr(self, '_config')
|
||||||
|
@ -217,11 +198,33 @@ class PluginManager(object):
|
||||||
config.hook.pytest_unconfigure(config=config)
|
config.hook.pytest_unconfigure(config=config)
|
||||||
config.pluginmanager.unregister(self)
|
config.pluginmanager.unregister(self)
|
||||||
|
|
||||||
|
def notify_exception(self, excinfo):
|
||||||
|
excrepr = excinfo.getrepr(funcargs=True, showlocals=True)
|
||||||
|
res = self.hook.pytest_internalerror(excrepr=excrepr)
|
||||||
|
if not py.builtin.any(res):
|
||||||
|
for line in str(excrepr).split("\n"):
|
||||||
|
sys.stderr.write("INTERNALERROR> %s\n" %line)
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
def listattr(self, attrname, plugins=None):
|
||||||
|
if plugins is None:
|
||||||
|
plugins = self._plugins
|
||||||
|
l = []
|
||||||
|
for plugin in plugins:
|
||||||
|
try:
|
||||||
|
l.append(getattr(plugin, attrname))
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
return l
|
||||||
|
|
||||||
|
def call_plugin(self, plugin, methname, kwargs):
|
||||||
|
return MultiCall(methods=self.listattr(methname, plugins=[plugin]),
|
||||||
|
kwargs=kwargs, firstresult=True).execute()
|
||||||
|
|
||||||
def canonical_importname(name):
|
def canonical_importname(name):
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
modprefix = "pytest_"
|
if not name.startswith(IMPORTPREFIX):
|
||||||
if not name.startswith(modprefix):
|
name = IMPORTPREFIX + name
|
||||||
name = modprefix + name
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def importplugin(importspec):
|
def importplugin(importspec):
|
||||||
|
@ -247,11 +250,9 @@ def importplugin(importspec):
|
||||||
|
|
||||||
class MultiCall:
|
class MultiCall:
|
||||||
""" execute a call into multiple python functions/methods. """
|
""" execute a call into multiple python functions/methods. """
|
||||||
|
|
||||||
def __init__(self, methods, kwargs, firstresult=False):
|
def __init__(self, methods, kwargs, firstresult=False):
|
||||||
self.methods = methods[:]
|
self.methods = list(methods)
|
||||||
self.kwargs = kwargs.copy()
|
self.kwargs = kwargs
|
||||||
self.kwargs['__multicall__'] = self
|
|
||||||
self.results = []
|
self.results = []
|
||||||
self.firstresult = firstresult
|
self.firstresult = firstresult
|
||||||
|
|
||||||
|
@ -277,65 +278,26 @@ class MultiCall:
|
||||||
try:
|
try:
|
||||||
kwargs[argname] = self.kwargs[argname]
|
kwargs[argname] = self.kwargs[argname]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass # might be optional param
|
if argname == "__multicall__":
|
||||||
|
kwargs[argname] = self
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def varnames(func):
|
def varnames(func, cache={}):
|
||||||
import inspect
|
|
||||||
if not inspect.isfunction(func) and not inspect.ismethod(func):
|
if not inspect.isfunction(func) and not inspect.ismethod(func):
|
||||||
func = getattr(func, '__call__', func)
|
func = getattr(func, '__call__', func)
|
||||||
ismethod = inspect.ismethod(func)
|
ismethod = inspect.ismethod(func)
|
||||||
rawcode = py.code.getrawcode(func)
|
rawcode = py.code.getrawcode(func)
|
||||||
try:
|
try:
|
||||||
return rawcode.co_varnames[ismethod:]
|
return rawcode.co_varnames[ismethod:rawcode.co_argcount]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
class Registry:
|
|
||||||
"""
|
|
||||||
Manage Plugins: register/unregister call calls to plugins.
|
|
||||||
"""
|
|
||||||
def __init__(self, plugins=None):
|
|
||||||
if plugins is None:
|
|
||||||
plugins = []
|
|
||||||
self._plugins = plugins
|
|
||||||
|
|
||||||
def register(self, plugin, prepend=False):
|
|
||||||
assert not isinstance(plugin, str)
|
|
||||||
assert not plugin in self._plugins
|
|
||||||
if not prepend:
|
|
||||||
self._plugins.append(plugin)
|
|
||||||
else:
|
|
||||||
self._plugins.insert(0, plugin)
|
|
||||||
|
|
||||||
def unregister(self, plugin):
|
|
||||||
self._plugins.remove(plugin)
|
|
||||||
|
|
||||||
def isregistered(self, plugin):
|
|
||||||
return plugin in self._plugins
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self._plugins)
|
|
||||||
|
|
||||||
def listattr(self, attrname, plugins=None, reverse=False):
|
|
||||||
l = []
|
|
||||||
if plugins is None:
|
|
||||||
plugins = self._plugins
|
|
||||||
for plugin in plugins:
|
|
||||||
try:
|
|
||||||
l.append(getattr(plugin, attrname))
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
if reverse:
|
|
||||||
l.reverse()
|
|
||||||
return l
|
|
||||||
|
|
||||||
class HookRelay:
|
class HookRelay:
|
||||||
def __init__(self, hookspecs, registry, prefix="pytest_"):
|
def __init__(self, hookspecs, pm, prefix="pytest_"):
|
||||||
if not isinstance(hookspecs, list):
|
if not isinstance(hookspecs, list):
|
||||||
hookspecs = [hookspecs]
|
hookspecs = [hookspecs]
|
||||||
self._hookspecs = []
|
self._hookspecs = []
|
||||||
self._registry = registry
|
self._pm = pm
|
||||||
for hookspec in hookspecs:
|
for hookspec in hookspecs:
|
||||||
self._addhooks(hookspec, prefix)
|
self._addhooks(hookspec, prefix)
|
||||||
|
|
||||||
|
@ -357,9 +319,6 @@ class HookRelay:
|
||||||
prefix, hookspecs,))
|
prefix, hookspecs,))
|
||||||
|
|
||||||
|
|
||||||
def _performcall(self, name, multicall):
|
|
||||||
return multicall.execute()
|
|
||||||
|
|
||||||
class HookCaller:
|
class HookCaller:
|
||||||
def __init__(self, hookrelay, name, firstresult):
|
def __init__(self, hookrelay, name, firstresult):
|
||||||
self.hookrelay = hookrelay
|
self.hookrelay = hookrelay
|
||||||
|
@ -370,16 +329,16 @@ class HookCaller:
|
||||||
return "<HookCaller %r>" %(self.name,)
|
return "<HookCaller %r>" %(self.name,)
|
||||||
|
|
||||||
def __call__(self, **kwargs):
|
def __call__(self, **kwargs):
|
||||||
methods = self.hookrelay._registry.listattr(self.name)
|
methods = self.hookrelay._pm.listattr(self.name)
|
||||||
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
||||||
return self.hookrelay._performcall(self.name, mc)
|
return mc.execute()
|
||||||
|
|
||||||
def pcall(self, plugins, **kwargs):
|
def pcall(self, plugins, **kwargs):
|
||||||
methods = self.hookrelay._registry.listattr(self.name, plugins=plugins)
|
methods = self.hookrelay._pm.listattr(self.name, plugins=plugins)
|
||||||
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
||||||
return self.hookrelay._performcall(self.name, mc)
|
return mc.execute()
|
||||||
|
|
||||||
pluginmanager = PluginManager() # will trigger default plugin loading
|
pluginmanager = PluginManager(load=True) # will trigger default plugin importing
|
||||||
|
|
||||||
def main(args=None):
|
def main(args=None):
|
||||||
global pluginmanager
|
global pluginmanager
|
||||||
|
@ -393,6 +352,6 @@ def main(args=None):
|
||||||
e = sys.exc_info()[1]
|
e = sys.exc_info()[1]
|
||||||
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
|
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
|
||||||
exitstatus = 3
|
exitstatus = 3
|
||||||
pluginmanager = PluginManager()
|
pluginmanager = PluginManager(load=True)
|
||||||
return exitstatus
|
return exitstatus
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ class Config(object):
|
||||||
processopt=self._processopt,
|
processopt=self._processopt,
|
||||||
)
|
)
|
||||||
#: a pluginmanager instance
|
#: a pluginmanager instance
|
||||||
self.pluginmanager = pluginmanager or PluginManager()
|
self.pluginmanager = pluginmanager or PluginManager(load=True)
|
||||||
self._conftest = Conftest(onimport=self._onimportconftest)
|
self._conftest = Conftest(onimport=self._onimportconftest)
|
||||||
self.hook = self.pluginmanager.hook
|
self.hook = self.pluginmanager.hook
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class PytestArg:
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
def gethookrecorder(self, hook):
|
def gethookrecorder(self, hook):
|
||||||
hookrecorder = HookRecorder(hook._registry)
|
hookrecorder = HookRecorder(hook._pm)
|
||||||
hookrecorder.start_recording(hook._hookspecs)
|
hookrecorder.start_recording(hook._hookspecs)
|
||||||
self.request.addfinalizer(hookrecorder.finish_recording)
|
self.request.addfinalizer(hookrecorder.finish_recording)
|
||||||
return hookrecorder
|
return hookrecorder
|
||||||
|
@ -45,8 +45,8 @@ class ParsedCall:
|
||||||
return "<ParsedCall %r(**%r)>" %(self._name, d)
|
return "<ParsedCall %r(**%r)>" %(self._name, d)
|
||||||
|
|
||||||
class HookRecorder:
|
class HookRecorder:
|
||||||
def __init__(self, registry):
|
def __init__(self, pluginmanager):
|
||||||
self._registry = registry
|
self._pluginmanager = pluginmanager
|
||||||
self.calls = []
|
self.calls = []
|
||||||
self._recorders = {}
|
self._recorders = {}
|
||||||
|
|
||||||
|
@ -62,13 +62,13 @@ class HookRecorder:
|
||||||
setattr(RecordCalls, name, self._makecallparser(method))
|
setattr(RecordCalls, name, self._makecallparser(method))
|
||||||
recorder = RecordCalls()
|
recorder = RecordCalls()
|
||||||
self._recorders[hookspec] = recorder
|
self._recorders[hookspec] = recorder
|
||||||
self._registry.register(recorder)
|
self._pluginmanager.register(recorder)
|
||||||
self.hook = HookRelay(hookspecs, registry=self._registry,
|
self.hook = HookRelay(hookspecs, pm=self._pluginmanager,
|
||||||
prefix="pytest_")
|
prefix="pytest_")
|
||||||
|
|
||||||
def finish_recording(self):
|
def finish_recording(self):
|
||||||
for recorder in self._recorders.values():
|
for recorder in self._recorders.values():
|
||||||
self._registry.unregister(recorder)
|
self._pluginmanager.unregister(recorder)
|
||||||
self._recorders.clear()
|
self._recorders.clear()
|
||||||
|
|
||||||
def _makecallparser(self, method):
|
def _makecallparser(self, method):
|
||||||
|
@ -493,8 +493,8 @@ class PseudoPlugin:
|
||||||
class ReportRecorder(object):
|
class ReportRecorder(object):
|
||||||
def __init__(self, hook):
|
def __init__(self, hook):
|
||||||
self.hook = hook
|
self.hook = hook
|
||||||
self.registry = hook._registry
|
self.pluginmanager = hook._pm
|
||||||
self.registry.register(self)
|
self.pluginmanager.register(self)
|
||||||
|
|
||||||
def getcall(self, name):
|
def getcall(self, name):
|
||||||
return self.hookrecorder.getcall(name)
|
return self.hookrecorder.getcall(name)
|
||||||
|
@ -558,7 +558,7 @@ class ReportRecorder(object):
|
||||||
self.hookrecorder.calls[:] = []
|
self.hookrecorder.calls[:] = []
|
||||||
|
|
||||||
def unregister(self):
|
def unregister(self):
|
||||||
self.registry.unregister(self)
|
self.pluginmanager.unregister(self)
|
||||||
self.hookrecorder.finish_recording()
|
self.hookrecorder.finish_recording()
|
||||||
|
|
||||||
class LineComp:
|
class LineComp:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import py
|
import py
|
||||||
import os, sys
|
import os, sys
|
||||||
from pytest.plugin.pytester import LineMatcher, LineComp, HookRecorder
|
from pytest.plugin.pytester import LineMatcher, LineComp, HookRecorder
|
||||||
from pytest._core import Registry
|
from pytest._core import PluginManager
|
||||||
|
|
||||||
def test_reportrecorder(testdir):
|
def test_reportrecorder(testdir):
|
||||||
item = testdir.getitem("def test_func(): pass")
|
item = testdir.getitem("def test_func(): pass")
|
||||||
|
@ -72,7 +72,7 @@ def test_testdir_runs_with_plugin(testdir):
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_hookrecorder_basic():
|
def test_hookrecorder_basic():
|
||||||
rec = HookRecorder(Registry())
|
rec = HookRecorder(PluginManager())
|
||||||
class ApiClass:
|
class ApiClass:
|
||||||
def pytest_xyz(self, arg):
|
def pytest_xyz(self, arg):
|
||||||
"x"
|
"x"
|
||||||
|
@ -84,7 +84,7 @@ def test_hookrecorder_basic():
|
||||||
py.test.raises(ValueError, "rec.popcall('abc')")
|
py.test.raises(ValueError, "rec.popcall('abc')")
|
||||||
|
|
||||||
def test_hookrecorder_basic_no_args_hook():
|
def test_hookrecorder_basic_no_args_hook():
|
||||||
rec = HookRecorder(Registry())
|
rec = HookRecorder(PluginManager())
|
||||||
apimod = type(os)('api')
|
apimod = type(os)('api')
|
||||||
def pytest_xyz():
|
def pytest_xyz():
|
||||||
"x"
|
"x"
|
||||||
|
@ -97,17 +97,17 @@ def test_hookrecorder_basic_no_args_hook():
|
||||||
def test_functional(testdir, linecomp):
|
def test_functional(testdir, linecomp):
|
||||||
reprec = testdir.inline_runsource("""
|
reprec = testdir.inline_runsource("""
|
||||||
import py
|
import py
|
||||||
from pytest._core import HookRelay, Registry
|
from pytest._core import HookRelay, PluginManager
|
||||||
pytest_plugins="pytester"
|
pytest_plugins="pytester"
|
||||||
def test_func(_pytest):
|
def test_func(_pytest):
|
||||||
class ApiClass:
|
class ApiClass:
|
||||||
def pytest_xyz(self, arg): "x"
|
def pytest_xyz(self, arg): "x"
|
||||||
hook = HookRelay([ApiClass], Registry())
|
hook = HookRelay([ApiClass], PluginManager(load=False))
|
||||||
rec = _pytest.gethookrecorder(hook)
|
rec = _pytest.gethookrecorder(hook)
|
||||||
class Plugin:
|
class Plugin:
|
||||||
def pytest_xyz(self, arg):
|
def pytest_xyz(self, arg):
|
||||||
return arg + 1
|
return arg + 1
|
||||||
rec._registry.register(Plugin())
|
rec._pluginmanager.register(Plugin())
|
||||||
res = rec.hook.pytest_xyz(arg=41)
|
res = rec.hook.pytest_xyz(arg=41)
|
||||||
assert res == [42]
|
assert res == [42]
|
||||||
""")
|
""")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import py, os
|
import py, os
|
||||||
from pytest._core import PluginManager, canonical_importname
|
from pytest._core import PluginManager, canonical_importname
|
||||||
from pytest._core import Registry, MultiCall, HookRelay, varnames
|
from pytest._core import MultiCall, HookRelay, varnames
|
||||||
|
|
||||||
|
|
||||||
class TestBootstrapping:
|
class TestBootstrapping:
|
||||||
|
@ -143,7 +143,7 @@ class TestBootstrapping:
|
||||||
pp = PluginManager()
|
pp = PluginManager()
|
||||||
py.test.raises(ImportError, "pp.consider_conftest(mod)")
|
py.test.raises(ImportError, "pp.consider_conftest(mod)")
|
||||||
|
|
||||||
def test_registry(self):
|
def test_pm(self):
|
||||||
pp = PluginManager()
|
pp = PluginManager()
|
||||||
class A: pass
|
class A: pass
|
||||||
a1, a2 = A(), A()
|
a1, a2 = A(), A()
|
||||||
|
@ -160,7 +160,7 @@ class TestBootstrapping:
|
||||||
pp.unregister(a2)
|
pp.unregister(a2)
|
||||||
assert not pp.isregistered(a2)
|
assert not pp.isregistered(a2)
|
||||||
|
|
||||||
def test_registry_ordering(self):
|
def test_pm_ordering(self):
|
||||||
pp = PluginManager()
|
pp = PluginManager()
|
||||||
class A: pass
|
class A: pass
|
||||||
a1, a2 = A(), A()
|
a1, a2 = A(), A()
|
||||||
|
@ -182,7 +182,7 @@ class TestBootstrapping:
|
||||||
assert mod in l
|
assert mod in l
|
||||||
py.test.raises(AssertionError, "pp.register(mod)")
|
py.test.raises(AssertionError, "pp.register(mod)")
|
||||||
mod2 = py.std.types.ModuleType("pytest_hello")
|
mod2 = py.std.types.ModuleType("pytest_hello")
|
||||||
#pp.register(mod2) # double registry
|
#pp.register(mod2) # double pm
|
||||||
py.test.raises(AssertionError, "pp.register(mod)")
|
py.test.raises(AssertionError, "pp.register(mod)")
|
||||||
#assert not pp.isregistered(mod2)
|
#assert not pp.isregistered(mod2)
|
||||||
assert pp.getplugins() == l
|
assert pp.getplugins() == l
|
||||||
|
@ -197,14 +197,14 @@ class TestBootstrapping:
|
||||||
assert pp.isregistered(mod)
|
assert pp.isregistered(mod)
|
||||||
|
|
||||||
def test_register_mismatch_method(self):
|
def test_register_mismatch_method(self):
|
||||||
pp = PluginManager()
|
pp = PluginManager(load=True)
|
||||||
class hello:
|
class hello:
|
||||||
def pytest_gurgel(self):
|
def pytest_gurgel(self):
|
||||||
pass
|
pass
|
||||||
py.test.raises(Exception, "pp.register(hello())")
|
py.test.raises(Exception, "pp.register(hello())")
|
||||||
|
|
||||||
def test_register_mismatch_arg(self):
|
def test_register_mismatch_arg(self):
|
||||||
pp = PluginManager()
|
pp = PluginManager(load=True)
|
||||||
class hello:
|
class hello:
|
||||||
def pytest_configure(self, asd):
|
def pytest_configure(self, asd):
|
||||||
pass
|
pass
|
||||||
|
@ -228,6 +228,36 @@ class TestBootstrapping:
|
||||||
out, err = capfd.readouterr()
|
out, err = capfd.readouterr()
|
||||||
assert not err
|
assert not err
|
||||||
|
|
||||||
|
def test_register(self):
|
||||||
|
pm = PluginManager(load=False)
|
||||||
|
class MyPlugin:
|
||||||
|
pass
|
||||||
|
my = MyPlugin()
|
||||||
|
pm.register(my)
|
||||||
|
assert pm.getplugins()
|
||||||
|
my2 = MyPlugin()
|
||||||
|
pm.register(my2)
|
||||||
|
assert pm.getplugins()[1:] == [my, my2]
|
||||||
|
|
||||||
|
assert pm.isregistered(my)
|
||||||
|
assert pm.isregistered(my2)
|
||||||
|
pm.unregister(my)
|
||||||
|
assert not pm.isregistered(my)
|
||||||
|
assert pm.getplugins()[1:] == [my2]
|
||||||
|
|
||||||
|
def test_listattr(self):
|
||||||
|
plugins = PluginManager()
|
||||||
|
class api1:
|
||||||
|
x = 41
|
||||||
|
class api2:
|
||||||
|
x = 42
|
||||||
|
class api3:
|
||||||
|
x = 43
|
||||||
|
plugins.register(api1())
|
||||||
|
plugins.register(api2())
|
||||||
|
plugins.register(api3())
|
||||||
|
l = list(plugins.listattr('x'))
|
||||||
|
assert l == [41, 42, 43]
|
||||||
|
|
||||||
class TestPytestPluginInteractions:
|
class TestPytestPluginInteractions:
|
||||||
|
|
||||||
|
@ -370,7 +400,7 @@ def test_namespace_has_default_and_env_plugins(testdir):
|
||||||
|
|
||||||
def test_varnames():
|
def test_varnames():
|
||||||
def f(x):
|
def f(x):
|
||||||
pass
|
i = 3
|
||||||
class A:
|
class A:
|
||||||
def f(self, y):
|
def f(self, y):
|
||||||
pass
|
pass
|
||||||
|
@ -425,6 +455,14 @@ class TestMultiCall:
|
||||||
assert reslist == [24+23, 24]
|
assert reslist == [24+23, 24]
|
||||||
assert "2 results" in repr(multicall)
|
assert "2 results" in repr(multicall)
|
||||||
|
|
||||||
|
def test_keyword_args_with_defaultargs(self):
|
||||||
|
def f(x, z=1):
|
||||||
|
return x + z
|
||||||
|
reslist = MultiCall([f], dict(x=23, y=24)).execute()
|
||||||
|
assert reslist == [24]
|
||||||
|
reslist = MultiCall([f], dict(x=23, z=2)).execute()
|
||||||
|
assert reslist == [25]
|
||||||
|
|
||||||
def test_keywords_call_error(self):
|
def test_keywords_call_error(self):
|
||||||
multicall = MultiCall([lambda x: x], {})
|
multicall = MultiCall([lambda x: x], {})
|
||||||
py.test.raises(TypeError, "multicall.execute()")
|
py.test.raises(TypeError, "multicall.execute()")
|
||||||
|
@ -451,79 +489,44 @@ class TestMultiCall:
|
||||||
res = MultiCall([m1, m2], {}).execute()
|
res = MultiCall([m1, m2], {}).execute()
|
||||||
assert res == [1]
|
assert res == [1]
|
||||||
|
|
||||||
class TestRegistry:
|
|
||||||
|
|
||||||
def test_register(self):
|
|
||||||
registry = Registry()
|
|
||||||
class MyPlugin:
|
|
||||||
pass
|
|
||||||
my = MyPlugin()
|
|
||||||
registry.register(my)
|
|
||||||
assert list(registry) == [my]
|
|
||||||
my2 = MyPlugin()
|
|
||||||
registry.register(my2)
|
|
||||||
assert list(registry) == [my, my2]
|
|
||||||
|
|
||||||
assert registry.isregistered(my)
|
|
||||||
assert registry.isregistered(my2)
|
|
||||||
registry.unregister(my)
|
|
||||||
assert not registry.isregistered(my)
|
|
||||||
assert list(registry) == [my2]
|
|
||||||
|
|
||||||
def test_listattr(self):
|
|
||||||
plugins = Registry()
|
|
||||||
class api1:
|
|
||||||
x = 41
|
|
||||||
class api2:
|
|
||||||
x = 42
|
|
||||||
class api3:
|
|
||||||
x = 43
|
|
||||||
plugins.register(api1())
|
|
||||||
plugins.register(api2())
|
|
||||||
plugins.register(api3())
|
|
||||||
l = list(plugins.listattr('x'))
|
|
||||||
assert l == [41, 42, 43]
|
|
||||||
l = list(plugins.listattr('x', reverse=True))
|
|
||||||
assert l == [43, 42, 41]
|
|
||||||
|
|
||||||
class TestHookRelay:
|
class TestHookRelay:
|
||||||
def test_happypath(self):
|
def test_happypath(self):
|
||||||
registry = Registry()
|
pm = PluginManager()
|
||||||
class Api:
|
class Api:
|
||||||
def hello(self, arg):
|
def hello(self, arg):
|
||||||
"api hook 1"
|
"api hook 1"
|
||||||
|
|
||||||
mcm = HookRelay(hookspecs=Api, registry=registry, prefix="he")
|
mcm = HookRelay(hookspecs=Api, pm=pm, prefix="he")
|
||||||
assert hasattr(mcm, 'hello')
|
assert hasattr(mcm, 'hello')
|
||||||
assert repr(mcm.hello).find("hello") != -1
|
assert repr(mcm.hello).find("hello") != -1
|
||||||
class Plugin:
|
class Plugin:
|
||||||
def hello(self, arg):
|
def hello(self, arg):
|
||||||
return arg + 1
|
return arg + 1
|
||||||
registry.register(Plugin())
|
pm.register(Plugin())
|
||||||
l = mcm.hello(arg=3)
|
l = mcm.hello(arg=3)
|
||||||
assert l == [4]
|
assert l == [4]
|
||||||
assert not hasattr(mcm, 'world')
|
assert not hasattr(mcm, 'world')
|
||||||
|
|
||||||
def test_only_kwargs(self):
|
def test_only_kwargs(self):
|
||||||
registry = Registry()
|
pm = PluginManager()
|
||||||
class Api:
|
class Api:
|
||||||
def hello(self, arg):
|
def hello(self, arg):
|
||||||
"api hook 1"
|
"api hook 1"
|
||||||
mcm = HookRelay(hookspecs=Api, registry=registry, prefix="he")
|
mcm = HookRelay(hookspecs=Api, pm=pm, prefix="he")
|
||||||
py.test.raises(TypeError, "mcm.hello(3)")
|
py.test.raises(TypeError, "mcm.hello(3)")
|
||||||
|
|
||||||
def test_firstresult_definition(self):
|
def test_firstresult_definition(self):
|
||||||
registry = Registry()
|
pm = PluginManager()
|
||||||
class Api:
|
class Api:
|
||||||
def hello(self, arg):
|
def hello(self, arg):
|
||||||
"api hook 1"
|
"api hook 1"
|
||||||
hello.firstresult = True
|
hello.firstresult = True
|
||||||
|
|
||||||
mcm = HookRelay(hookspecs=Api, registry=registry, prefix="he")
|
mcm = HookRelay(hookspecs=Api, pm=pm, prefix="he")
|
||||||
class Plugin:
|
class Plugin:
|
||||||
def hello(self, arg):
|
def hello(self, arg):
|
||||||
return arg + 1
|
return arg + 1
|
||||||
registry.register(Plugin())
|
pm.register(Plugin())
|
||||||
res = mcm.hello(arg=3)
|
res = mcm.hello(arg=3)
|
||||||
assert res == 4
|
assert res == 4
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue