1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
import pytest
from pluggy import HookimplMarker
from pluggy import HookspecMarker
from pluggy import PluginManager
hookspec = HookspecMarker("example")
hookimpl = HookimplMarker("example")
def test_parse_hookimpl_override() -> None:
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 = {} # type: ignore[assignment]
return opts
class Plugin:
def x1meth(self):
pass
@hookimpl(hookwrapper=True, tryfirst=True)
def x1meth2(self):
yield # pragma: no cover
@hookimpl(wrapper=True, trylast=True)
def x1meth3(self):
return (yield) # pragma: no cover
class Spec:
@hookspec
def x1meth(self):
pass
@hookspec
def x1meth2(self):
pass
@hookspec
def x1meth3(self):
pass
pm = MyPluginManager(hookspec.project_name)
pm.register(Plugin())
pm.add_hookspecs(Spec)
hookimpls = pm.hook.x1meth.get_hookimpls()
assert len(hookimpls) == 1
assert not hookimpls[0].hookwrapper
assert not hookimpls[0].wrapper
assert not hookimpls[0].tryfirst
assert not hookimpls[0].trylast
assert not hookimpls[0].optionalhook
hookimpls = pm.hook.x1meth2.get_hookimpls()
assert len(hookimpls) == 1
assert hookimpls[0].hookwrapper
assert not hookimpls[0].wrapper
assert hookimpls[0].tryfirst
hookimpls = pm.hook.x1meth3.get_hookimpls()
assert len(hookimpls) == 1
assert not hookimpls[0].hookwrapper
assert hookimpls[0].wrapper
assert not hookimpls[0].tryfirst
assert hookimpls[0].trylast
def test_warn_when_deprecated_specified(recwarn) -> None:
warning = DeprecationWarning("foo is deprecated")
class Spec:
@hookspec(warn_on_impl=warning)
def foo(self):
pass
class Plugin:
@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() -> None:
"""Pluggy must be able to handle plugins which raise weird exceptions
when getattr() gets called (#11).
"""
class DontTouchMe:
def __getattr__(self, x):
raise Exception("can't touch me")
class Module:
pass
module = Module()
module.x = DontTouchMe() # type: ignore[attr-defined]
pm = PluginManager(hookspec.project_name)
# register() would raise an error
pm.register(module, "donttouch")
assert pm.get_plugin("donttouch") is module
def test_not_all_arguments_are_provided_issues_a_warning(pm: PluginManager) -> None:
"""Calling a hook without providing all arguments specified in
the hook spec issues a warning."""
class Spec:
@hookspec
def hello(self, arg1, arg2):
pass
@hookspec(historic=True)
def herstory(self, arg1, arg2):
pass
pm.add_hookspecs(Spec)
with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
pm.hook.hello()
with pytest.warns(UserWarning, match=r"'arg2'.*cannot be found.*$"):
pm.hook.hello(arg1=1)
with pytest.warns(UserWarning, match=r"'arg1'.*cannot be found.*$"):
pm.hook.hello(arg2=2)
with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
pm.hook.hello.call_extra([], kwargs=dict())
with pytest.warns(UserWarning, match=r"'arg1', 'arg2'.*cannot be found.*$"):
pm.hook.herstory.call_historic(kwargs=dict())
def test_repr() -> None:
class Plugin:
@hookimpl
def myhook(self):
raise NotImplementedError()
pm = PluginManager(hookspec.project_name)
plugin = Plugin()
pname = pm.register(plugin)
assert repr(pm.hook.myhook.get_hookimpls()[0]) == (
f"<HookImpl plugin_name={pname!r}, plugin={plugin!r}>"
)
|