blob: 9584a0ae5a8244f1d063e73b9b23972993e611fb [file] [log] [blame]
import pytest
import sys
import types
from pluggy import PluginManager, HookImpl, HookimplMarker, HookspecMarker
hookspec = HookspecMarker("example")
hookimpl = HookimplMarker("example")
@pytest.fixture
def hc(pm):
class Hooks(object):
@hookspec
def he_method1(self, arg):
pass
pm.add_hookspecs(Hooks)
return pm.hook.he_method1
@pytest.fixture
def addmeth(hc):
def addmeth(tryfirst=False, trylast=False, hookwrapper=False):
def wrap(func):
hookimpl(tryfirst=tryfirst, trylast=trylast,
hookwrapper=hookwrapper)(func)
hc._add_hookimpl(HookImpl(None, "<temp>", func, func.example_impl))
return func
return wrap
return addmeth
def funcs(hookmethods):
return [hookmethod.function for hookmethod in hookmethods]
def test_adding_nonwrappers(hc, addmeth):
@addmeth()
def he_method1():
pass
@addmeth()
def he_method2():
pass
@addmeth()
def he_method3():
pass
assert funcs(hc._nonwrappers) == [he_method1, he_method2, he_method3]
def test_adding_nonwrappers_trylast(hc, addmeth):
@addmeth()
def he_method1_middle():
pass
@addmeth(trylast=True)
def he_method1():
pass
@addmeth()
def he_method1_b():
pass
assert funcs(hc._nonwrappers) == [he_method1, he_method1_middle, he_method1_b]
def test_adding_nonwrappers_trylast3(hc, addmeth):
@addmeth()
def he_method1_a():
pass
@addmeth(trylast=True)
def he_method1_b():
pass
@addmeth()
def he_method1_c():
pass
@addmeth(trylast=True)
def he_method1_d():
pass
assert funcs(hc._nonwrappers) == \
[he_method1_d, he_method1_b, he_method1_a, he_method1_c]
def test_adding_nonwrappers_trylast2(hc, addmeth):
@addmeth()
def he_method1_middle():
pass
@addmeth()
def he_method1_b():
pass
@addmeth(trylast=True)
def he_method1():
pass
assert funcs(hc._nonwrappers) == \
[he_method1, he_method1_middle, he_method1_b]
def test_adding_nonwrappers_tryfirst(hc, addmeth):
@addmeth(tryfirst=True)
def he_method1():
pass
@addmeth()
def he_method1_middle():
pass
@addmeth()
def he_method1_b():
pass
assert funcs(hc._nonwrappers) == [
he_method1_middle, he_method1_b, he_method1]
def test_adding_wrappers_ordering(hc, addmeth):
@addmeth(hookwrapper=True)
def he_method1():
pass
@addmeth()
def he_method1_middle():
pass
@addmeth(hookwrapper=True)
def he_method3():
pass
assert funcs(hc._nonwrappers) == [he_method1_middle]
assert funcs(hc._wrappers) == [he_method1, he_method3]
def test_adding_wrappers_ordering_tryfirst(hc, addmeth):
@addmeth(hookwrapper=True, tryfirst=True)
def he_method1():
pass
@addmeth(hookwrapper=True)
def he_method2():
pass
assert hc._nonwrappers == []
assert funcs(hc._wrappers) == [he_method2, he_method1]
def test_hookspec(pm):
class HookSpec(object):
@hookspec()
def he_myhook1(arg1):
pass
@hookspec(firstresult=True)
def he_myhook2(arg1):
pass
@hookspec(firstresult=False)
def he_myhook3(arg1):
pass
pm.add_hookspecs(HookSpec)
assert not pm.hook.he_myhook1.spec_opts["firstresult"]
assert pm.hook.he_myhook2.spec_opts["firstresult"]
assert not pm.hook.he_myhook3.spec_opts["firstresult"]
@pytest.mark.parametrize('name', ["hookwrapper", "optionalhook", "tryfirst", "trylast"])
@pytest.mark.parametrize('val', [True, False])
def test_hookimpl(name, val):
@hookimpl(**{name: val})
def he_myhook1(arg1):
pass
if val:
assert he_myhook1.example_impl.get(name)
else:
assert not hasattr(he_myhook1, name)
def test_load_setuptools_instantiation(monkeypatch, pm):
pkg_resources = pytest.importorskip("pkg_resources")
def my_iter(name):
assert name == "hello"
class EntryPoint(object):
name = "myname"
dist = None
def load(self):
class PseudoPlugin(object):
x = 42
return PseudoPlugin()
return iter([EntryPoint()])
monkeypatch.setattr(pkg_resources, 'iter_entry_points', my_iter)
num = pm.load_setuptools_entrypoints("hello")
assert num == 1
plugin = pm.get_plugin("myname")
assert plugin.x == 42
assert pm.list_plugin_distinfo() == [(plugin, None)]
def test_load_setuptools_not_installed(monkeypatch, pm):
monkeypatch.setitem(
sys.modules, 'pkg_resources',
types.ModuleType("pkg_resources"))
with pytest.raises(ImportError):
pm.load_setuptools_entrypoints("qwe")
def test_add_tracefuncs(he_pm):
out = []
class api1(object):
@hookimpl
def he_method1(self):
out.append("he_method1-api1")
class api2(object):
@hookimpl
def he_method1(self):
out.append("he_method1-api2")
he_pm.register(api1())
he_pm.register(api2())
def before(hook_name, hook_impls, kwargs):
out.append((hook_name, list(hook_impls), kwargs))
def after(outcome, hook_name, hook_impls, kwargs):
out.append((outcome, hook_name, list(hook_impls), kwargs))
undo = he_pm.add_hookcall_monitoring(before, after)
he_pm.hook.he_method1(arg=1)
assert len(out) == 4
assert out[0][0] == "he_method1"
assert len(out[0][1]) == 2
assert isinstance(out[0][2], dict)
assert out[1] == "he_method1-api2"
assert out[2] == "he_method1-api1"
assert len(out[3]) == 4
assert out[3][1] == out[0][0]
undo()
he_pm.hook.he_method1(arg=1)
assert len(out) == 4 + 2
def test_hook_tracing(he_pm):
saveindent = []
class api1(object):
@hookimpl
def he_method1(self):
saveindent.append(he_pm.trace.root.indent)
class api2(object):
@hookimpl
def he_method1(self):
saveindent.append(he_pm.trace.root.indent)
raise ValueError()
he_pm.register(api1())
out = []
he_pm.trace.root.setwriter(out.append)
undo = he_pm.enable_tracing()
try:
indent = he_pm.trace.root.indent
he_pm.hook.he_method1(arg=1)
assert indent == he_pm.trace.root.indent
assert len(out) == 2
assert 'he_method1' in out[0]
assert 'finish' in out[1]
out[:] = []
he_pm.register(api2())
with pytest.raises(ValueError):
he_pm.hook.he_method1(arg=1)
assert he_pm.trace.root.indent == indent
assert saveindent[0] > indent
finally:
undo()
@pytest.mark.parametrize('include_hookspec', [True, False])
def test_prefix_hookimpl(include_hookspec):
pm = PluginManager(hookspec.project_name, "hello_")
if include_hookspec:
class HookSpec(object):
@hookspec
def hello_myhook(self, arg1):
""" add to arg1 """
pm.add_hookspecs(HookSpec)
class Plugin(object):
def hello_myhook(self, arg1):
return arg1 + 1
pm.register(Plugin())
pm.register(Plugin())
results = pm.hook.hello_myhook(arg1=17)
assert results == [18, 18]
def test_prefix_hookimpl_dontmatch_module():
pm = PluginManager(hookspec.project_name, "hello_")
class BadPlugin(object):
hello_module = __import__('email')
pm.register(BadPlugin())
pm.check_pending()