Why does a decorated class looses its docstrings?

157 views Asked by At

I'm currently implementing an API on which I need to decorate the class Wrapper, but I want it to keep its docstring to make it available to the API user. Take a look at the following minimal working example :

class ClassDecorator:
    """ClassDecorator docstring
    """
    def __init__(self, enableCache=True):
        self.enableCache = enableCache

    def __call__(self, wrapper):
        def numericalmathfunction(*args, **kwargs):
            func = wrapper(*args, **kwargs)
            return func
        return numericalmathfunction

@ClassDecorator(enableCache=True)
class Wrapper(object):
    """Wrapper docstring
    Instructions on how to use the Wrapper
    """
    def __init__(self, p):
        self.p = p

model = Wrapper(4)
print model.__doc__
print Wrapper.__doc__

This returns

Wrapper docstring
None

Instances of Wrapper do keep the docstring, which is fine, but Wrapper itself does not. If a user wants to learn how to use Wrapper using help(Wrapper), he won't get what he wants.

I know I could just copy paste the dosctring into numericalmathfunction, but the decorator will be used on several classes with different docstrings.

Any ideas on how to make numericalmathfunction systematically inherit the docstrings of the wrapped class ?

1

There are 1 answers

5
ronakg On BEST ANSWER

Use functools.wraps() to update the attributes of the decorator:

from functools import wraps

class ClassDecorator:
    """ClassDecorator docstring
    """
    def __init__(self, enableCache=True):
        self.enableCache = enableCache

    def __call__(self, wrapper):
        @wraps(wrapper)                              # <-----------
        def numericalmathfunction(*args, **kwargs):
            func = wrapper(*args, **kwargs)
            return func
        return numericalmathfunction

@ClassDecorator(enableCache=True)
class Wrapper(object):
    """Wrapper docstring
    Instructions on how to use the Wrapper
    """
    def __init__(self, p):
        self.p = p

See more standard library documentation for functools.wrap.