Skip to content

Commit

Permalink
Merge pull request #359 from eachimei/main
Browse files Browse the repository at this point in the history
Proposed fix for issue #358
  • Loading branch information
RonnyPfannschmidt committed Nov 6, 2022
2 parents 4ec84ec + 7372a05 commit f69e314
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
27 changes: 24 additions & 3 deletions src/pluggy/_hooks.py
Expand Up @@ -244,12 +244,33 @@ def varnames(func: object) -> Tuple[Tuple[str, ...], Tuple[str, ...]]:
except Exception:
return (), ()

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

args, defaults = tuple(spec.args), spec.defaults
_valid_param_kinds = (
inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD,
)
_valid_params = {
name: param
for name, param in sig.parameters.items()
if param.kind in _valid_param_kinds
}
args = tuple(_valid_params)
defaults = (
tuple(
param.default
for param in _valid_params.values()
if param.default is not param.empty
)
or None
)

if defaults:
index = -len(defaults)
args, kwargs = args[:index], tuple(args[index:])
Expand Down
28 changes: 28 additions & 0 deletions testing/test_helpers.py
@@ -1,3 +1,5 @@
from functools import wraps
from typing import Any, Callable, TypeVar, cast
from pluggy._hooks import varnames
from pluggy._manager import _formatdef

Expand Down Expand Up @@ -82,3 +84,29 @@ def function4(arg1, *args, **kwargs):
pass

assert _formatdef(function4) == "function4(arg1, *args, **kwargs)"


def test_varnames_decorator() -> None:
F = TypeVar("F", bound=Callable[..., Any])

def my_decorator(func: F) -> F:
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)

return cast(F, wrapper)

@my_decorator
def example(a, b=123) -> None:
pass

class Example:
@my_decorator
def example_method(self, x, y=1) -> None:
pass

ex_inst = Example()

assert varnames(example) == (("a",), ("b",))
assert varnames(Example.example_method) == (("x",), ("y",))
assert varnames(ex_inst.example_method) == (("x",), ("y",))

0 comments on commit f69e314

Please sign in to comment.