I'm not good enough with decorators yet to do this ... Is it possible to define a decorator live_doc that allows me to get an interpolated doc string after a method or function call, filled in with the actual arguments and return value.
@live_doc("f was called with %d, %s and returned %d")
def f(x, y):
x + len(y)
After the code below:
f(3, "marty")
d = f.doc
d should be "f was called with 3, "marty", and returned 8". I would prefer to not build up the strings until f.doc is accessed, but would surely need to squirrel away the call args & return value somewhere.
Here's a somewhat generalised solution that will treat your original docstring as a template, and maintain other information about the decorated function (like its name):
from functools import wraps
def live_doc(func):
template = func.__doc__
@wraps(func)
def wrapper(*args, **kwargs):
ret_val = func(*args, **kwargs)
args_pretty = ", ".join(repr(a) for a in args)
kw_pretty = ", ".join("%s=%r" % (k, v) for k, v in kwargs.items())
signature = ", ".join(x for x in (args_pretty, kw_pretty) if x)
name = func.__name__
wrapper.__doc__ = template % locals()
return ret_val
return wrapper
@live_doc
def f(x, y):
"""%(name)s was called with %(signature)s and returned %(ret_val)r."""
return x + len(y)
Before f is first called, help(f) in the interactive interpreter gives you:
Help on function f in module __main__:
f(*args, **kwargs)
%(name)s was called with %(signature)s and returned %(ret_val)r.
After it's called, you get:
f(*args, **kwargs)
f was called with 3, 'marty' and returned 8.
Or with a more general function, showing off kwargs:
@live_doc
def q(*args, **kwargs):
"""%(name)s was called with %(signature)s and returned %(ret_val)r."""
return len(args) + len(kwargs)
>>> q(1, 2, 3, a=7, b="foo")
5
>>> help(q)
q(*args, **kwargs)
q was called with 1, 2, 3, a=7, b='foo' and returned 5.
Obviously you could create whatever variables you wanted to use in the template inside wrapper.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With