Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python-Sphinx: "inherit" method documentation from superclass

Edit: As of now (Sphinx 1.4.9) there seems to be no way to tell Sphinx to do what I want (see issue on GitHub). The accepted answer from Brecht Machiels solves the problem in an other way, until Sphinx might be able to do so one day.

Description: I am trying to document a Python project with sphinx-apidoc. The Sphinx config is almost default, I just included 'sphinx.ext.autodoc'.

It works in general, but derived classes do not inherit method documentation of their superclasses as I would expect it.

Example: Consider a very minimalistic Python package called project. Aside an empty __init__.py it only consists of one file (base.py, see below)

# -*- coding: utf-8 -*
import abc


class Superclass(object):
    """The one to rule them all"""

    @abc.abstractmethod
    def give(self, ring):
        """Give out a ring"""
        pass


class Derived(Superclass):
    """Somebody has to do the work"""

    def give(self, ring):
        print("I pass the ring {} to you".format(ring))

Running sphinx-apidoc (sphinx-apidoc -o apidoc project -f) generates the following files:

  • apidoc/modules.rst

    project
    =======
    
    .. toctree::
       :maxdepth: 4
    
       project
    
  • apidoc/project.rst

    project package
    ===============
    
    Submodules
    ----------
    
    project.base module
    -------------------
    
    .. automodule:: project.base
        :members:
        :undoc-members:
        :show-inheritance:
    
    
    Module contents
    ---------------
    
    .. automodule:: project
        :members:
        :undoc-members:
        :show-inheritance:
    

Including apidoc/modules.rst in the default index.rst followed by make html generates a basic html documentation for both classes and their methods. Unfortunately, the docstring of Derived.give is empty.

Question: Is there a way to tell Sphinx to take the parent's method documentation without decorator magic as described in this SO post for every single method?

like image 655
AlexV Avatar asked Nov 09 '16 13:11

AlexV


1 Answers

You can manage docstrings automatically by employing a metaclass for the abstract base class. The following is a very basic implementation of such a metaclass. It needs to be extended to properly handle multiple base classes and corner cases.

# -*- coding: utf-8 -*
import abc


class SuperclassMeta(type):
    def __new__(mcls, classname, bases, cls_dict):
        cls = super().__new__(mcls, classname, bases, cls_dict)
        for name, member in cls_dict.items():
            if not getattr(member, '__doc__'):
                member.__doc__ = getattr(bases[-1], name).__doc__
        return cls


class Superclass(object, metaclass=SuperclassMeta):
    """The one to rule them all"""

    @abc.abstractmethod
    def give(self, ring):
        """Give out a ring"""
        pass


class Derived(Superclass):
    """Somebody has to do the work"""

    def give(self, ring):
        print("I pass the ring {} to you".format(ring))

This is even a better solution than having Sphinx do this, because this will also work when calling help() on the derived classes.

like image 180
Brecht Machiels Avatar answered Sep 22 '22 23:09

Brecht Machiels