From bcd551d76d6d9db0a3fba80ce7dfdbb35f4ec1e7 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 16 Sep 2018 02:44:23 +0200 Subject: [PATCH 1/9] Added get_hookimpl with test. --- pluggy/manager.py | 5 +++++ testing/test_pluginmanager.py | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/pluggy/manager.py b/pluggy/manager.py index 427a7dbb..90cb1813 100644 --- a/pluggy/manager.py +++ b/pluggy/manager.py @@ -289,6 +289,11 @@ def get_hookcallers(self, plugin): """ get all hook callers for the specified plugin. """ return self._plugin2hookcallers.get(plugin) + def get_hookimpl(self, name): + """ Return a list of all plugins that implements a given hook. """ + hc = getattr(self.hook, name) + return hc._wrappers + hc._nonwrappers + def add_hookcall_monitoring(self, before, after): """ add before/after tracing functions for all hooks and return an undo function which, when called, diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index a53437e1..6762e74e 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -384,6 +384,43 @@ class PluginNo(object): assert out == [10] +def test_get_hookimpl(pm): + class Hooks(object): + @hookspec + def he_method1(self, arg): + pass + + pm.add_hookspecs(Hooks) + + 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) + + hook_plugins = pm.get_hookimpl("he_method1") + + assert plugin1.he_method1 in hook_plugins + hook_plugins.remove(plugin1.he_method1) + + assert plugin2.he_method1 in hook_plugins + hook_plugins.remove(plugin2.he_method1) + + assert len(hook_plugins) == 0 + + def test_add_hookspecs_nohooks(pm): with pytest.raises(ValueError): pm.add_hookspecs(10) From 5e1ee9552f8d386a9a677f959c15cba858e9084e Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 16 Sep 2018 02:55:08 +0200 Subject: [PATCH 2/9] Fixed test. --- testing/test_pluginmanager.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 6762e74e..7f9b69ed 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -410,15 +410,12 @@ class PluginNo(object): pm.register(plugin2) pm.register(plugin3) - hook_plugins = pm.get_hookimpl("he_method1") + hookimpls = pm.get_hookimpl("he_method1") + hook_plugins = [hookimpl.plugin for hookimpl in hookimpls] - assert plugin1.he_method1 in hook_plugins - hook_plugins.remove(plugin1.he_method1) - - assert plugin2.he_method1 in hook_plugins - hook_plugins.remove(plugin2.he_method1) - - assert len(hook_plugins) == 0 + assert plugin1 in hook_plugins + assert plugin2 in hook_plugins + assert plugin3 not in hook_plugins def test_add_hookspecs_nohooks(pm): From 17783a5504ca1ff619c5d7b0222ad4002829c4b6 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 16 Sep 2018 02:57:06 +0200 Subject: [PATCH 3/9] Updated docstring. --- pluggy/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pluggy/manager.py b/pluggy/manager.py index 90cb1813..75b21877 100644 --- a/pluggy/manager.py +++ b/pluggy/manager.py @@ -290,7 +290,7 @@ def get_hookcallers(self, plugin): return self._plugin2hookcallers.get(plugin) def get_hookimpl(self, name): - """ Return a list of all plugins that implements a given hook. """ + """ Return a list of all hook implementations (HookImpl) for a given hook. """ hc = getattr(self.hook, name) return hc._wrappers + hc._nonwrappers From 163ff505cd8c69810d287708b6e248bab3249993 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 16 Sep 2018 14:26:58 +0200 Subject: [PATCH 4/9] Moved get_hookimpl to HookCaller. --- pluggy/hooks.py | 3 +++ pluggy/manager.py | 5 ----- testing/test_pluginmanager.py | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pluggy/hooks.py b/pluggy/hooks.py index ce0335fe..3d974a84 100644 --- a/pluggy/hooks.py +++ b/pluggy/hooks.py @@ -233,6 +233,9 @@ def remove(wrappers): if remove(self._nonwrappers) is None: raise ValueError("plugin %r not found" % (plugin,)) + def get_hookimpl(self): + return self._wrappers + self._nonwrappers + def _add_hookimpl(self, hookimpl): """Add an implementation to the callback chain. """ diff --git a/pluggy/manager.py b/pluggy/manager.py index 75b21877..427a7dbb 100644 --- a/pluggy/manager.py +++ b/pluggy/manager.py @@ -289,11 +289,6 @@ def get_hookcallers(self, plugin): """ get all hook callers for the specified plugin. """ return self._plugin2hookcallers.get(plugin) - def get_hookimpl(self, name): - """ Return a list of all hook implementations (HookImpl) for a given hook. """ - hc = getattr(self.hook, name) - return hc._wrappers + hc._nonwrappers - def add_hookcall_monitoring(self, before, after): """ add before/after tracing functions for all hooks and return an undo function which, when called, diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 7f9b69ed..8153cd67 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -410,7 +410,7 @@ class PluginNo(object): pm.register(plugin2) pm.register(plugin3) - hookimpls = pm.get_hookimpl("he_method1") + hookimpls = pm.hook.he_method1.get_hookimpl() hook_plugins = [hookimpl.plugin for hookimpl in hookimpls] assert plugin1 in hook_plugins From ca0d07136e21370cf04cfea84682c8e4c226a083 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 16 Sep 2018 14:33:22 +0200 Subject: [PATCH 5/9] Fixed test. --- testing/test_pluginmanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 8153cd67..19e9ada0 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -411,7 +411,7 @@ class PluginNo(object): pm.register(plugin3) hookimpls = pm.hook.he_method1.get_hookimpl() - hook_plugins = [hookimpl.plugin for hookimpl in hookimpls] + hook_plugins = [item.plugin for item in hookimpls] assert plugin1 in hook_plugins assert plugin2 in hook_plugins From e1fcf6041e63fe8635d798488c338a04fa0d7c85 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 30 Sep 2018 00:35:58 +0200 Subject: [PATCH 6/9] Refactored to use get_hookimpls() --- changelog/177.feature.rst | 1 + pluggy/hooks.py | 6 +++--- pluggy/manager.py | 6 +++--- testing/test_pluginmanager.py | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 changelog/177.feature.rst diff --git a/changelog/177.feature.rst b/changelog/177.feature.rst new file mode 100644 index 00000000..4345a9d7 --- /dev/null +++ b/changelog/177.feature.rst @@ -0,0 +1 @@ +Add ``get_hookimpls()`` method to hook callers. diff --git a/pluggy/hooks.py b/pluggy/hooks.py index 3d974a84..49c877f7 100644 --- a/pluggy/hooks.py +++ b/pluggy/hooks.py @@ -233,7 +233,7 @@ def remove(wrappers): if remove(self._nonwrappers) is None: raise ValueError("plugin %r not found" % (plugin,)) - def get_hookimpl(self): + def get_hookimpls(self): return self._wrappers + self._nonwrappers def _add_hookimpl(self, hookimpl): @@ -280,7 +280,7 @@ def __call__(self, *args, **kwargs): "can not be found in this hook call".format(tuple(notincall)), stacklevel=2, ) - return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) + return self._hookexec(self, self.get_hookimpls(), kwargs) def call_historic(self, result_callback=None, kwargs=None, proc=None): """Call the hook with given ``kwargs`` for all registered plugins and @@ -302,7 +302,7 @@ def call_historic(self, result_callback=None, kwargs=None, proc=None): self._call_history.append((kwargs or {}, result_callback)) # historizing hooks don't return results - res = self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) + res = self._hookexec(self, self.get_hookimpls(), kwargs) if result_callback is None: return # XXX: remember firstresult isn't compat with historic diff --git a/pluggy/manager.py b/pluggy/manager.py index 427a7dbb..3a90979e 100644 --- a/pluggy/manager.py +++ b/pluggy/manager.py @@ -168,7 +168,7 @@ def add_hookspecs(self, module_or_class): else: # plugins registered this hook without knowing the spec hc.set_specification(module_or_class, spec_opts) - for hookfunction in hc._wrappers + hc._nonwrappers: + for hookfunction in hc.get_hookimpls(): self._verify_hook(hc, hookfunction) names.append(name) @@ -242,7 +242,7 @@ def check_pending(self): if name[0] != "_": hook = getattr(self.hook, name) if not hook.has_spec(): - for hookimpl in hook._wrappers + hook._nonwrappers: + for hookimpl in hook.get_hookimpls(): if not hookimpl.optionalhook: raise PluginValidationError( hookimpl.plugin, @@ -329,7 +329,7 @@ def subset_hook_caller(self, name, remove_plugins): hc = _HookCaller( orig.name, orig._hookexec, orig.spec.namespace, orig.spec.opts ) - for hookimpl in orig._wrappers + orig._nonwrappers: + for hookimpl in orig.get_hookimpls(): plugin = hookimpl.plugin if plugin not in plugins_to_remove: hc._add_hookimpl(hookimpl) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 19e9ada0..6c48efe7 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -384,13 +384,14 @@ class PluginNo(object): assert out == [10] -def test_get_hookimpl(pm): +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 @@ -410,7 +411,7 @@ class PluginNo(object): pm.register(plugin2) pm.register(plugin3) - hookimpls = pm.hook.he_method1.get_hookimpl() + hookimpls = pm.hook.he_method1.get_hookimpls() hook_plugins = [item.plugin for item in hookimpls] assert plugin1 in hook_plugins From c85f15449c4ebe188e693d01cdfddbc999f5386f Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 30 Sep 2018 00:46:38 +0200 Subject: [PATCH 7/9] Inverted order, needed for calls. --- pluggy/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pluggy/hooks.py b/pluggy/hooks.py index 49c877f7..ddb9eeae 100644 --- a/pluggy/hooks.py +++ b/pluggy/hooks.py @@ -234,7 +234,7 @@ def remove(wrappers): raise ValueError("plugin %r not found" % (plugin,)) def get_hookimpls(self): - return self._wrappers + self._nonwrappers + return self._nonwrappers + self._wrappers def _add_hookimpl(self, hookimpl): """Add an implementation to the callback chain. From 21dec08835384fcbc8359fe2c83c4cd966e60fd2 Mon Sep 17 00:00:00 2001 From: victor Date: Sun, 30 Sep 2018 00:49:18 +0200 Subject: [PATCH 8/9] Added comment to make order importance more explicit. --- pluggy/hooks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pluggy/hooks.py b/pluggy/hooks.py index ddb9eeae..70b47466 100644 --- a/pluggy/hooks.py +++ b/pluggy/hooks.py @@ -234,6 +234,7 @@ def remove(wrappers): raise ValueError("plugin %r not found" % (plugin,)) def get_hookimpls(self): + # Order is important for _hookexec return self._nonwrappers + self._wrappers def _add_hookimpl(self, hookimpl): From a5c17ec664367debcb21abbbfd29877937782d29 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 30 Sep 2018 12:17:28 -0300 Subject: [PATCH 9/9] Simplify asserts in test_get_hookimpls --- testing/test_pluginmanager.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/testing/test_pluginmanager.py b/testing/test_pluginmanager.py index 6c48efe7..14a028a5 100644 --- a/testing/test_pluginmanager.py +++ b/testing/test_pluginmanager.py @@ -413,10 +413,7 @@ class PluginNo(object): hookimpls = pm.hook.he_method1.get_hookimpls() hook_plugins = [item.plugin for item in hookimpls] - - assert plugin1 in hook_plugins - assert plugin2 in hook_plugins - assert plugin3 not in hook_plugins + assert hook_plugins == [plugin1, plugin2] def test_add_hookspecs_nohooks(pm):