diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/pluggy/py2/tests | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/pluggy/py2/tests')
-rw-r--r-- | contrib/python/pluggy/py2/tests/benchmark.py | 102 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/conftest.py | 52 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_deprecations.py | 108 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_details.py | 270 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_helpers.py | 180 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_hookcaller.py | 430 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_invocations.py | 432 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_multicall.py | 372 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_pluginmanager.py | 1200 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/test_tracer.py | 156 | ||||
-rw-r--r-- | contrib/python/pluggy/py2/tests/ya.make | 46 |
11 files changed, 1674 insertions, 1674 deletions
diff --git a/contrib/python/pluggy/py2/tests/benchmark.py b/contrib/python/pluggy/py2/tests/benchmark.py index cb99660adb..aa8de92911 100644 --- a/contrib/python/pluggy/py2/tests/benchmark.py +++ b/contrib/python/pluggy/py2/tests/benchmark.py @@ -1,51 +1,51 @@ -""" -Benchmarking and performance tests. -""" -import pytest -from pluggy import HookspecMarker, HookimplMarker -from pluggy.hooks import HookImpl -from pluggy.callers import _multicall, _legacymulticall - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def MC(methods, kwargs, callertype, firstresult=False): - hookfuncs = [] - for method in methods: - f = HookImpl(None, "<temp>", method, method.example_impl) - hookfuncs.append(f) - return callertype(hookfuncs, kwargs, firstresult=firstresult) - - -@hookimpl -def hook(arg1, arg2, arg3): - return arg1, arg2, arg3 - - -@hookimpl(hookwrapper=True) -def wrapper(arg1, arg2, arg3): - yield - - -@pytest.fixture(params=[10, 100], ids="hooks={}".format) -def hooks(request): - return [hook for i in range(request.param)] - - -@pytest.fixture(params=[10, 100], ids="wrappers={}".format) -def wrappers(request): - return [wrapper for i in range(request.param)] - - -@pytest.fixture(params=[_multicall, _legacymulticall], ids=lambda item: item.__name__) -def callertype(request): - return request.param - - -def inner_exec(methods, callertype): - return MC(methods, {"arg1": 1, "arg2": 2, "arg3": 3}, callertype) - - -def test_hook_and_wrappers_speed(benchmark, hooks, wrappers, callertype): - benchmark(inner_exec, hooks + wrappers, callertype) +""" +Benchmarking and performance tests. +""" +import pytest +from pluggy import HookspecMarker, HookimplMarker +from pluggy.hooks import HookImpl +from pluggy.callers import _multicall, _legacymulticall + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def MC(methods, kwargs, callertype, firstresult=False): + hookfuncs = [] + for method in methods: + f = HookImpl(None, "<temp>", method, method.example_impl) + hookfuncs.append(f) + return callertype(hookfuncs, kwargs, firstresult=firstresult) + + +@hookimpl +def hook(arg1, arg2, arg3): + return arg1, arg2, arg3 + + +@hookimpl(hookwrapper=True) +def wrapper(arg1, arg2, arg3): + yield + + +@pytest.fixture(params=[10, 100], ids="hooks={}".format) +def hooks(request): + return [hook for i in range(request.param)] + + +@pytest.fixture(params=[10, 100], ids="wrappers={}".format) +def wrappers(request): + return [wrapper for i in range(request.param)] + + +@pytest.fixture(params=[_multicall, _legacymulticall], ids=lambda item: item.__name__) +def callertype(request): + return request.param + + +def inner_exec(methods, callertype): + return MC(methods, {"arg1": 1, "arg2": 2, "arg3": 3}, callertype) + + +def test_hook_and_wrappers_speed(benchmark, hooks, wrappers, callertype): + benchmark(inner_exec, hooks + wrappers, callertype) diff --git a/contrib/python/pluggy/py2/tests/conftest.py b/contrib/python/pluggy/py2/tests/conftest.py index 3e40b0f9ca..e44667ef5f 100644 --- a/contrib/python/pluggy/py2/tests/conftest.py +++ b/contrib/python/pluggy/py2/tests/conftest.py @@ -1,26 +1,26 @@ -import pytest - - -@pytest.fixture( - params=[lambda spec: spec, lambda spec: spec()], - ids=["spec-is-class", "spec-is-instance"], -) -def he_pm(request, pm): - from pluggy import HookspecMarker - - hookspec = HookspecMarker("example") - - class Hooks(object): - @hookspec - def he_method1(self, arg): - return arg + 1 - - pm.add_hookspecs(request.param(Hooks)) - return pm - - -@pytest.fixture -def pm(): - from pluggy import PluginManager - - return PluginManager("example") +import pytest + + +@pytest.fixture( + params=[lambda spec: spec, lambda spec: spec()], + ids=["spec-is-class", "spec-is-instance"], +) +def he_pm(request, pm): + from pluggy import HookspecMarker + + hookspec = HookspecMarker("example") + + class Hooks(object): + @hookspec + def he_method1(self, arg): + return arg + 1 + + pm.add_hookspecs(request.param(Hooks)) + return pm + + +@pytest.fixture +def pm(): + from pluggy import PluginManager + + return PluginManager("example") diff --git a/contrib/python/pluggy/py2/tests/test_deprecations.py b/contrib/python/pluggy/py2/tests/test_deprecations.py index 72048397d7..7151921b66 100644 --- a/contrib/python/pluggy/py2/tests/test_deprecations.py +++ b/contrib/python/pluggy/py2/tests/test_deprecations.py @@ -1,54 +1,54 @@ -""" -Deprecation warnings testing roundup. -""" -import pytest -from pluggy.callers import _Result -from pluggy import PluginManager, HookimplMarker, HookspecMarker - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def test_result_deprecated(): - r = _Result(10, None) - with pytest.deprecated_call(): - assert r.result == 10 - - -def test_implprefix_deprecated(): - with pytest.deprecated_call(): - pm = PluginManager("blah", implprefix="blah_") - - class Plugin: - def blah_myhook(self, arg1): - return arg1 - - with pytest.deprecated_call(): - pm.register(Plugin()) - - -def test_callhistoric_proc_deprecated(pm): - """``proc`` kwarg to `PluginMananger.call_historic()` is now officially - deprecated. - """ - - class P1(object): - @hookspec(historic=True) - @hookimpl - def m(self, x): - pass - - p1 = P1() - pm.add_hookspecs(p1) - pm.register(p1) - with pytest.deprecated_call(): - pm.hook.m.call_historic(kwargs=dict(x=10), proc=lambda res: res) - - -def test_multicall_deprecated(pm): - class P1(object): - @hookimpl - def m(self, __multicall__, x): - pass - - pytest.deprecated_call(pm.register, P1()) +""" +Deprecation warnings testing roundup. +""" +import pytest +from pluggy.callers import _Result +from pluggy import PluginManager, HookimplMarker, HookspecMarker + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_result_deprecated(): + r = _Result(10, None) + with pytest.deprecated_call(): + assert r.result == 10 + + +def test_implprefix_deprecated(): + with pytest.deprecated_call(): + pm = PluginManager("blah", implprefix="blah_") + + class Plugin: + def blah_myhook(self, arg1): + return arg1 + + with pytest.deprecated_call(): + pm.register(Plugin()) + + +def test_callhistoric_proc_deprecated(pm): + """``proc`` kwarg to `PluginMananger.call_historic()` is now officially + deprecated. + """ + + class P1(object): + @hookspec(historic=True) + @hookimpl + def m(self, x): + pass + + p1 = P1() + pm.add_hookspecs(p1) + pm.register(p1) + with pytest.deprecated_call(): + pm.hook.m.call_historic(kwargs=dict(x=10), proc=lambda res: res) + + +def test_multicall_deprecated(pm): + class P1(object): + @hookimpl + def m(self, __multicall__, x): + pass + + pytest.deprecated_call(pm.register, P1()) diff --git a/contrib/python/pluggy/py2/tests/test_details.py b/contrib/python/pluggy/py2/tests/test_details.py index 4745a155df..fc49fc308d 100644 --- a/contrib/python/pluggy/py2/tests/test_details.py +++ b/contrib/python/pluggy/py2/tests/test_details.py @@ -1,135 +1,135 @@ -import warnings -import pytest -from pluggy import PluginManager, HookimplMarker, HookspecMarker - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def test_parse_hookimpl_override(): - class MyPluginManager(PluginManager): - def parse_hookimpl_opts(self, module_or_class, name): - opts = PluginManager.parse_hookimpl_opts(self, module_or_class, name) - if opts is None: - if name.startswith("x1"): - opts = {} - return opts - - class Plugin(object): - def x1meth(self): - pass - - @hookimpl(hookwrapper=True, tryfirst=True) - def x1meth2(self): - pass - - class Spec(object): - @hookspec - def x1meth(self): - pass - - @hookspec - def x1meth2(self): - pass - - pm = MyPluginManager(hookspec.project_name) - pm.register(Plugin()) - pm.add_hookspecs(Spec) - assert not pm.hook.x1meth._nonwrappers[0].hookwrapper - assert not pm.hook.x1meth._nonwrappers[0].tryfirst - assert not pm.hook.x1meth._nonwrappers[0].trylast - assert not pm.hook.x1meth._nonwrappers[0].optionalhook - - assert pm.hook.x1meth2._wrappers[0].tryfirst - assert pm.hook.x1meth2._wrappers[0].hookwrapper - - -def test_warn_when_deprecated_specified(recwarn): - warning = DeprecationWarning("foo is deprecated") - - class Spec(object): - @hookspec(warn_on_impl=warning) - def foo(self): - pass - - class Plugin(object): - @hookimpl - def foo(self): - pass - - pm = PluginManager(hookspec.project_name) - pm.add_hookspecs(Spec) - - with pytest.warns(DeprecationWarning) as records: - pm.register(Plugin()) - (record,) = records - assert record.message is warning - assert record.filename == Plugin.foo.__code__.co_filename - assert record.lineno == Plugin.foo.__code__.co_firstlineno - - -def test_plugin_getattr_raises_errors(): - """Pluggy must be able to handle plugins which raise weird exceptions - when getattr() gets called (#11). - """ - - class DontTouchMe(object): - def __getattr__(self, x): - raise Exception("cant touch me") - - class Module(object): - pass - - module = Module() - module.x = DontTouchMe() - - pm = PluginManager(hookspec.project_name) - # register() would raise an error - pm.register(module, "donttouch") - assert pm.get_plugin("donttouch") is module - - -def test_warning_on_call_vs_hookspec_arg_mismatch(): - """Verify that is a hook is called with less arguments then defined in the - spec that a warning is emitted. - """ - - class Spec: - @hookspec - def myhook(self, arg1, arg2): - pass - - class Plugin: - @hookimpl - def myhook(self, arg1): - pass - - pm = PluginManager(hookspec.project_name) - pm.register(Plugin()) - pm.add_hookspecs(Spec()) - - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter("always") - - # calling should trigger a warning - pm.hook.myhook(arg1=1) - - assert len(warns) == 1 - warning = warns[-1] - assert issubclass(warning.category, Warning) - assert "Argument(s) ('arg2',)" in str(warning.message) - - -def test_repr(): - class Plugin: - @hookimpl - def myhook(): - raise NotImplementedError() - - pm = PluginManager(hookspec.project_name) - - plugin = Plugin() - pname = pm.register(plugin) - assert repr(pm.hook.myhook._nonwrappers[0]) == ( - "<HookImpl plugin_name=%r, plugin=%r>" % (pname, plugin) - ) +import warnings +import pytest +from pluggy import PluginManager, HookimplMarker, HookspecMarker + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_parse_hookimpl_override(): + class MyPluginManager(PluginManager): + def parse_hookimpl_opts(self, module_or_class, name): + opts = PluginManager.parse_hookimpl_opts(self, module_or_class, name) + if opts is None: + if name.startswith("x1"): + opts = {} + return opts + + class Plugin(object): + def x1meth(self): + pass + + @hookimpl(hookwrapper=True, tryfirst=True) + def x1meth2(self): + pass + + class Spec(object): + @hookspec + def x1meth(self): + pass + + @hookspec + def x1meth2(self): + pass + + pm = MyPluginManager(hookspec.project_name) + pm.register(Plugin()) + pm.add_hookspecs(Spec) + assert not pm.hook.x1meth._nonwrappers[0].hookwrapper + assert not pm.hook.x1meth._nonwrappers[0].tryfirst + assert not pm.hook.x1meth._nonwrappers[0].trylast + assert not pm.hook.x1meth._nonwrappers[0].optionalhook + + assert pm.hook.x1meth2._wrappers[0].tryfirst + assert pm.hook.x1meth2._wrappers[0].hookwrapper + + +def test_warn_when_deprecated_specified(recwarn): + warning = DeprecationWarning("foo is deprecated") + + class Spec(object): + @hookspec(warn_on_impl=warning) + def foo(self): + pass + + class Plugin(object): + @hookimpl + def foo(self): + pass + + pm = PluginManager(hookspec.project_name) + pm.add_hookspecs(Spec) + + with pytest.warns(DeprecationWarning) as records: + pm.register(Plugin()) + (record,) = records + assert record.message is warning + assert record.filename == Plugin.foo.__code__.co_filename + assert record.lineno == Plugin.foo.__code__.co_firstlineno + + +def test_plugin_getattr_raises_errors(): + """Pluggy must be able to handle plugins which raise weird exceptions + when getattr() gets called (#11). + """ + + class DontTouchMe(object): + def __getattr__(self, x): + raise Exception("cant touch me") + + class Module(object): + pass + + module = Module() + module.x = DontTouchMe() + + pm = PluginManager(hookspec.project_name) + # register() would raise an error + pm.register(module, "donttouch") + assert pm.get_plugin("donttouch") is module + + +def test_warning_on_call_vs_hookspec_arg_mismatch(): + """Verify that is a hook is called with less arguments then defined in the + spec that a warning is emitted. + """ + + class Spec: + @hookspec + def myhook(self, arg1, arg2): + pass + + class Plugin: + @hookimpl + def myhook(self, arg1): + pass + + pm = PluginManager(hookspec.project_name) + pm.register(Plugin()) + pm.add_hookspecs(Spec()) + + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter("always") + + # calling should trigger a warning + pm.hook.myhook(arg1=1) + + assert len(warns) == 1 + warning = warns[-1] + assert issubclass(warning.category, Warning) + assert "Argument(s) ('arg2',)" in str(warning.message) + + +def test_repr(): + class Plugin: + @hookimpl + def myhook(): + raise NotImplementedError() + + pm = PluginManager(hookspec.project_name) + + plugin = Plugin() + pname = pm.register(plugin) + assert repr(pm.hook.myhook._nonwrappers[0]) == ( + "<HookImpl plugin_name=%r, plugin=%r>" % (pname, plugin) + ) diff --git a/contrib/python/pluggy/py2/tests/test_helpers.py b/contrib/python/pluggy/py2/tests/test_helpers.py index 63e56ebde8..64c3edaa0a 100644 --- a/contrib/python/pluggy/py2/tests/test_helpers.py +++ b/contrib/python/pluggy/py2/tests/test_helpers.py @@ -1,90 +1,90 @@ -from pluggy.hooks import varnames -from pluggy.manager import _formatdef - -import sys -import pytest - - -def test_varnames(): - def f(x): - i = 3 # noqa - - class A(object): - def f(self, y): - pass - - class B(object): - def __call__(self, z): - pass - - assert varnames(f) == (("x",), ()) - assert varnames(A().f) == (("y",), ()) - assert varnames(B()) == (("z",), ()) - - -def test_varnames_default(): - def f(x, y=3): - pass - - assert varnames(f) == (("x",), ("y",)) - - -def test_varnames_class(): - class C(object): - def __init__(self, x): - pass - - class D(object): - pass - - class E(object): - def __init__(self, x): - pass - - class F(object): - pass - - assert varnames(C) == (("x",), ()) - assert varnames(D) == ((), ()) - assert varnames(E) == (("x",), ()) - assert varnames(F) == ((), ()) - - -@pytest.mark.skipif( - sys.version_info < (3,), reason="Keyword only arguments are Python 3 only" -) -def test_varnames_keyword_only(): - # SyntaxError on Python 2, so we exec - ns = {} - exec( - "def f1(x, *, y): pass\n" - "def f2(x, *, y=3): pass\n" - "def f3(x=1, *, y=3): pass\n", - ns, - ) - - assert varnames(ns["f1"]) == (("x",), ()) - assert varnames(ns["f2"]) == (("x",), ()) - assert varnames(ns["f3"]) == ((), ("x",)) - - -def test_formatdef(): - def function1(): - pass - - assert _formatdef(function1) == "function1()" - - def function2(arg1): - pass - - assert _formatdef(function2) == "function2(arg1)" - - def function3(arg1, arg2="qwe"): - pass - - assert _formatdef(function3) == "function3(arg1, arg2='qwe')" - - def function4(arg1, *args, **kwargs): - pass - - assert _formatdef(function4) == "function4(arg1, *args, **kwargs)" +from pluggy.hooks import varnames +from pluggy.manager import _formatdef + +import sys +import pytest + + +def test_varnames(): + def f(x): + i = 3 # noqa + + class A(object): + def f(self, y): + pass + + class B(object): + def __call__(self, z): + pass + + assert varnames(f) == (("x",), ()) + assert varnames(A().f) == (("y",), ()) + assert varnames(B()) == (("z",), ()) + + +def test_varnames_default(): + def f(x, y=3): + pass + + assert varnames(f) == (("x",), ("y",)) + + +def test_varnames_class(): + class C(object): + def __init__(self, x): + pass + + class D(object): + pass + + class E(object): + def __init__(self, x): + pass + + class F(object): + pass + + assert varnames(C) == (("x",), ()) + assert varnames(D) == ((), ()) + assert varnames(E) == (("x",), ()) + assert varnames(F) == ((), ()) + + +@pytest.mark.skipif( + sys.version_info < (3,), reason="Keyword only arguments are Python 3 only" +) +def test_varnames_keyword_only(): + # SyntaxError on Python 2, so we exec + ns = {} + exec( + "def f1(x, *, y): pass\n" + "def f2(x, *, y=3): pass\n" + "def f3(x=1, *, y=3): pass\n", + ns, + ) + + assert varnames(ns["f1"]) == (("x",), ()) + assert varnames(ns["f2"]) == (("x",), ()) + assert varnames(ns["f3"]) == ((), ("x",)) + + +def test_formatdef(): + def function1(): + pass + + assert _formatdef(function1) == "function1()" + + def function2(arg1): + pass + + assert _formatdef(function2) == "function2(arg1)" + + def function3(arg1, arg2="qwe"): + pass + + assert _formatdef(function3) == "function3(arg1, arg2='qwe')" + + def function4(arg1, *args, **kwargs): + pass + + assert _formatdef(function4) == "function4(arg1, *args, **kwargs)" diff --git a/contrib/python/pluggy/py2/tests/test_hookcaller.py b/contrib/python/pluggy/py2/tests/test_hookcaller.py index 87ab929f2f..5664f2bbf6 100644 --- a/contrib/python/pluggy/py2/tests/test_hookcaller.py +++ b/contrib/python/pluggy/py2/tests/test_hookcaller.py @@ -1,215 +1,215 @@ -import pytest - -from pluggy import HookimplMarker, HookspecMarker -from pluggy.hooks import HookImpl - -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_hookrelay_registry(pm): - """Verify hook caller instances are registered by name onto the relay - and can be likewise unregistered.""" - - class Api(object): - @hookspec - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - hook = pm.hook - assert hasattr(hook, "hello") - assert repr(hook.hello).find("hello") != -1 - - class Plugin(object): - @hookimpl - def hello(self, arg): - return arg + 1 - - plugin = Plugin() - pm.register(plugin) - out = hook.hello(arg=3) - assert out == [4] - assert not hasattr(hook, "world") - pm.unregister(plugin) - assert hook.hello(arg=3) == [] +import pytest + +from pluggy import HookimplMarker, HookspecMarker +from pluggy.hooks import HookImpl + +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_hookrelay_registry(pm): + """Verify hook caller instances are registered by name onto the relay + and can be likewise unregistered.""" + + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + hook = pm.hook + assert hasattr(hook, "hello") + assert repr(hook.hello).find("hello") != -1 + + class Plugin(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + plugin = Plugin() + pm.register(plugin) + out = hook.hello(arg=3) + assert out == [4] + assert not hasattr(hook, "world") + pm.unregister(plugin) + assert hook.hello(arg=3) == [] diff --git a/contrib/python/pluggy/py2/tests/test_invocations.py b/contrib/python/pluggy/py2/tests/test_invocations.py index 95d0be5bda..a6ec63cfc7 100644 --- a/contrib/python/pluggy/py2/tests/test_invocations.py +++ b/contrib/python/pluggy/py2/tests/test_invocations.py @@ -1,216 +1,216 @@ -import pytest -from pluggy import PluginValidationError, HookimplMarker, HookspecMarker - - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def test_argmismatch(pm): - class Api(object): - @hookspec - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - - class Plugin(object): - @hookimpl - def hello(self, argwrong): - pass - - with pytest.raises(PluginValidationError) as exc: - pm.register(Plugin()) - - assert "argwrong" in str(exc.value) - - -def test_only_kwargs(pm): - class Api(object): - @hookspec - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - with pytest.raises(TypeError) as exc: - pm.hook.hello(3) - - comprehensible = "hook calling supports only keyword arguments" - assert comprehensible in str(exc.value) - - -def test_opt_in_args(pm): - """Verfiy that two hookimpls with mutex args can serve - under the same spec. - """ - - class Api(object): - @hookspec - def hello(self, arg1, arg2, common_arg): - "api hook 1" - - class Plugin1(object): - @hookimpl - def hello(self, arg1, common_arg): - return arg1 + common_arg - - class Plugin2(object): - @hookimpl - def hello(self, arg2, common_arg): - return arg2 + common_arg - - pm.add_hookspecs(Api) - pm.register(Plugin1()) - pm.register(Plugin2()) - - results = pm.hook.hello(arg1=1, arg2=2, common_arg=0) - assert results == [2, 1] - - -def test_call_order(pm): - class Api(object): - @hookspec - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - - class Plugin1(object): - @hookimpl - def hello(self, arg): - return 1 - - class Plugin2(object): - @hookimpl - def hello(self, arg): - return 2 - - class Plugin3(object): - @hookimpl - def hello(self, arg): - return 3 - - class Plugin4(object): - @hookimpl(hookwrapper=True) - def hello(self, arg): - assert arg == 0 - outcome = yield - assert outcome.get_result() == [3, 2, 1] - - pm.register(Plugin1()) - pm.register(Plugin2()) - pm.register(Plugin3()) - pm.register(Plugin4()) # hookwrapper should get same list result - res = pm.hook.hello(arg=0) - assert res == [3, 2, 1] - - -def test_firstresult_definition(pm): - class Api(object): - @hookspec(firstresult=True) - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - - class Plugin1(object): - @hookimpl - def hello(self, arg): - return arg + 1 - - class Plugin2(object): - @hookimpl - def hello(self, arg): - return arg - 1 - - class Plugin3(object): - @hookimpl - def hello(self, arg): - return None - - class Plugin4(object): - @hookimpl(hookwrapper=True) - def hello(self, arg): - assert arg == 3 - outcome = yield - assert outcome.get_result() == 2 - - pm.register(Plugin1()) # discarded - not the last registered plugin - pm.register(Plugin2()) # used as result - pm.register(Plugin3()) # None result is ignored - pm.register(Plugin4()) # hookwrapper should get same non-list result - res = pm.hook.hello(arg=3) - assert res == 2 - - -def test_firstresult_force_result(pm): - """Verify forcing a result in a wrapper. - """ - - class Api(object): - @hookspec(firstresult=True) - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - - class Plugin1(object): - @hookimpl - def hello(self, arg): - return arg + 1 - - class Plugin2(object): - @hookimpl(hookwrapper=True) - def hello(self, arg): - assert arg == 3 - outcome = yield - assert outcome.get_result() == 4 - outcome.force_result(0) - - class Plugin3(object): - @hookimpl - def hello(self, arg): - return None - - pm.register(Plugin1()) - pm.register(Plugin2()) # wrapper - pm.register(Plugin3()) # ignored since returns None - res = pm.hook.hello(arg=3) - assert res == 0 # this result is forced and not a list - - -def test_firstresult_returns_none(pm): - """If None results are returned by underlying implementations ensure - the multi-call loop returns a None value. - """ - - class Api(object): - @hookspec(firstresult=True) - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - - class Plugin1(object): - @hookimpl - def hello(self, arg): - return None - - pm.register(Plugin1()) - res = pm.hook.hello(arg=3) - assert res is None - - -def test_firstresult_no_plugin(pm): - """If no implementations/plugins have been registered for a firstresult - hook the multi-call loop should return a None value. - """ - - class Api(object): - @hookspec(firstresult=True) - def hello(self, arg): - "api hook 1" - - pm.add_hookspecs(Api) - res = pm.hook.hello(arg=3) - assert res is None +import pytest +from pluggy import PluginValidationError, HookimplMarker, HookspecMarker + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_argmismatch(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin(object): + @hookimpl + def hello(self, argwrong): + pass + + with pytest.raises(PluginValidationError) as exc: + pm.register(Plugin()) + + assert "argwrong" in str(exc.value) + + +def test_only_kwargs(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + with pytest.raises(TypeError) as exc: + pm.hook.hello(3) + + comprehensible = "hook calling supports only keyword arguments" + assert comprehensible in str(exc.value) + + +def test_opt_in_args(pm): + """Verfiy that two hookimpls with mutex args can serve + under the same spec. + """ + + class Api(object): + @hookspec + def hello(self, arg1, arg2, common_arg): + "api hook 1" + + class Plugin1(object): + @hookimpl + def hello(self, arg1, common_arg): + return arg1 + common_arg + + class Plugin2(object): + @hookimpl + def hello(self, arg2, common_arg): + return arg2 + common_arg + + pm.add_hookspecs(Api) + pm.register(Plugin1()) + pm.register(Plugin2()) + + results = pm.hook.hello(arg1=1, arg2=2, common_arg=0) + assert results == [2, 1] + + +def test_call_order(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return 1 + + class Plugin2(object): + @hookimpl + def hello(self, arg): + return 2 + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return 3 + + class Plugin4(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 0 + outcome = yield + assert outcome.get_result() == [3, 2, 1] + + pm.register(Plugin1()) + pm.register(Plugin2()) + pm.register(Plugin3()) + pm.register(Plugin4()) # hookwrapper should get same list result + res = pm.hook.hello(arg=0) + assert res == [3, 2, 1] + + +def test_firstresult_definition(pm): + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + class Plugin2(object): + @hookimpl + def hello(self, arg): + return arg - 1 + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return None + + class Plugin4(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 3 + outcome = yield + assert outcome.get_result() == 2 + + pm.register(Plugin1()) # discarded - not the last registered plugin + pm.register(Plugin2()) # used as result + pm.register(Plugin3()) # None result is ignored + pm.register(Plugin4()) # hookwrapper should get same non-list result + res = pm.hook.hello(arg=3) + assert res == 2 + + +def test_firstresult_force_result(pm): + """Verify forcing a result in a wrapper. + """ + + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return arg + 1 + + class Plugin2(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 3 + outcome = yield + assert outcome.get_result() == 4 + outcome.force_result(0) + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return None + + pm.register(Plugin1()) + pm.register(Plugin2()) # wrapper + pm.register(Plugin3()) # ignored since returns None + res = pm.hook.hello(arg=3) + assert res == 0 # this result is forced and not a list + + +def test_firstresult_returns_none(pm): + """If None results are returned by underlying implementations ensure + the multi-call loop returns a None value. + """ + + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return None + + pm.register(Plugin1()) + res = pm.hook.hello(arg=3) + assert res is None + + +def test_firstresult_no_plugin(pm): + """If no implementations/plugins have been registered for a firstresult + hook the multi-call loop should return a None value. + """ + + class Api(object): + @hookspec(firstresult=True) + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + res = pm.hook.hello(arg=3) + assert res is None diff --git a/contrib/python/pluggy/py2/tests/test_multicall.py b/contrib/python/pluggy/py2/tests/test_multicall.py index 7a6f0a87ec..eaf534a016 100644 --- a/contrib/python/pluggy/py2/tests/test_multicall.py +++ b/contrib/python/pluggy/py2/tests/test_multicall.py @@ -1,186 +1,186 @@ -import pytest -from pluggy import HookCallError, HookspecMarker, HookimplMarker -from pluggy.hooks import HookImpl -from pluggy.callers import _multicall, _legacymulticall - - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def MC(methods, kwargs, firstresult=False): - caller = _multicall - hookfuncs = [] - for method in methods: - f = HookImpl(None, "<temp>", method, method.example_impl) - hookfuncs.append(f) - if "__multicall__" in f.argnames: - caller = _legacymulticall - return caller(hookfuncs, kwargs, firstresult=firstresult) - - -def test_call_passing(): - class P1(object): - @hookimpl - def m(self, __multicall__, x): - assert len(__multicall__.results) == 1 - assert not __multicall__.hook_impls - return 17 - - class P2(object): - @hookimpl - def m(self, __multicall__, x): - assert __multicall__.results == [] - assert __multicall__.hook_impls - return 23 - - p1 = P1() - p2 = P2() - reslist = MC([p1.m, p2.m], {"x": 23}) - assert len(reslist) == 2 - # ensure reversed order - assert reslist == [23, 17] - - -def test_keyword_args(): - @hookimpl - def f(x): - return x + 1 - - class A(object): - @hookimpl - def f(self, x, y): - return x + y - - reslist = MC([f, A().f], dict(x=23, y=24)) - assert reslist == [24 + 23, 24] - - -def test_keyword_args_with_defaultargs(): - @hookimpl - def f(x, z=1): - return x + z - - reslist = MC([f], dict(x=23, y=24)) - assert reslist == [24] - - -def test_tags_call_error(): - @hookimpl - def f(x): - return x - - with pytest.raises(HookCallError): - MC([f], {}) - - -def test_call_subexecute(): - @hookimpl - def m(__multicall__): - subresult = __multicall__.execute() - return subresult + 1 - - @hookimpl - def n(): - return 1 - - res = MC([n, m], {}, firstresult=True) - assert res == 2 - - -def test_call_none_is_no_result(): - @hookimpl - def m1(): - return 1 - - @hookimpl - def m2(): - return None - - res = MC([m1, m2], {}, firstresult=True) - assert res == 1 - res = MC([m1, m2], {}, {}) - assert res == [1] - - -def test_hookwrapper(): - out = [] - - @hookimpl(hookwrapper=True) - def m1(): - out.append("m1 init") - yield None - out.append("m1 finish") - - @hookimpl - def m2(): - out.append("m2") - return 2 - - res = MC([m2, m1], {}) - assert res == [2] - assert out == ["m1 init", "m2", "m1 finish"] - out[:] = [] - res = MC([m2, m1], {}, firstresult=True) - assert res == 2 - assert out == ["m1 init", "m2", "m1 finish"] - - -def test_hookwrapper_order(): - out = [] - - @hookimpl(hookwrapper=True) - def m1(): - out.append("m1 init") - yield 1 - out.append("m1 finish") - - @hookimpl(hookwrapper=True) - def m2(): - out.append("m2 init") - yield 2 - out.append("m2 finish") - - res = MC([m2, m1], {}) - assert res == [] - assert out == ["m1 init", "m2 init", "m2 finish", "m1 finish"] - - -def test_hookwrapper_not_yield(): - @hookimpl(hookwrapper=True) - def m1(): - pass - - with pytest.raises(TypeError): - MC([m1], {}) - - -def test_hookwrapper_too_many_yield(): - @hookimpl(hookwrapper=True) - def m1(): - yield 1 - yield 2 - - with pytest.raises(RuntimeError) as ex: - MC([m1], {}) - assert "m1" in str(ex.value) - assert (__file__ + ":") in str(ex.value) - - -@pytest.mark.parametrize("exc", [ValueError, SystemExit]) -def test_hookwrapper_exception(exc): - out = [] - - @hookimpl(hookwrapper=True) - def m1(): - out.append("m1 init") - yield None - out.append("m1 finish") - - @hookimpl - def m2(): - raise exc - - with pytest.raises(exc): - MC([m2, m1], {}) - assert out == ["m1 init", "m1 finish"] +import pytest +from pluggy import HookCallError, HookspecMarker, HookimplMarker +from pluggy.hooks import HookImpl +from pluggy.callers import _multicall, _legacymulticall + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def MC(methods, kwargs, firstresult=False): + caller = _multicall + hookfuncs = [] + for method in methods: + f = HookImpl(None, "<temp>", method, method.example_impl) + hookfuncs.append(f) + if "__multicall__" in f.argnames: + caller = _legacymulticall + return caller(hookfuncs, kwargs, firstresult=firstresult) + + +def test_call_passing(): + class P1(object): + @hookimpl + def m(self, __multicall__, x): + assert len(__multicall__.results) == 1 + assert not __multicall__.hook_impls + return 17 + + class P2(object): + @hookimpl + def m(self, __multicall__, x): + assert __multicall__.results == [] + assert __multicall__.hook_impls + return 23 + + p1 = P1() + p2 = P2() + reslist = MC([p1.m, p2.m], {"x": 23}) + assert len(reslist) == 2 + # ensure reversed order + assert reslist == [23, 17] + + +def test_keyword_args(): + @hookimpl + def f(x): + return x + 1 + + class A(object): + @hookimpl + def f(self, x, y): + return x + y + + reslist = MC([f, A().f], dict(x=23, y=24)) + assert reslist == [24 + 23, 24] + + +def test_keyword_args_with_defaultargs(): + @hookimpl + def f(x, z=1): + return x + z + + reslist = MC([f], dict(x=23, y=24)) + assert reslist == [24] + + +def test_tags_call_error(): + @hookimpl + def f(x): + return x + + with pytest.raises(HookCallError): + MC([f], {}) + + +def test_call_subexecute(): + @hookimpl + def m(__multicall__): + subresult = __multicall__.execute() + return subresult + 1 + + @hookimpl + def n(): + return 1 + + res = MC([n, m], {}, firstresult=True) + assert res == 2 + + +def test_call_none_is_no_result(): + @hookimpl + def m1(): + return 1 + + @hookimpl + def m2(): + return None + + res = MC([m1, m2], {}, firstresult=True) + assert res == 1 + res = MC([m1, m2], {}, {}) + assert res == [1] + + +def test_hookwrapper(): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield None + out.append("m1 finish") + + @hookimpl + def m2(): + out.append("m2") + return 2 + + res = MC([m2, m1], {}) + assert res == [2] + assert out == ["m1 init", "m2", "m1 finish"] + out[:] = [] + res = MC([m2, m1], {}, firstresult=True) + assert res == 2 + assert out == ["m1 init", "m2", "m1 finish"] + + +def test_hookwrapper_order(): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield 1 + out.append("m1 finish") + + @hookimpl(hookwrapper=True) + def m2(): + out.append("m2 init") + yield 2 + out.append("m2 finish") + + res = MC([m2, m1], {}) + assert res == [] + assert out == ["m1 init", "m2 init", "m2 finish", "m1 finish"] + + +def test_hookwrapper_not_yield(): + @hookimpl(hookwrapper=True) + def m1(): + pass + + with pytest.raises(TypeError): + MC([m1], {}) + + +def test_hookwrapper_too_many_yield(): + @hookimpl(hookwrapper=True) + def m1(): + yield 1 + yield 2 + + with pytest.raises(RuntimeError) as ex: + MC([m1], {}) + assert "m1" in str(ex.value) + assert (__file__ + ":") in str(ex.value) + + +@pytest.mark.parametrize("exc", [ValueError, SystemExit]) +def test_hookwrapper_exception(exc): + out = [] + + @hookimpl(hookwrapper=True) + def m1(): + out.append("m1 init") + yield None + out.append("m1 finish") + + @hookimpl + def m2(): + raise exc + + with pytest.raises(exc): + MC([m2, m1], {}) + assert out == ["m1 init", "m1 finish"] diff --git a/contrib/python/pluggy/py2/tests/test_pluginmanager.py b/contrib/python/pluggy/py2/tests/test_pluginmanager.py index 09d83ab9d4..67261aaa7b 100644 --- a/contrib/python/pluggy/py2/tests/test_pluginmanager.py +++ b/contrib/python/pluggy/py2/tests/test_pluginmanager.py @@ -1,600 +1,600 @@ -""" -``PluginManager`` unit and public API testing. -""" -import pytest -import types - -from pluggy import ( - PluginManager, - PluginValidationError, - HookCallError, - HookimplMarker, - HookspecMarker, -) -from pluggy.manager import importlib_metadata - - -hookspec = HookspecMarker("example") -hookimpl = HookimplMarker("example") - - -def test_plugin_double_register(pm): - """Registering the same plugin more then once isn't allowed""" - pm.register(42, name="abc") - with pytest.raises(ValueError): - pm.register(42, name="abc") - with pytest.raises(ValueError): - pm.register(42, name="def") - - -def test_pm(pm): - """Basic registration with objects""" - - class A(object): - pass - - a1, a2 = A(), A() - pm.register(a1) - assert pm.is_registered(a1) - pm.register(a2, "hello") - assert pm.is_registered(a2) - out = pm.get_plugins() - assert a1 in out - assert a2 in out - assert pm.get_plugin("hello") == a2 - assert pm.unregister(a1) == a1 - assert not pm.is_registered(a1) - - out = pm.list_name_plugin() - assert len(out) == 1 - assert out == [("hello", a2)] - - -def test_has_plugin(pm): - class A(object): - pass - - a1 = A() - pm.register(a1, "hello") - assert pm.is_registered(a1) - assert pm.has_plugin("hello") - - -def test_register_dynamic_attr(he_pm): - class A(object): - def __getattr__(self, name): - if name[0] != "_": - return 42 - raise AttributeError() - - a = A() - he_pm.register(a) - assert not he_pm.get_hookcallers(a) - - -def test_pm_name(pm): - class A(object): - pass - - a1 = A() - name = pm.register(a1, name="hello") - assert name == "hello" - pm.unregister(a1) - assert pm.get_plugin(a1) is None - assert not pm.is_registered(a1) - assert not pm.get_plugins() - name2 = pm.register(a1, name="hello") - assert name2 == name - pm.unregister(name="hello") - assert pm.get_plugin(a1) is None - assert not pm.is_registered(a1) - assert not pm.get_plugins() - - -def test_set_blocked(pm): - class A(object): - pass - - a1 = A() - name = pm.register(a1) - assert pm.is_registered(a1) - assert not pm.is_blocked(name) - pm.set_blocked(name) - assert pm.is_blocked(name) - assert not pm.is_registered(a1) - - pm.set_blocked("somename") - assert pm.is_blocked("somename") - assert not pm.register(A(), "somename") - pm.unregister(name="somename") - assert pm.is_blocked("somename") - - -def test_register_mismatch_method(he_pm): - class hello(object): - @hookimpl - def he_method_notexists(self): - pass - - plugin = hello() - - he_pm.register(plugin) - with pytest.raises(PluginValidationError) as excinfo: - he_pm.check_pending() - assert excinfo.value.plugin is plugin - - -def test_register_mismatch_arg(he_pm): - class hello(object): - @hookimpl - def he_method1(self, qlwkje): - pass - - plugin = hello() - - with pytest.raises(PluginValidationError) as excinfo: - he_pm.register(plugin) - assert excinfo.value.plugin is plugin - - -def test_register(pm): - class MyPlugin(object): - pass - - my = MyPlugin() - pm.register(my) - assert my in pm.get_plugins() - my2 = MyPlugin() - pm.register(my2) - assert set([my, my2]).issubset(pm.get_plugins()) - - assert pm.is_registered(my) - assert pm.is_registered(my2) - pm.unregister(my) - assert not pm.is_registered(my) - assert my not in pm.get_plugins() - - -def test_register_unknown_hooks(pm): - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - return arg + 1 - - pname = pm.register(Plugin1()) - - class Hooks(object): - @hookspec - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - # assert not pm._unverified_hooks - assert pm.hook.he_method1(arg=1) == [2] - assert len(pm.get_hookcallers(pm.get_plugin(pname))) == 1 - - -def test_register_historic(pm): - class Hooks(object): - @hookspec(historic=True) - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - pm.hook.he_method1.call_historic(kwargs=dict(arg=1)) - out = [] - - class Plugin(object): - @hookimpl - def he_method1(self, arg): - out.append(arg) - - pm.register(Plugin()) - assert out == [1] - - class Plugin2(object): - @hookimpl - def he_method1(self, arg): - out.append(arg * 10) - - pm.register(Plugin2()) - assert out == [1, 10] - pm.hook.he_method1.call_historic(kwargs=dict(arg=12)) - assert out == [1, 10, 120, 12] - - -@pytest.mark.parametrize("result_callback", [True, False]) -def test_with_result_memorized(pm, result_callback): - """Verify that ``_HookCaller._maybe_apply_history()` - correctly applies the ``result_callback`` function, when provided, - to the result from calling each newly registered hook. - """ - out = [] - if result_callback: - - def callback(res): - out.append(res) - - else: - callback = None - - class Hooks(object): - @hookspec(historic=True) - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - return arg * 10 - - pm.register(Plugin1()) - - he_method1 = pm.hook.he_method1 - he_method1.call_historic(result_callback=callback, kwargs=dict(arg=1)) - - class Plugin2(object): - @hookimpl - def he_method1(self, arg): - return arg * 10 - - pm.register(Plugin2()) - if result_callback: - assert out == [10, 10] - else: - assert out == [] - - -def test_with_callbacks_immediately_executed(pm): - class Hooks(object): - @hookspec(historic=True) - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - return arg * 10 - - class Plugin2(object): - @hookimpl - def he_method1(self, arg): - return arg * 20 - - class Plugin3(object): - @hookimpl - def he_method1(self, arg): - return arg * 30 - - out = [] - pm.register(Plugin1()) - pm.register(Plugin2()) - - he_method1 = pm.hook.he_method1 - he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) - assert out == [20, 10] - pm.register(Plugin3()) - assert out == [20, 10, 30] - - -def test_register_historic_incompat_hookwrapper(pm): - class Hooks(object): - @hookspec(historic=True) - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - out = [] - - class Plugin(object): - @hookimpl(hookwrapper=True) - def he_method1(self, arg): - out.append(arg) - - with pytest.raises(PluginValidationError): - pm.register(Plugin()) - - -def test_call_extra(pm): - class Hooks(object): - @hookspec - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - def he_method1(arg): - return arg * 10 - - out = pm.hook.he_method1.call_extra([he_method1], dict(arg=1)) - assert out == [10] - - -def test_call_with_too_few_args(pm): - class Hooks(object): - @hookspec - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - 0 / 0 - - pm.register(Plugin1()) - with pytest.raises(HookCallError): - with pytest.warns(UserWarning): - pm.hook.he_method1() - - -def test_subset_hook_caller(pm): - class Hooks(object): - @hookspec - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - - out = [] - - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - out.append(arg) - - class Plugin2(object): - @hookimpl - def he_method1(self, arg): - out.append(arg * 10) - - class PluginNo(object): - pass - - plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo() - pm.register(plugin1) - pm.register(plugin2) - pm.register(plugin3) - pm.hook.he_method1(arg=1) - assert out == [10, 1] - out[:] = [] - - hc = pm.subset_hook_caller("he_method1", [plugin1]) - hc(arg=2) - assert out == [20] - out[:] = [] - - hc = pm.subset_hook_caller("he_method1", [plugin2]) - hc(arg=2) - assert out == [2] - out[:] = [] - - pm.unregister(plugin1) - hc(arg=2) - assert out == [] - out[:] = [] - - pm.hook.he_method1(arg=1) - assert out == [10] - - -def test_get_hookimpls(pm): - class Hooks(object): - @hookspec - def he_method1(self, arg): - pass - - pm.add_hookspecs(Hooks) - assert pm.hook.he_method1.get_hookimpls() == [] - - class Plugin1(object): - @hookimpl - def he_method1(self, arg): - pass - - class Plugin2(object): - @hookimpl - def he_method1(self, arg): - pass - - class PluginNo(object): - pass - - plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo() - pm.register(plugin1) - pm.register(plugin2) - pm.register(plugin3) - - hookimpls = pm.hook.he_method1.get_hookimpls() - hook_plugins = [item.plugin for item in hookimpls] - assert hook_plugins == [plugin1, plugin2] - - -def test_add_hookspecs_nohooks(pm): - with pytest.raises(ValueError): - pm.add_hookspecs(10) - - -def test_reject_prefixed_module(pm): - """Verify that a module type attribute that contains the project - prefix in its name (in this case `'example_*'` isn't collected - when registering a module which imports it. - """ - pm._implprefix = "example" - conftest = types.ModuleType("conftest") - src = """ -def example_hook(): - pass -""" - exec(src, conftest.__dict__) - conftest.example_blah = types.ModuleType("example_blah") - with pytest.deprecated_call(): - name = pm.register(conftest) - assert name == "conftest" - assert getattr(pm.hook, "example_blah", None) is None - assert getattr( - pm.hook, "example_hook", None - ) # conftest.example_hook should be collected - with pytest.deprecated_call(): - assert pm.parse_hookimpl_opts(conftest, "example_blah") is None - assert pm.parse_hookimpl_opts(conftest, "example_hook") == {} - - -def test_load_setuptools_instantiation(monkeypatch, pm): - class EntryPoint(object): - name = "myname" - group = "hello" - value = "myname:foo" - - def load(self): - class PseudoPlugin(object): - x = 42 - - return PseudoPlugin() - - class Distribution(object): - entry_points = (EntryPoint(),) - - dist = Distribution() - - def my_distributions(): - return (dist,) - - monkeypatch.setattr(importlib_metadata, "distributions", my_distributions) - num = pm.load_setuptools_entrypoints("hello") - assert num == 1 - plugin = pm.get_plugin("myname") - assert plugin.x == 42 - ret = pm.list_plugin_distinfo() - # poor man's `assert ret == [(plugin, mock.ANY)]` - assert len(ret) == 1 - assert len(ret[0]) == 2 - assert ret[0][0] == plugin - assert ret[0][1]._dist == dist - num = pm.load_setuptools_entrypoints("hello") - assert num == 0 # no plugin loaded by this call - - -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() - - -def test_implprefix_warning(recwarn): - PluginManager(hookspec.project_name, "hello_") - w = recwarn.pop(DeprecationWarning) - assert "test_pluginmanager.py" in w.filename - - -@pytest.mark.parametrize("include_hookspec", [True, False]) -def test_prefix_hookimpl(include_hookspec): - with pytest.deprecated_call(): - 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 - - with pytest.deprecated_call(): - pm.register(Plugin()) - pm.register(Plugin()) - results = pm.hook.hello_myhook(arg1=17) - assert results == [18, 18] - - -def test_prefix_hookimpl_dontmatch_module(): - with pytest.deprecated_call(): - pm = PluginManager(hookspec.project_name, "hello_") - - class BadPlugin(object): - hello_module = __import__("email") - - pm.register(BadPlugin()) - pm.check_pending() +""" +``PluginManager`` unit and public API testing. +""" +import pytest +import types + +from pluggy import ( + PluginManager, + PluginValidationError, + HookCallError, + HookimplMarker, + HookspecMarker, +) +from pluggy.manager import importlib_metadata + + +hookspec = HookspecMarker("example") +hookimpl = HookimplMarker("example") + + +def test_plugin_double_register(pm): + """Registering the same plugin more then once isn't allowed""" + pm.register(42, name="abc") + with pytest.raises(ValueError): + pm.register(42, name="abc") + with pytest.raises(ValueError): + pm.register(42, name="def") + + +def test_pm(pm): + """Basic registration with objects""" + + class A(object): + pass + + a1, a2 = A(), A() + pm.register(a1) + assert pm.is_registered(a1) + pm.register(a2, "hello") + assert pm.is_registered(a2) + out = pm.get_plugins() + assert a1 in out + assert a2 in out + assert pm.get_plugin("hello") == a2 + assert pm.unregister(a1) == a1 + assert not pm.is_registered(a1) + + out = pm.list_name_plugin() + assert len(out) == 1 + assert out == [("hello", a2)] + + +def test_has_plugin(pm): + class A(object): + pass + + a1 = A() + pm.register(a1, "hello") + assert pm.is_registered(a1) + assert pm.has_plugin("hello") + + +def test_register_dynamic_attr(he_pm): + class A(object): + def __getattr__(self, name): + if name[0] != "_": + return 42 + raise AttributeError() + + a = A() + he_pm.register(a) + assert not he_pm.get_hookcallers(a) + + +def test_pm_name(pm): + class A(object): + pass + + a1 = A() + name = pm.register(a1, name="hello") + assert name == "hello" + pm.unregister(a1) + assert pm.get_plugin(a1) is None + assert not pm.is_registered(a1) + assert not pm.get_plugins() + name2 = pm.register(a1, name="hello") + assert name2 == name + pm.unregister(name="hello") + assert pm.get_plugin(a1) is None + assert not pm.is_registered(a1) + assert not pm.get_plugins() + + +def test_set_blocked(pm): + class A(object): + pass + + a1 = A() + name = pm.register(a1) + assert pm.is_registered(a1) + assert not pm.is_blocked(name) + pm.set_blocked(name) + assert pm.is_blocked(name) + assert not pm.is_registered(a1) + + pm.set_blocked("somename") + assert pm.is_blocked("somename") + assert not pm.register(A(), "somename") + pm.unregister(name="somename") + assert pm.is_blocked("somename") + + +def test_register_mismatch_method(he_pm): + class hello(object): + @hookimpl + def he_method_notexists(self): + pass + + plugin = hello() + + he_pm.register(plugin) + with pytest.raises(PluginValidationError) as excinfo: + he_pm.check_pending() + assert excinfo.value.plugin is plugin + + +def test_register_mismatch_arg(he_pm): + class hello(object): + @hookimpl + def he_method1(self, qlwkje): + pass + + plugin = hello() + + with pytest.raises(PluginValidationError) as excinfo: + he_pm.register(plugin) + assert excinfo.value.plugin is plugin + + +def test_register(pm): + class MyPlugin(object): + pass + + my = MyPlugin() + pm.register(my) + assert my in pm.get_plugins() + my2 = MyPlugin() + pm.register(my2) + assert set([my, my2]).issubset(pm.get_plugins()) + + assert pm.is_registered(my) + assert pm.is_registered(my2) + pm.unregister(my) + assert not pm.is_registered(my) + assert my not in pm.get_plugins() + + +def test_register_unknown_hooks(pm): + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + return arg + 1 + + pname = pm.register(Plugin1()) + + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + # assert not pm._unverified_hooks + assert pm.hook.he_method1(arg=1) == [2] + assert len(pm.get_hookcallers(pm.get_plugin(pname))) == 1 + + +def test_register_historic(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + pm.hook.he_method1.call_historic(kwargs=dict(arg=1)) + out = [] + + class Plugin(object): + @hookimpl + def he_method1(self, arg): + out.append(arg) + + pm.register(Plugin()) + assert out == [1] + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + out.append(arg * 10) + + pm.register(Plugin2()) + assert out == [1, 10] + pm.hook.he_method1.call_historic(kwargs=dict(arg=12)) + assert out == [1, 10, 120, 12] + + +@pytest.mark.parametrize("result_callback", [True, False]) +def test_with_result_memorized(pm, result_callback): + """Verify that ``_HookCaller._maybe_apply_history()` + correctly applies the ``result_callback`` function, when provided, + to the result from calling each newly registered hook. + """ + out = [] + if result_callback: + + def callback(res): + out.append(res) + + else: + callback = None + + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + return arg * 10 + + pm.register(Plugin1()) + + he_method1 = pm.hook.he_method1 + he_method1.call_historic(result_callback=callback, kwargs=dict(arg=1)) + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + return arg * 10 + + pm.register(Plugin2()) + if result_callback: + assert out == [10, 10] + else: + assert out == [] + + +def test_with_callbacks_immediately_executed(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + return arg * 10 + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + return arg * 20 + + class Plugin3(object): + @hookimpl + def he_method1(self, arg): + return arg * 30 + + out = [] + pm.register(Plugin1()) + pm.register(Plugin2()) + + he_method1 = pm.hook.he_method1 + he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) + assert out == [20, 10] + pm.register(Plugin3()) + assert out == [20, 10, 30] + + +def test_register_historic_incompat_hookwrapper(pm): + class Hooks(object): + @hookspec(historic=True) + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + out = [] + + class Plugin(object): + @hookimpl(hookwrapper=True) + def he_method1(self, arg): + out.append(arg) + + with pytest.raises(PluginValidationError): + pm.register(Plugin()) + + +def test_call_extra(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + def he_method1(arg): + return arg * 10 + + out = pm.hook.he_method1.call_extra([he_method1], dict(arg=1)) + assert out == [10] + + +def test_call_with_too_few_args(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + 0 / 0 + + pm.register(Plugin1()) + with pytest.raises(HookCallError): + with pytest.warns(UserWarning): + pm.hook.he_method1() + + +def test_subset_hook_caller(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + out = [] + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + out.append(arg) + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + out.append(arg * 10) + + class PluginNo(object): + pass + + plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo() + pm.register(plugin1) + pm.register(plugin2) + pm.register(plugin3) + pm.hook.he_method1(arg=1) + assert out == [10, 1] + out[:] = [] + + hc = pm.subset_hook_caller("he_method1", [plugin1]) + hc(arg=2) + assert out == [20] + out[:] = [] + + hc = pm.subset_hook_caller("he_method1", [plugin2]) + hc(arg=2) + assert out == [2] + out[:] = [] + + pm.unregister(plugin1) + hc(arg=2) + assert out == [] + out[:] = [] + + pm.hook.he_method1(arg=1) + assert out == [10] + + +def test_get_hookimpls(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + assert pm.hook.he_method1.get_hookimpls() == [] + + class Plugin1(object): + @hookimpl + def he_method1(self, arg): + pass + + class Plugin2(object): + @hookimpl + def he_method1(self, arg): + pass + + class PluginNo(object): + pass + + plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo() + pm.register(plugin1) + pm.register(plugin2) + pm.register(plugin3) + + hookimpls = pm.hook.he_method1.get_hookimpls() + hook_plugins = [item.plugin for item in hookimpls] + assert hook_plugins == [plugin1, plugin2] + + +def test_add_hookspecs_nohooks(pm): + with pytest.raises(ValueError): + pm.add_hookspecs(10) + + +def test_reject_prefixed_module(pm): + """Verify that a module type attribute that contains the project + prefix in its name (in this case `'example_*'` isn't collected + when registering a module which imports it. + """ + pm._implprefix = "example" + conftest = types.ModuleType("conftest") + src = """ +def example_hook(): + pass +""" + exec(src, conftest.__dict__) + conftest.example_blah = types.ModuleType("example_blah") + with pytest.deprecated_call(): + name = pm.register(conftest) + assert name == "conftest" + assert getattr(pm.hook, "example_blah", None) is None + assert getattr( + pm.hook, "example_hook", None + ) # conftest.example_hook should be collected + with pytest.deprecated_call(): + assert pm.parse_hookimpl_opts(conftest, "example_blah") is None + assert pm.parse_hookimpl_opts(conftest, "example_hook") == {} + + +def test_load_setuptools_instantiation(monkeypatch, pm): + class EntryPoint(object): + name = "myname" + group = "hello" + value = "myname:foo" + + def load(self): + class PseudoPlugin(object): + x = 42 + + return PseudoPlugin() + + class Distribution(object): + entry_points = (EntryPoint(),) + + dist = Distribution() + + def my_distributions(): + return (dist,) + + monkeypatch.setattr(importlib_metadata, "distributions", my_distributions) + num = pm.load_setuptools_entrypoints("hello") + assert num == 1 + plugin = pm.get_plugin("myname") + assert plugin.x == 42 + ret = pm.list_plugin_distinfo() + # poor man's `assert ret == [(plugin, mock.ANY)]` + assert len(ret) == 1 + assert len(ret[0]) == 2 + assert ret[0][0] == plugin + assert ret[0][1]._dist == dist + num = pm.load_setuptools_entrypoints("hello") + assert num == 0 # no plugin loaded by this call + + +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() + + +def test_implprefix_warning(recwarn): + PluginManager(hookspec.project_name, "hello_") + w = recwarn.pop(DeprecationWarning) + assert "test_pluginmanager.py" in w.filename + + +@pytest.mark.parametrize("include_hookspec", [True, False]) +def test_prefix_hookimpl(include_hookspec): + with pytest.deprecated_call(): + 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 + + with pytest.deprecated_call(): + pm.register(Plugin()) + pm.register(Plugin()) + results = pm.hook.hello_myhook(arg1=17) + assert results == [18, 18] + + +def test_prefix_hookimpl_dontmatch_module(): + with pytest.deprecated_call(): + pm = PluginManager(hookspec.project_name, "hello_") + + class BadPlugin(object): + hello_module = __import__("email") + + pm.register(BadPlugin()) + pm.check_pending() diff --git a/contrib/python/pluggy/py2/tests/test_tracer.py b/contrib/python/pluggy/py2/tests/test_tracer.py index 7915f0ee75..992ec67914 100644 --- a/contrib/python/pluggy/py2/tests/test_tracer.py +++ b/contrib/python/pluggy/py2/tests/test_tracer.py @@ -1,78 +1,78 @@ -from pluggy._tracing import TagTracer - -import pytest - - -@pytest.fixture -def rootlogger(): - return TagTracer() - - -def test_simple(rootlogger): - log = rootlogger.get("pytest") - log("hello") - out = [] - rootlogger.setwriter(out.append) - log("world") - assert len(out) == 1 - assert out[0] == "world [pytest]\n" - sublog = log.get("collection") - sublog("hello") - assert out[1] == "hello [pytest:collection]\n" - - -def test_indent(rootlogger): - log = rootlogger.get("1") - out = [] - log.root.setwriter(lambda arg: out.append(arg)) - log("hello") - log.root.indent += 1 - log("line1") - log("line2") - log.root.indent += 1 - log("line3") - log("line4") - log.root.indent -= 1 - log("line5") - log.root.indent -= 1 - log("last") - assert len(out) == 7 - names = [x[: x.rfind(" [")] for x in out] - assert names == [ - "hello", - " line1", - " line2", - " line3", - " line4", - " line5", - "last", - ] - - -def test_readable_output_dictargs(rootlogger): - - out = rootlogger._format_message(["test"], [1]) - assert out == "1 [test]\n" - - out2 = rootlogger._format_message(["test"], ["test", {"a": 1}]) - assert out2 == "test [test]\n a: 1\n" - - -def test_setprocessor(rootlogger): - log = rootlogger.get("1") - log2 = log.get("2") - assert log2.tags == tuple("12") - out = [] - rootlogger.setprocessor(tuple("12"), lambda *args: out.append(args)) - log("not seen") - log2("seen") - assert len(out) == 1 - tags, args = out[0] - assert "1" in tags - assert "2" in tags - assert args == ("seen",) - l2 = [] - rootlogger.setprocessor("1:2", lambda *args: l2.append(args)) - log2("seen") - tags, args = l2[0] - assert args == ("seen",) +from pluggy._tracing import TagTracer + +import pytest + + +@pytest.fixture +def rootlogger(): + return TagTracer() + + +def test_simple(rootlogger): + log = rootlogger.get("pytest") + log("hello") + out = [] + rootlogger.setwriter(out.append) + log("world") + assert len(out) == 1 + assert out[0] == "world [pytest]\n" + sublog = log.get("collection") + sublog("hello") + assert out[1] == "hello [pytest:collection]\n" + + +def test_indent(rootlogger): + log = rootlogger.get("1") + out = [] + log.root.setwriter(lambda arg: out.append(arg)) + log("hello") + log.root.indent += 1 + log("line1") + log("line2") + log.root.indent += 1 + log("line3") + log("line4") + log.root.indent -= 1 + log("line5") + log.root.indent -= 1 + log("last") + assert len(out) == 7 + names = [x[: x.rfind(" [")] for x in out] + assert names == [ + "hello", + " line1", + " line2", + " line3", + " line4", + " line5", + "last", + ] + + +def test_readable_output_dictargs(rootlogger): + + out = rootlogger._format_message(["test"], [1]) + assert out == "1 [test]\n" + + out2 = rootlogger._format_message(["test"], ["test", {"a": 1}]) + assert out2 == "test [test]\n a: 1\n" + + +def test_setprocessor(rootlogger): + log = rootlogger.get("1") + log2 = log.get("2") + assert log2.tags == tuple("12") + out = [] + rootlogger.setprocessor(tuple("12"), lambda *args: out.append(args)) + log("not seen") + log2("seen") + assert len(out) == 1 + tags, args = out[0] + assert "1" in tags + assert "2" in tags + assert args == ("seen",) + l2 = [] + rootlogger.setprocessor("1:2", lambda *args: l2.append(args)) + log2("seen") + tags, args = l2[0] + assert args == ("seen",) diff --git a/contrib/python/pluggy/py2/tests/ya.make b/contrib/python/pluggy/py2/tests/ya.make index 2091a66adf..a0bd221149 100644 --- a/contrib/python/pluggy/py2/tests/ya.make +++ b/contrib/python/pluggy/py2/tests/ya.make @@ -1,23 +1,23 @@ -PY2TEST() - -OWNER(g:python-contrib) - -PEERDIR ( - contrib/python/pluggy -) - -TEST_SRCS( - conftest.py - test_deprecations.py - test_details.py - test_helpers.py - test_hookcaller.py - test_invocations.py - test_multicall.py - test_pluginmanager.py - test_tracer.py -) - -NO_LINT() - -END() +PY2TEST() + +OWNER(g:python-contrib) + +PEERDIR ( + contrib/python/pluggy +) + +TEST_SRCS( + conftest.py + test_deprecations.py + test_details.py + test_helpers.py + test_hookcaller.py + test_invocations.py + test_multicall.py + test_pluginmanager.py + test_tracer.py +) + +NO_LINT() + +END() |