Skip to content

Commit 1b1042e

Browse files
authored
Merge pull request #430 from bluetech/typing3
More steps towards exporting our typings
2 parents ba6fb4a + 20b419d commit 1b1042e

File tree

7 files changed

+97
-42
lines changed

7 files changed

+97
-42
lines changed

docs/api_reference.rst

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ API Reference
1414

1515
.. autodecorator:: pluggy.HookimplMarker
1616

17-
.. autoclass:: pluggy.Result()
18-
:show-inheritance:
17+
.. autoclass:: pluggy.HookRelay()
1918
:members:
2019

20+
.. data:: <hook name>
21+
22+
:type: HookCaller
23+
24+
The caller for the hook with the given name.
25+
2126
.. autoclass:: pluggy.HookCaller()
2227
:members:
2328
:special-members: __call__
@@ -26,11 +31,17 @@ API Reference
2631
:show-inheritance:
2732
:members:
2833

29-
.. autoclass:: pluggy.HookRelay()
34+
.. autoclass:: pluggy.Result()
35+
:show-inheritance:
3036
:members:
3137

32-
.. data:: <hook name>
38+
.. autoclass:: pluggy.HookImpl()
39+
:members:
3340

34-
:type: HookCaller
41+
.. autoclass:: pluggy.HookspecOpts()
42+
:show-inheritance:
43+
:members:
3544

36-
The caller for the hook with the given name.
45+
.. autoclass:: pluggy.HookimplOpts()
46+
:show-inheritance:
47+
:members:

docs/conf.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@
6161

6262
autodoc_member_order = "bysource"
6363

64+
nitpicky = True
65+
nitpick_ignore = {
66+
# Don't want to expose this yet (see #428).
67+
("py:class", "pluggy._tracing.TagTracerSub"),
68+
# Compat hack, don't want to expose it.
69+
("py:class", "pluggy._manager.DistFacade"),
70+
# `types.ModuleType` turns into `module` but then fails to resolve...
71+
("py:class", "module"),
72+
# Just a TypeVar.
73+
("py:obj", "pluggy._result.ResultType"),
74+
("py:class", "pluggy._result.ResultType"),
75+
}
76+
6477
# -- Options for Texinfo output -------------------------------------------
6578

6679
# Grouping the document tree into Texinfo files. List of tuples

docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -966,11 +966,11 @@ The expected signature and default implementations for these functions is:
966966

967967
.. code-block:: python
968968
969-
def before(hook_name, methods, kwargs):
969+
def before(hook_name, hook_impls, kwargs):
970970
pass
971971
972972
973-
def after(outcome, hook_name, methods, kwargs):
973+
def after(outcome, hook_name, hook_impls, kwargs):
974974
pass
975975
976976
Public API

src/pluggy/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
"PluginValidationError",
1111
"HookCaller",
1212
"HookCallError",
13-
"HookSpecOpts",
14-
"HookImplOpts",
13+
"HookspecOpts",
14+
"HookimplOpts",
15+
"HookImpl",
1516
"HookRelay",
1617
"HookspecMarker",
1718
"HookimplMarker",
@@ -25,6 +26,7 @@
2526
HookimplMarker,
2627
HookCaller,
2728
HookRelay,
28-
HookSpecOpts,
29-
HookImplOpts,
29+
HookspecOpts,
30+
HookimplOpts,
31+
HookImpl,
3032
)

src/pluggy/_hooks.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any
1212
from typing import Callable
1313
from typing import Final
14+
from typing import final
1415
from typing import Generator
1516
from typing import List
1617
from typing import Mapping
@@ -37,7 +38,7 @@
3738
_HookImplFunction = Callable[..., Union[_T, Generator[None, Result[_T], None]]]
3839

3940

40-
class HookSpecOpts(TypedDict):
41+
class HookspecOpts(TypedDict):
4142
"""Options for a hook specification."""
4243

4344
#: Whether the hook is :ref:`first result only <firstresult>`.
@@ -48,7 +49,7 @@ class HookSpecOpts(TypedDict):
4849
warn_on_impl: Warning | None
4950

5051

51-
class HookImplOpts(TypedDict):
52+
class HookimplOpts(TypedDict):
5253
"""Options for a hook implementation."""
5354

5455
#: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.
@@ -69,6 +70,7 @@ class HookImplOpts(TypedDict):
6970
specname: str | None
7071

7172

73+
@final
7274
class HookspecMarker:
7375
"""Decorator for marking functions as hook specifications.
7476
@@ -132,7 +134,7 @@ def __call__( # noqa: F811
132134
def setattr_hookspec_opts(func: _F) -> _F:
133135
if historic and firstresult:
134136
raise ValueError("cannot have a historic firstresult hook")
135-
opts: HookSpecOpts = {
137+
opts: HookspecOpts = {
136138
"firstresult": firstresult,
137139
"historic": historic,
138140
"warn_on_impl": warn_on_impl,
@@ -146,6 +148,7 @@ def setattr_hookspec_opts(func: _F) -> _F:
146148
return setattr_hookspec_opts
147149

148150

151+
@final
149152
class HookimplMarker:
150153
"""Decorator for marking functions as hook implementations.
151154
@@ -247,7 +250,7 @@ def __call__( # noqa: F811
247250
"""
248251

249252
def setattr_hookimpl_opts(func: _F) -> _F:
250-
opts: HookImplOpts = {
253+
opts: HookimplOpts = {
251254
"wrapper": wrapper,
252255
"hookwrapper": hookwrapper,
253256
"optionalhook": optionalhook,
@@ -264,7 +267,7 @@ def setattr_hookimpl_opts(func: _F) -> _F:
264267
return setattr_hookimpl_opts(function)
265268

266269

267-
def normalize_hookimpl_opts(opts: HookImplOpts) -> None:
270+
def normalize_hookimpl_opts(opts: HookimplOpts) -> None:
268271
opts.setdefault("tryfirst", False)
269272
opts.setdefault("trylast", False)
270273
opts.setdefault("wrapper", False)
@@ -341,6 +344,7 @@ def varnames(func: object) -> tuple[tuple[str, ...], tuple[str, ...]]:
341344
return args, kwargs
342345

343346

347+
@final
344348
class HookRelay:
345349
"""Hook holder object for performing 1:N hook calls where N is the number
346350
of registered plugins."""
@@ -379,13 +383,15 @@ def __init__(
379383
name: str,
380384
hook_execute: _HookExec,
381385
specmodule_or_class: _Namespace | None = None,
382-
spec_opts: HookSpecOpts | None = None,
386+
spec_opts: HookspecOpts | None = None,
383387
) -> None:
384388
""":meta private:"""
389+
#: Name of the hook getting called.
385390
self.name: Final = name
386391
self._hookexec: Final = hook_execute
387392
self._hookimpls: Final[list[HookImpl]] = []
388393
self._call_history: _CallHistory | None = None
394+
# TODO: Document, or make private.
389395
self.spec: HookSpec | None = None
390396
if specmodule_or_class is not None:
391397
assert spec_opts is not None
@@ -399,7 +405,7 @@ def has_spec(self) -> bool:
399405
def set_specification(
400406
self,
401407
specmodule_or_class: _Namespace,
402-
spec_opts: HookSpecOpts,
408+
spec_opts: HookspecOpts,
403409
) -> None:
404410
if self.spec is not None:
405411
raise ValueError(
@@ -522,7 +528,7 @@ def call_extra(
522528
not self.is_historic()
523529
), "Cannot directly call a historic hook - use call_historic instead."
524530
self._verify_all_args_are_provided(kwargs)
525-
opts: HookImplOpts = {
531+
opts: HookimplOpts = {
526532
"wrapper": False,
527533
"hookwrapper": False,
528534
"optionalhook": False,
@@ -606,7 +612,10 @@ def __repr__(self) -> str:
606612
return f"<_SubsetHookCaller {self.name!r}>"
607613

608614

615+
@final
609616
class HookImpl:
617+
"""A hook implementation in a :class:`HookCaller`."""
618+
610619
__slots__ = (
611620
"function",
612621
"argnames",
@@ -626,23 +635,42 @@ def __init__(
626635
plugin: _Plugin,
627636
plugin_name: str,
628637
function: _HookImplFunction[object],
629-
hook_impl_opts: HookImplOpts,
638+
hook_impl_opts: HookimplOpts,
630639
) -> None:
640+
""":meta private:"""
641+
#: The hook implementation function.
631642
self.function: Final = function
632-
self.argnames, self.kwargnames = varnames(self.function)
633-
self.plugin = plugin
634-
self.opts = hook_impl_opts
635-
self.plugin_name = plugin_name
636-
self.wrapper = hook_impl_opts["wrapper"]
637-
self.hookwrapper = hook_impl_opts["hookwrapper"]
638-
self.optionalhook = hook_impl_opts["optionalhook"]
639-
self.tryfirst = hook_impl_opts["tryfirst"]
640-
self.trylast = hook_impl_opts["trylast"]
643+
argnames, kwargnames = varnames(self.function)
644+
#: The positional parameter names of ``function```.
645+
self.argnames: Final = argnames
646+
#: The keyword parameter names of ``function```.
647+
self.kwargnames: Final = kwargnames
648+
#: The plugin which defined this hook implementation.
649+
self.plugin: Final = plugin
650+
#: The :class:`HookimplOpts` used to configure this hook implementation.
651+
self.opts: Final = hook_impl_opts
652+
#: The name of the plugin which defined this hook implementation.
653+
self.plugin_name: Final = plugin_name
654+
#: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.
655+
self.wrapper: Final = hook_impl_opts["wrapper"]
656+
#: Whether the hook implementation is an :ref:`old-style wrapper
657+
#: <old_style_hookwrappers>`.
658+
self.hookwrapper: Final = hook_impl_opts["hookwrapper"]
659+
#: Whether validation against a hook specification is :ref:`optional
660+
#: <optionalhook>`.
661+
self.optionalhook: Final = hook_impl_opts["optionalhook"]
662+
#: Whether to try to order this hook implementation :ref:`first
663+
#: <callorder>`.
664+
self.tryfirst: Final = hook_impl_opts["tryfirst"]
665+
#: Whether to try to order this hook implementation :ref:`last
666+
#: <callorder>`.
667+
self.trylast: Final = hook_impl_opts["trylast"]
641668

642669
def __repr__(self) -> str:
643670
return f"<HookImpl plugin_name={self.plugin_name!r}, plugin={self.plugin!r}>"
644671

645672

673+
@final
646674
class HookSpec:
647675
__slots__ = (
648676
"namespace",
@@ -654,7 +682,7 @@ class HookSpec:
654682
"warn_on_impl",
655683
)
656684

657-
def __init__(self, namespace: _Namespace, name: str, opts: HookSpecOpts) -> None:
685+
def __init__(self, namespace: _Namespace, name: str, opts: HookspecOpts) -> None:
658686
self.namespace = namespace
659687
self.function: Callable[..., object] = getattr(namespace, name)
660688
self.name = name

src/pluggy/_manager.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
from ._hooks import _SubsetHookCaller
2121
from ._hooks import HookCaller
2222
from ._hooks import HookImpl
23-
from ._hooks import HookImplOpts
23+
from ._hooks import HookimplOpts
2424
from ._hooks import HookRelay
25-
from ._hooks import HookSpec
26-
from ._hooks import HookSpecOpts
25+
from ._hooks import HookspecOpts
2726
from ._hooks import normalize_hookimpl_opts
2827
from ._result import Result
2928

@@ -92,12 +91,12 @@ class PluginManager:
9291

9392
def __init__(self, project_name: str) -> None:
9493
#: The project name.
95-
self.project_name: Final[str] = project_name
94+
self.project_name: Final = project_name
9695
self._name2plugin: Final[dict[str, _Plugin]] = {}
9796
self._plugin_distinfo: Final[list[tuple[_Plugin, DistFacade]]] = []
9897
#: The "hook relay", used to call a hook on all registered plugins.
9998
#: See :ref:`calling`.
100-
self.hook: Final[HookRelay] = HookRelay()
99+
self.hook: Final = HookRelay()
101100
#: The tracing entry point. See :ref:`tracing`.
102101
self.trace: Final[_tracing.TagTracerSub] = _tracing.TagTracer().get(
103102
"pluginmanage"
@@ -166,7 +165,7 @@ def register(self, plugin: _Plugin, name: str | None = None) -> str | None:
166165
hook._add_hookimpl(hookimpl)
167166
return plugin_name
168167

169-
def parse_hookimpl_opts(self, plugin: _Plugin, name: str) -> HookImplOpts | None:
168+
def parse_hookimpl_opts(self, plugin: _Plugin, name: str) -> HookimplOpts | None:
170169
"""Try to obtain a hook implementation from an item with the given name
171170
in the given plugin which is being searched for hook impls.
172171
@@ -175,13 +174,13 @@ def parse_hookimpl_opts(self, plugin: _Plugin, name: str) -> HookImplOpts | None
175174
176175
This method can be overridden by ``PluginManager`` subclasses to
177176
customize how hook implementation are picked up. By default, returns the
178-
options for items decorated with :class:`HookImplMarker`.
177+
options for items decorated with :class:`HookimplMarker`.
179178
"""
180179
method: object = getattr(plugin, name)
181180
if not inspect.isroutine(method):
182181
return None
183182
try:
184-
res: HookImplOpts | None = getattr(
183+
res: HookimplOpts | None = getattr(
185184
method, self.project_name + "_impl", None
186185
)
187186
except Exception:
@@ -260,7 +259,7 @@ def add_hookspecs(self, module_or_class: _Namespace) -> None:
260259

261260
def parse_hookspec_opts(
262261
self, module_or_class: _Namespace, name: str
263-
) -> HookSpecOpts | None:
262+
) -> HookspecOpts | None:
264263
"""Try to obtain a hook specification from an item with the given name
265264
in the given module or class which is being searched for hook specs.
266265
@@ -272,8 +271,8 @@ def parse_hookspec_opts(
272271
customize how hook specifications are picked up. By default, returns the
273272
options for items decorated with :class:`HookspecMarker`.
274273
"""
275-
method: HookSpec = getattr(module_or_class, name)
276-
opts: HookSpecOpts | None = getattr(method, self.project_name + "_spec", None)
274+
method = getattr(module_or_class, name)
275+
opts: HookspecOpts | None = getattr(method, self.project_name + "_spec", None)
277276
return opts
278277

279278
def get_plugins(self) -> set[Any]:

src/pluggy/_result.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from types import TracebackType
77
from typing import Callable
88
from typing import cast
9+
from typing import final
910
from typing import Generator
1011
from typing import Generic
1112
from typing import NoReturn
@@ -36,6 +37,7 @@ class HookCallError(Exception):
3637
"""Hook was called incorrectly."""
3738

3839

40+
@final
3941
class Result(Generic[ResultType]):
4042
"""An object used to inspect and set the result in a :ref:`hook wrapper
4143
<hookwrappers>`."""

0 commit comments

Comments
 (0)