Skip to content

Commit 7667246

Browse files
Refactor argument verification logic from _multicall to HookImpl
Move the duplicated argument extraction and error handling logic from _multicall into a private _get_call_args() method on HookImpl. This eliminates code duplication between wrapper and normal hook implementation processing paths and centralizes the argument verification logic. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent f11fee2 commit 7667246

File tree

2 files changed

+27
-19
lines changed

2 files changed

+27
-19
lines changed

src/pluggy/_callers.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
from ._hook_callers import HookImpl
1515
from ._hook_callers import WrapperImpl
16-
from ._result import HookCallError
1716
from ._result import Result
1817
from ._warnings import PluggyTeardownRaisedWarning
1918

@@ -94,15 +93,7 @@ def _multicall(
9493
teardowns: list[Teardown] = []
9594
try:
9695
for hook_impl in reversed(wrapper_impls):
97-
try:
98-
args = [caller_kwargs[argname] for argname in hook_impl.argnames]
99-
except KeyError as e:
100-
# coverage bug - this is tested
101-
for argname in hook_impl.argnames: # pragma: no cover
102-
if argname not in caller_kwargs:
103-
raise HookCallError(
104-
f"hook call must provide argument {argname!r}"
105-
) from e
96+
args = hook_impl._get_call_args(caller_kwargs)
10697

10798
if hook_impl.hookwrapper:
10899
function_gen = run_old_style_hookwrapper(hook_impl, hook_name, args)
@@ -122,15 +113,7 @@ def _multicall(
122113
# Process normal implementations (in reverse order for correct execution)
123114
# Caller ensures normal_impls contains only non-wrapper implementations
124115
for normal_impl in reversed(normal_impls):
125-
try:
126-
args = [caller_kwargs[argname] for argname in normal_impl.argnames]
127-
except KeyError as e:
128-
# coverage bug - this is tested
129-
for argname in normal_impl.argnames: # pragma: no cover
130-
if argname not in caller_kwargs:
131-
raise HookCallError(
132-
f"hook call must provide argument {argname!r}"
133-
) from e
116+
args = normal_impl._get_call_args(caller_kwargs)
134117

135118
res = normal_impl.function(*args)
136119
if res is not None:

src/pluggy/_hook_callers.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ._hook_config import HookspecOpts
2929
from ._hook_markers import HookSpec
3030
from ._hook_markers import varnames
31+
from ._result import HookCallError
3132

3233

3334
_T_HookImpl = TypeVar("_T_HookImpl", bound="HookImpl")
@@ -668,6 +669,30 @@ def __init__(
668669
#: <callorder>`.
669670
self.trylast = hook_impl_config.trylast
670671

672+
def _get_call_args(self, caller_kwargs: Mapping[str, object]) -> list[object]:
673+
"""Extract arguments for calling this hook implementation.
674+
675+
Args:
676+
caller_kwargs: Keyword arguments passed to the hook call
677+
678+
Returns:
679+
List of arguments in the order expected by the hook implementation
680+
681+
Raises:
682+
HookCallError: If required arguments are missing
683+
"""
684+
try:
685+
return [caller_kwargs[argname] for argname in self.argnames]
686+
except KeyError as e:
687+
# Find the first missing argument for a clearer error message
688+
for argname in self.argnames: # pragma: no cover
689+
if argname not in caller_kwargs:
690+
raise HookCallError(
691+
f"hook call must provide argument {argname!r}"
692+
) from e
693+
# This should never be reached but keep the original exception just in case
694+
raise # pragma: no cover
695+
671696
def __repr__(self) -> str:
672697
return (
673698
f"<{self.__class__.__name__} "

0 commit comments

Comments
 (0)