Reputation: 532
Consider a function with signature f(a, b)
. In future, I would like to change the signature to f(a, *, b)
, disallowing b to be passed as positional argument.
To reduce the impact of the change, I want to first deprecate specifying b positionally, warning users that do so.
For that I would like to write something like:
def f(a, b):
frame = inspect.currentframe()
if b in frame.specified_as_positional:
print('Do not do that')
else:
print('Good')
The result would be that
>>> f(1, 2)
'Do not do that'
>>> f(1, b=2)
'Good'
inspect.getargvalues(frame)
does not seem to be sufficient. The ArgInfo object just provides
>>> f(1,b=2)
ArgInfo(args=['a', 'b'], varargs=None, keywords=None, locals={'a': 1, 'b': 2})
Is such inspection even possible in Python? Conceptually the interpreter does not seem to be required to remember if a argument was specified positionally or as keyword.
Python 2 support would be nice to have but is not strictly required.
Upvotes: 15
Views: 460
Reputation: 51
Here is a pretty hacky solution:
def f(a, c=None, b=None):
if c is not None:
print("do not do that")
else:
print("good")
where input f(1, b=2)
prints good
and f(1, 2)
prints do not do that
Upvotes: 4
Reputation: 5263
You can use a wrapper to add an extra step between the user and the function. In that step, you can examine the arguments before the names matter. Note that this depends on the fact that b
doesn't have a default value and always must be given as an arg.
functools.wraps
is used to make the decorated function resemble the original in a bunch of ways.
import functools
import warnings
def deprecate_positional(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
if 'b' not in kwargs:
warnings.warn(
'b will soon be keyword-only',
DeprecationWarning,
stacklevel=2
)
return fun(*args, **kwargs)
return wrapper
@deprecate_positional
def f(a, b):
return a + b
>>> f(1, b=2)
3
>>> f(1, 2)
Warning (from warnings module):
File "C:/Users/nwerth/Desktop/deprecate_positional.py", line 36
print(f(1, 2))
DeprecationWarning: b will soon be keyword-only
3
Upvotes: 4