Skip to content

Commit f69e314

Browse files
Merge pull request #359 from eachimei/main
Proposed fix for issue #358
2 parents 4ec84ec + 7372a05 commit f69e314

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

src/pluggy/_hooks.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,33 @@ def varnames(func: object) -> Tuple[Tuple[str, ...], Tuple[str, ...]]:
244244
except Exception:
245245
return (), ()
246246

247-
try: # func MUST be a function or method here or we won't parse any args
248-
spec = inspect.getfullargspec(func)
247+
try:
248+
# func MUST be a function or method here or we won't parse any args.
249+
sig = inspect.signature(
250+
func.__func__ if inspect.ismethod(func) else func # type:ignore[arg-type]
251+
)
249252
except TypeError:
250253
return (), ()
251254

252-
args, defaults = tuple(spec.args), spec.defaults
255+
_valid_param_kinds = (
256+
inspect.Parameter.POSITIONAL_ONLY,
257+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
258+
)
259+
_valid_params = {
260+
name: param
261+
for name, param in sig.parameters.items()
262+
if param.kind in _valid_param_kinds
263+
}
264+
args = tuple(_valid_params)
265+
defaults = (
266+
tuple(
267+
param.default
268+
for param in _valid_params.values()
269+
if param.default is not param.empty
270+
)
271+
or None
272+
)
273+
253274
if defaults:
254275
index = -len(defaults)
255276
args, kwargs = args[:index], tuple(args[index:])

testing/test_helpers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import wraps
2+
from typing import Any, Callable, TypeVar, cast
13
from pluggy._hooks import varnames
24
from pluggy._manager import _formatdef
35

@@ -82,3 +84,29 @@ def function4(arg1, *args, **kwargs):
8284
pass
8385

8486
assert _formatdef(function4) == "function4(arg1, *args, **kwargs)"
87+
88+
89+
def test_varnames_decorator() -> None:
90+
F = TypeVar("F", bound=Callable[..., Any])
91+
92+
def my_decorator(func: F) -> F:
93+
@wraps(func)
94+
def wrapper(*args, **kwargs):
95+
return func(*args, **kwargs)
96+
97+
return cast(F, wrapper)
98+
99+
@my_decorator
100+
def example(a, b=123) -> None:
101+
pass
102+
103+
class Example:
104+
@my_decorator
105+
def example_method(self, x, y=1) -> None:
106+
pass
107+
108+
ex_inst = Example()
109+
110+
assert varnames(example) == (("a",), ("b",))
111+
assert varnames(Example.example_method) == (("x",), ("y",))
112+
assert varnames(ex_inst.example_method) == (("x",), ("y",))

0 commit comments

Comments
 (0)