Reputation: 314
So I have been stuck on this for some time and figure I would ask for some advice. I am attempting to create a decorator that can modify a functions docstring, allow for optional arguments or none, and is signature preserving. Separately, these can be done. And even getting two of the three.
The sample below seems to modify the docstring and allow for optional arguments or none. However, this method does not preserve the signature.
from functools import wraps
def thisDecorator(*targs, **tkwargs):
def internalFunc(func):
func.__doc__ = "Added this... {0}".format(func.__doc__)
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
if len(targs) == 1 and callable(targs[0]):
return internalFunc(targs[0])
else:
return internalFunc
I have read about the decorator module that does preserve the signature but I can not seem to modify the docstring.
All the help is greatly appreciated
Upvotes: 3
Views: 1334
Reputation: 314
By adding a decorator to the internal wrapper, this will preserve the function signature.
from functools import wraps
from decorator import decorator
def thisDecorator(*targs, **tkwargs):
def internalFunc(func):
func.__doc__ = "Added this... {0}".format(func.__doc__)
@wraps(func)
def wrapper(func, *args, **kwargs):
return func(*args, **kwargs)
return decorator(wrapper, func)
if len(targs) == 1 and callable(targs[0]):
return internalFunc(targs[0])
else:
return internalFunc
Upvotes: 4
Reputation: 1574
Maybe I don't fully understand your requirements, but this seems to be working for me:
class myDeco:
def __init__(self, f):
self.f = f
if f.__doc__:
self.__doc__ = 'great doc: ' + f.__doc__
else:
self.__doc__ = 'ooohh, no doc'
def __call__(self, *args, **kwargs):
print "decorator args and kwargs: {0}, {1}".format(args, kwargs)
self.f(*args, **kwargs)
@myDeco
def test1():
"""test1 doc"""
print 'test1'
@myDeco
def test2(a, b):
print 'test2: {0}, {1}'.format(a,b)
@myDeco
def test3(a, *args):
print "test3: {0}, {1}".format(a, args)
@myDeco
def test4(a, *args, **kwargs):
print "test4: {0}, {1}, {2}".format(a, args, kwargs)
print test1.__doc__
print test2.__doc__
print test3.__doc__
print test4.__doc__
test1()
test2(1,2)
test3(1,2,3)
test4(1,2,3, foo=4, bar=5)
The signature is preserved, the doc is modified, optional arguments are allowed. The output is:
great doc: test1 doc
ooohh, no doc
ooohh, no doc
ooohh, no doc
decorator args and kwargs: (), {}
test1
decorator args and kwargs: (1, 2), {}
test2: 1, 2
decorator args and kwargs: (1, 2, 3), {}
test3: 1, (2, 3)
decorator args and kwargs: (1, 2, 3), {'foo': 4, 'bar': 5}
test4: 1, (2, 3), {'foo': 4, 'bar': 5}
Upvotes: 0