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

add test coverage for weird case of plugin with multiple impls of same spec #446

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
56 changes: 56 additions & 0 deletions testing/test_hookcaller.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,59 @@ def conflict(self) -> None:
"Hook 'conflict' is already registered within namespace "
"<class 'test_hookcaller.test_hook_conflict.<locals>.Api1'>"
)


def test_hook_multi_impl(pm: PluginManager) -> None:
"""Since plugins' impls are able to (optionally) specify a spec name, it is possible for a plugin to implement
the same spec multiple times."""

class Api:
@hookspec
def hello(self, arg: object) -> None:
"api hook 1"

pm.add_hookspecs(Api)
hook = pm.hook
test_hc = hook.hello

class Plugin:
@hookimpl
def hello(self, arg):
return arg + 1

@hookimpl(specname="hello")
def hello_again(self, arg):
return arg + 100

plugin = Plugin()

# Confirm that registration puts the impls into all the right registries
pm.register(plugin)
out = test_hc(arg=3)
assert out == [103, 4]

assert len(pm.get_plugins()) == 1

hookimpls = test_hc.get_hookimpls()
hook_plugins = [item.plugin for item in hookimpls]
assert hook_plugins == [plugin, plugin]
for impl in hookimpls:
pm._verify_hook(test_hc, impl)

hook_callers = pm.get_hookcallers(plugin)
assert (
len(hook_callers) == 2
), "This should return two callers. Same spec but different impls."
assert hook_callers[0].spec == hook_callers[1].spec

subset_caller = pm.subset_hook_caller("hello", [plugin])
out = subset_caller(arg=3)
assert out == []

# Confirm that 'unregistering' does the converse
pm.unregister(plugin)
assert test_hc(arg=3) == []
hookimpls = test_hc.get_hookimpls()
assert hookimpls == []
hook_callers = pm.get_hookcallers(plugin)
assert hook_callers is None
82 changes: 82 additions & 0 deletions testing/test_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

import pytest

from pluggy import HookimplMarker
from pluggy import HookspecMarker
from pluggy import PluginManager
from pluggy._tracing import TagTracer

hookspec = HookspecMarker("example")
hookimpl = HookimplMarker("example")


@pytest.fixture
def rootlogger() -> TagTracer:
Expand Down Expand Up @@ -77,3 +83,79 @@ def test_setprocessor(rootlogger: TagTracer) -> None:
log2("seen")
tags, args = l2[0]
assert args == ("seen",)


def test_plugin_tracing(pm: PluginManager) -> None:
class Api:
@hookspec
def hello(self, arg: object) -> None:
"api hook 1"

pm.add_hookspecs(Api)
hook = pm.hook
test_hc = hook.hello

class Plugin:
@hookimpl
def hello(self, arg):
return arg + 1

plugin = Plugin()

trace_out: List[str] = []
pm.trace.root.setwriter(trace_out.append)
pm.register(plugin)
pm.enable_tracing()

out = test_hc(arg=3)
assert out == [4]

assert trace_out == [
" hello [hook]\n arg: 3\n",
" finish hello --> [4] [hook]\n",
]


def test_dbl_plugin_tracing(pm: PluginManager) -> None:
class Api:
@hookspec
def hello(self, arg: object) -> None:
"api hook 1"

pm.add_hookspecs(Api)
hook = pm.hook
test_hc = hook.hello

class Plugin:
@hookimpl
def hello(self, arg):
return arg + 1

@hookimpl(specname="hello")
def hello_again(self, arg):
return arg + 100

plugin = Plugin()

trace_out: List[str] = []
pm.trace.root.setwriter(trace_out.append)
pm.register(plugin)
pm.enable_tracing()

out = test_hc(arg=3)
assert out == [103, 4]

assert trace_out == [
" hello [hook]\n arg: 3\n",
" finish hello --> [103, 4] [hook]\n",
]

trace_out.clear()
pm.unregister(plugin)
out = test_hc(arg=3)
assert out == []

assert trace_out == [
" hello [hook]\n arg: 3\n",
" finish hello --> [] [hook]\n",
]