-->

Python-Sphinx: “inherit” method documentation from

2020-07-10 11:11发布

问题:

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?

回答1:

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.