From 4c19d8da3ddca373e4bff8274002d6d173f89870 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 22 May 2018 17:30:55 -0400 Subject: [PATCH 1/5] Rename some test modules test_hookcaller.py: We're not testing "method ordering" per say, we're testing the general internal API and behaviour of the `_HookCaller`; its method ordering is the majority of its purpose, yes. There's also a bunch of tests in this module that don't belong. test_invocations.py: You can't really test the "hookrelay" (unless you're trying to test `getattr`). Really this module is testing the different types of hook "invocations" in terms of API and execution behaviour. Resolves #100 --- testing/{test_method_ordering.py => test_hookcaller.py} | 0 testing/{test_hookrelay.py => test_invocations.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename testing/{test_method_ordering.py => test_hookcaller.py} (100%) rename testing/{test_hookrelay.py => test_invocations.py} (100%) diff --git a/testing/test_method_ordering.py b/testing/test_hookcaller.py similarity index 100% rename from testing/test_method_ordering.py rename to testing/test_hookcaller.py diff --git a/testing/test_hookrelay.py b/testing/test_invocations.py similarity index 100% rename from testing/test_hookrelay.py rename to testing/test_invocations.py From 32a02876aba75104129861472fb0efd733149f48 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 22 May 2018 17:58:35 -0400 Subject: [PATCH 2/5] Move hookcaller test to appropriate module --- testing/test_hookcaller.py | 29 +++++++++++++++++++++++++++++ testing/test_invocations.py | 25 ------------------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/testing/test_hookcaller.py b/testing/test_hookcaller.py index 308aa592..dce34db7 100644 --- a/testing/test_hookcaller.py +++ b/testing/test_hookcaller.py @@ -11,10 +11,12 @@ @pytest.fixture def hc(pm): + class Hooks(object): @hookspec def he_method1(self, arg): pass + pm.add_hookspecs(Hooks) return pm.hook.he_method1 @@ -179,6 +181,33 @@ def he_myhook1(arg1): assert not hasattr(he_myhook1, name) +def test_happypath(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) == [] + + def test_load_setuptools_instantiation(monkeypatch, pm): pkg_resources = pytest.importorskip("pkg_resources") diff --git a/testing/test_invocations.py b/testing/test_invocations.py index 5e7821be..2725f0e7 100644 --- a/testing/test_invocations.py +++ b/testing/test_invocations.py @@ -6,31 +6,6 @@ hookimpl = HookimplMarker("example") -def test_happypath(pm): - 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) == [] - - def test_argmismatch(pm): class Api(object): @hookspec From b093f9eec0183172bf2b9b484d60a9cd3bb115ae Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 22 May 2018 18:09:41 -0400 Subject: [PATCH 3/5] Move manager related tests to proper module --- testing/test_hookcaller.py | 149 +-------------------------------- testing/test_pluginmanager.py | 152 +++++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 150 deletions(-) diff --git a/testing/test_hookcaller.py b/testing/test_hookcaller.py index dce34db7..5f3b1e58 100644 --- a/testing/test_hookcaller.py +++ b/testing/test_hookcaller.py @@ -1,8 +1,6 @@ import pytest -import sys -import types -from pluggy import PluginManager, HookimplMarker, HookspecMarker +from pluggy import HookimplMarker, HookspecMarker from pluggy.hooks import HookImpl hookspec = HookspecMarker("example") @@ -206,148 +204,3 @@ def hello(self, arg): assert not hasattr(hook, 'world') pm.unregister(plugin) assert hook.hello(arg=3) == [] - - -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): - 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/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 351bdce6..ad245d72 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -1,7 +1,10 @@ import pytest import types -from pluggy import (PluginValidationError, - HookCallError, HookimplMarker, HookspecMarker) +import sys +from pluggy import ( + PluginManager, PluginValidationError, + HookCallError, HookimplMarker, HookspecMarker +) hookspec = HookspecMarker("example") @@ -418,3 +421,148 @@ def m(self, x): pm.register(p1) with pytest.deprecated_call(): pm.hook.m.call_historic(kwargs=dict(x=10), proc=lambda res: res) + + +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): + 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() From 8573118599004b0f1d3d4038e6e5ad344c9a64e6 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 22 May 2018 18:17:59 -0400 Subject: [PATCH 4/5] Document the manager module --- testing/test_pluginmanager.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index ad245d72..dd63d4df 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -1,3 +1,6 @@ +""" +``PluginManager`` unit and public API testing. +""" import pytest import types import sys @@ -12,6 +15,7 @@ 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") @@ -20,6 +24,7 @@ def test_plugin_double_register(pm): def test_pm(pm): + """Basic registration with objects""" class A(object): pass From dbda5aa8848170c19192d11998245316efc47772 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 22 May 2018 18:31:22 -0400 Subject: [PATCH 5/5] Move deprecation warnings tests to a module --- testing/test_deprecations.py | 53 +++++++++++++++++++++++++++++++++++ testing/test_details.py | 19 ------------- testing/test_hookcaller.py | 2 +- testing/test_pluginmanager.py | 26 ----------------- 4 files changed, 54 insertions(+), 46 deletions(-) create mode 100644 testing/test_deprecations.py diff --git a/testing/test_deprecations.py b/testing/test_deprecations.py new file mode 100644 index 00000000..3000a374 --- /dev/null +++ b/testing/test_deprecations.py @@ -0,0 +1,53 @@ +""" +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/testing/test_details.py b/testing/test_details.py index 179dde6b..66a1b65f 100644 --- a/testing/test_details.py +++ b/testing/test_details.py @@ -1,7 +1,6 @@ import warnings import pytest from pluggy import PluginManager, HookimplMarker, HookspecMarker -from pluggy.callers import _Result hookspec = HookspecMarker("example") hookimpl = HookimplMarker("example") @@ -118,21 +117,3 @@ def myhook(self, arg1): warning = warns[-1] assert issubclass(warning.category, Warning) assert "Argument(s) ('arg2',)" in str(warning.message) - - -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()) diff --git a/testing/test_hookcaller.py b/testing/test_hookcaller.py index 5f3b1e58..a58e6402 100644 --- a/testing/test_hookcaller.py +++ b/testing/test_hookcaller.py @@ -179,7 +179,7 @@ def he_myhook1(arg1): assert not hasattr(he_myhook1, name) -def test_happypath(pm): +def test_hookrelay_registry(pm): """Verify hook caller instances are registered by name onto the relay and can be likewise unregistered.""" class Api(object): diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index dd63d4df..f04300be 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -374,15 +374,6 @@ class PluginNo(object): assert out == [10] -def test_multicall_deprecated(pm): - class P1(object): - @hookimpl - def m(self, __multicall__, x): - pass - - pytest.deprecated_call(pm.register, P1()) - - def test_add_hookspecs_nohooks(pm): with pytest.raises(ValueError): pm.add_hookspecs(10) @@ -411,23 +402,6 @@ def example_hook(): assert pm.parse_hookimpl_opts(conftest, 'example_hook') == {} -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_load_setuptools_instantiation(monkeypatch, pm): pkg_resources = pytest.importorskip("pkg_resources")