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