Reputation: 9672
I have the following generic debugger:
def debugger(method):
def dec(*args, **kwargs):
print("\ndebugging '{name}':\n".format(name=method.__name__))
FOUR_SPACES = " " * 4
EIGHT_SPACES = " " * 8
if args:
print("{four}args:\n".format(four=FOUR_SPACES))
for arg in args:
print("%s%s" % (EIGHT_SPACES, arg))
if kwargs:
for key, value in kwargs.items():
print("{four}{key}:\n{eight}{value}\n".format(
four=FOUR_SPACES,
key=key,
eight=EIGHT_SPACES,
value=value
))
if args or kwargs:
print("\n")
result = method(*args, **kwargs)
return result
return dec
@debugger
def generate_minutes_in_timespan(start, end, cutoff_date=None):
# cutoff_date is just example of kwarg
minutes_delta = (end - start).seconds / 60
datetimes = []
delta_range = range(0, minutes_delta + 1)
return [start + timedelta(minutes=i) for i in delta_range]
Debugger will do:
debugging 'generate_minutes_in_timespan':
args:
2017-08-31 17:19:00
2017-09-01 12:05:00
this pleases me slightly, but notice I missed the true info.
What I want is:
debugging 'generate_minutes_in_timespan':
args:
start = 2017-08-31 17:19:00
end = 2017-09-01 12:05:00
*args:
not allowed
kwargs:
cutoff_date = None
*kwargs:
not allowed
Those args have semantic meaning, and can be used as start
and end
...they aren't *args
.
Is there a way deep in python standard library I can read this method generate_minutes_in_timespan
and pluck off the declaration, the names and order of required positional args, also the names of any declared kwargs (like declaring cutoff_date=None
, I would want to know cutoff_date
was offered as a kwarg, vs the optional **kwargs
...)
I shoot for {'args': [('start', 'the value given'), ('end', 'the user given value')], 'star_args': None, 'kwargs': {'cutoff_date': None}, 'star_kwargs': None}
for full debug info.
Upvotes: 2
Views: 57
Reputation: 9672
The result is nice:
import inspect
def debugger(method):
def dec(*args, **kwargs):
print("\ndebugging '{name}':\n".format(name=method.__name__))
FOUR_SPACES = " " * 4
EIGHT_SPACES = " " * 8
inspector = inspect.getargspec(method)
arg_names = inspector.args
var_args = inspector.varargs
keyword_args = inspector.keywords
def wrap_string_in_quotes(value):
if isinstance(value, str):
return '"' + value + '"'
else:
return value
if args:
print("{four}args:\n".format(four=FOUR_SPACES))
for index, arg_name in enumerate(arg_names):
print(
"{eight}{name} = {arg}" \
.format(
eight=EIGHT_SPACES,
name=arg_name,
arg=wrap_string_in_quotes(args[index])
)
)
if var_args:
start = len(arg_names)
these_args = args[start:]
print("\n{four}*{star_arg_name}:\n".format(four=FOUR_SPACES, star_arg_name=var_args))
for this_var_arg in these_args:
print("{eight}{arg}".format(eight=EIGHT_SPACES, arg=wrap_string_in_quotes(this_var_arg)))
if kwargs:
print("\n{four}**{kwargs_name}:\n".format(four=FOUR_SPACES, kwargs_name=keyword_args))
for key, value in kwargs.items():
print("{eight}{key} = {value}\n".format(
eight=EIGHT_SPACES,
key=key,
value=wrap_string_in_quotes(value)
))
if args or kwargs:
print("\n")
result = method(*args, **kwargs)
return result
return dec
@debugger
def one_two_kwarg_three_star_args_star_kwargs(one, two, three=None, *args, **kwargs):
pass
one_two_kwarg_three_star_args_star_kwargs(1, 2, 3, 'star arg 1', 'star arg 2', blah='blah, kwarg')
does
$ python debugger.py
debugging 'one_two_kwarg_three_star_args_star_kwargs':
args:
one = 1
two = 2
three = 3
*args:
"star arg 1"
"star arg 2"
**kwargs:
blah = "blah, kwarg"
Upvotes: 1
Reputation: 280301
Use inspect.signature(method).bind
:
for name, val in inspect.signature(method).bind(*args, **kwargs).arguments:
print('{} = {}'.format(name, val))
If you're on Python 2, there's a backport of this functionality on PyPI you can use.
Upvotes: 3
Reputation: 362557
From within the decorator, use the inspect
module to discover the arg names:
>>> def generate_minutes_in_timespan(start, end, cutoff_date=None):
... ...
...
>>> inspect.getargspec(generate_minutes_in_timespan)
ArgSpec(args=['start', 'end', 'cutoff_date'], varargs=None, keywords=None, defaults=(None,))
^ ^
|________|_____ here they are...
Matching up the arguments passed with the actual arg names is left as exercise for the OP.
Upvotes: 4