As explained in the Napoleon manual, using low-level ReStructuredText syntax in docstrings is a bad idea, as the docstrings will be effectively unreadable in plain text (e.g. when interactively exploring a package in IPython). Instead, Google style docstrings should be used, and rendered using the builtin Napoleon Sphinx extension. In this style, the docstring is organized using sections. There are only a small handful of shortcomings:
- The formatting of Attributes is less than ideal by default. It can be
improved by setting
napoleon_use_ivar = True
in the Sphinxdoc.py
, but this also causes the section to be named "Variables" instead of "Attributes" - It would be nice to distinguish (instance) attributes from class attributes, by allowing a "Class Attributes" section
- When documenting classes that have a dictionary interface, it would be nice to have a "Keys" section
The source code for the Napoleon extension is written in such a way that makes
it easy to fix these annoyances. However, this would require forking the
extension. Instead, we may patch it at runtime to achieve the desired behavior.
Adding the following code in doc.py
will achieve this:
# -- Extensions to the Napoleon GoogleDocstring class ---------------------
from sphinx.ext.napoleon.docstring import GoogleDocstring
# first, we define new methods for any new sections and add them to the class
def parse_keys_section(self, section):
return self._format_fields('Keys', self._consume_fields())
GoogleDocstring._parse_keys_section = parse_keys_section
def parse_attributes_section(self, section):
return self._format_fields('Attributes', self._consume_fields())
GoogleDocstring._parse_attributes_section = parse_attributes_section
def parse_class_attributes_section(self, section):
return self._format_fields('Class Attributes', self._consume_fields())
GoogleDocstring._parse_class_attributes_section = parse_class_attributes_section
# we now patch the parse method to guarantee that the the above methods are
# assigned to the _section dict
def patched_parse(self):
self._sections['keys'] = self._parse_keys_section
self._sections['class attributes'] = self._parse_class_attributes_section
self._unpatched_parse()
GoogleDocstring._unpatched_parse = GoogleDocstring._parse
GoogleDocstring._parse = patched_parse