Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/get plugins for hook #177

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/177.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``get_hookimpls()`` method to hook callers.
8 changes: 6 additions & 2 deletions pluggy/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ def remove(wrappers):
if remove(self._nonwrappers) is None:
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):
"""Add an implementation to the callback chain.
"""
Expand Down Expand Up @@ -277,7 +281,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
Expand All @@ -299,7 +303,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
Expand Down
6 changes: 3 additions & 3 deletions pluggy/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
35 changes: 35 additions & 0 deletions testing/test_pluginmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,41 @@ class PluginNo(object):
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):
Sup3rGeo marked this conversation as resolved.
Show resolved Hide resolved
@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 plugin1 in hook_plugins
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took the liberty of improving this check a bit. 👍

assert plugin2 in hook_plugins
assert plugin3 not in hook_plugins


def test_add_hookspecs_nohooks(pm):
with pytest.raises(ValueError):
pm.add_hookspecs(10)
Expand Down