Search code examples
pythonpython-sphinxpython-decoratorsdocstring

How to preserve a docstring of a decorated class for sphinx documentation?


I have a decorator that has a nested definition of the wrapping class. Wrapper maintains as the attribute the original class that it wraps. Toy example looks like this:

def decorator(cls):
    class Wrapper(object):
        original = cls

        def __init__(self):
            self.__doc__ = self.original.__doc__
            self.__name__ = self.original.__name__

        def do_something_with_cls(cls):
            pass

    return Wrapper

Now I want to decorate the Foo class with this decorator in the other module and generate sphinx documentation for the Foo class before it has been decorated. It looks like this:

from .bar import decorator


@decorator
class Foo(object):
    """The docstring I want to preserve."""
    def __init__(self):
        pass

I was trying to achieve this with use of the autoclass functionality but it didn't work out. What i wanted to do was to create a class instance and take its docstring:

.. autoclass:: package.baz.Foo()
   :members:

but it returned this in the html documentation of the package.baz.Foo class: alias of package.bar.decorator.<locals>.Wrapper

I want to achieve that when I am documenting the baz module I am able to generate a documentation of the Foo class before its decoration. Is it possible?

EDIT:

This looks like a similar problem but here what I would like to achieve is to pass to the Wrapper instance the docstring that Sphinx will see and generate a documentation basing on the original Foo docstring or I will be able to call a Wrapper.original and make a documentation of this, but the following didn't work out:

.. autoclass package.baz.Foo.original
   :members:

Solution

  • If @wraps is not working you can update __doc__ manually.

    Do something like:

    def decorator(cls):
        class Wrapper(object):
            original = cls
    
            def __init__(self):
                self.__doc__ = self.original.__doc__
                self.__name__ = self.original.__name__
    
            def do_something_with_cls(cls):
                pass
    
        Wrapper.__doc__ = cls.__doc__
        return Wrapper
    
    
    @decorator
    class Foo(object):
        """The docstring I want to preserve."""
        def __init__(self):
            pass
    
    
    print(Foo.__doc__)
    

    'The docstring I want to preserve.'