Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.5.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Bug fixes

Other
~~~~~
- Avoid showing deprecated signatures when introspecting functions that use ``deprecate_nonkeyword_arguments`` (:issue:`48692`)
-
-

Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/util/test_deprecate_nonkeyword_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Tests for the `deprecate_nonkeyword_arguments` decorator
"""

import inspect
import warnings

from pandas.util._decorators import deprecate_nonkeyword_arguments
Expand All @@ -16,6 +17,10 @@ def f(a, b=0, c=0, d=0):
return a + b + c + d


def test_f_signature():
assert str(inspect.signature(f)) == "(a, b=0, *, c=0, d=0)"


def test_one_argument():
with tm.assert_produces_warning(None):
assert f(19) == 19
Expand Down Expand Up @@ -65,6 +70,10 @@ def g(a, b=0, c=0, d=0):
return a + b + c + d


def test_g_signature():
assert str(inspect.signature(g)) == "(a, *, b=0, c=0, d=0)"


def test_one_and_three_arguments_default_allowed_args():
with tm.assert_produces_warning(None):
assert g(1, b=3, c=3, d=5) == 12
Expand Down Expand Up @@ -93,6 +102,10 @@ def h(a=0, b=0, c=0, d=0):
return a + b + c + d


def test_h_signature():
assert str(inspect.signature(h)) == "(*, a=0, b=0, c=0, d=0)"


def test_all_keyword_arguments():
with tm.assert_produces_warning(None):
assert h(a=1, b=2) == 3
Expand Down Expand Up @@ -122,6 +135,10 @@ def baz(self, bar=None, foobar=None):
...


def test_foo_signature():
assert str(inspect.signature(Foo.baz)) == "(self, bar=None, *, foobar=None)"


def test_class():
msg = (
r"In a future version of pandas all arguments of Foo\.baz "
Expand Down
29 changes: 23 additions & 6 deletions pandas/util/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,29 @@ def deprecate_nonkeyword_arguments(
"""

def decorate(func):
old_sig = inspect.signature(func)

if allowed_args is not None:
allow_args = allowed_args
else:
spec = inspect.getfullargspec(func)
allow_args = [
p.name
for p in old_sig.parameters.values()
if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test that requires p.POSITIONAL_ONLY? I tried deleting it from here, and pytest pandas/tests/util/test_deprecate_nonkeyword_arguments.py still passed

If there's not a test that needs this, could we add a little one that does?

EDIT: apologies, I wrote this comment then forgot to add this comment to the previous review

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test!

and p.default is p.empty
]

# We must have some defaults if we are deprecating default-less
assert spec.defaults is not None # for mypy
allow_args = spec.args[: -len(spec.defaults)]
new_params = [
p.replace(kind=p.KEYWORD_ONLY)
if (
p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
and p.name not in allow_args
)
else p
for p in old_sig.parameters.values()
]
new_params.sort(key=lambda p: p.kind)
new_sig = old_sig.replace(parameters=new_params)

num_allow_args = len(allow_args)
msg = (
Expand All @@ -307,15 +322,17 @@ def decorate(func):

@wraps(func)
def wrapper(*args, **kwargs):
arguments = _format_argument_list(allow_args)
if len(args) > num_allow_args:
warnings.warn(
msg.format(arguments=arguments),
msg.format(arguments=_format_argument_list(allow_args)),
FutureWarning,
stacklevel=find_stack_level(inspect.currentframe()),
)
return func(*args, **kwargs)

# error: "Callable[[VarArg(Any), KwArg(Any)], Any]" has no
# attribute "__signature__"
wrapper.__signature__ = new_sig # type: ignore[attr-defined]
return wrapper

return decorate
Expand Down