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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With