diff options
Diffstat (limited to 'sphinx/ext/napoleon/__init__.py')
-rw-r--r-- | sphinx/ext/napoleon/__init__.py | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py new file mode 100644 index 0000000..61aa3d8 --- /dev/null +++ b/sphinx/ext/napoleon/__init__.py @@ -0,0 +1,474 @@ +"""Support for NumPy and Google style docstrings.""" + +from __future__ import annotations + +from typing import Any + +import sphinx +from sphinx.application import Sphinx +from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring +from sphinx.util import inspect + + +class Config: + """Sphinx napoleon extension settings in `conf.py`. + + Listed below are all the settings used by napoleon and their default + values. These settings can be changed in the Sphinx `conf.py` file. Make + sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: + + # conf.py + + # Add any Sphinx extension module names here, as strings + extensions = ['sphinx.ext.napoleon'] + + # Napoleon settings + napoleon_google_docstring = True + napoleon_numpy_docstring = True + napoleon_include_init_with_doc = False + napoleon_include_private_with_doc = False + napoleon_include_special_with_doc = False + napoleon_use_admonition_for_examples = False + napoleon_use_admonition_for_notes = False + napoleon_use_admonition_for_references = False + napoleon_use_ivar = False + napoleon_use_param = True + napoleon_use_rtype = True + napoleon_use_keyword = True + napoleon_preprocess_types = False + napoleon_type_aliases = None + napoleon_custom_sections = None + napoleon_attr_annotations = True + + .. _Google style: + https://google.github.io/styleguide/pyguide.html + .. _NumPy style: + https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard + + Attributes + ---------- + napoleon_google_docstring : :obj:`bool` (Defaults to True) + True to parse `Google style`_ docstrings. False to disable support + for Google style docstrings. + napoleon_numpy_docstring : :obj:`bool` (Defaults to True) + True to parse `NumPy style`_ docstrings. False to disable support + for NumPy style docstrings. + napoleon_include_init_with_doc : :obj:`bool` (Defaults to False) + True to list ``__init___`` docstrings separately from the class + docstring. False to fall back to Sphinx's default behavior, which + considers the ``__init___`` docstring as part of the class + documentation. + + **If True**:: + + def __init__(self): + \"\"\" + This will be included in the docs because it has a docstring + \"\"\" + + def __init__(self): + # This will NOT be included in the docs + + napoleon_include_private_with_doc : :obj:`bool` (Defaults to False) + True to include private members (like ``_membername``) with docstrings + in the documentation. False to fall back to Sphinx's default behavior. + + **If True**:: + + def _included(self): + \"\"\" + This will be included in the docs because it has a docstring + \"\"\" + pass + + def _skipped(self): + # This will NOT be included in the docs + pass + + napoleon_include_special_with_doc : :obj:`bool` (Defaults to False) + True to include special members (like ``__membername__``) with + docstrings in the documentation. False to fall back to Sphinx's + default behavior. + + **If True**:: + + def __str__(self): + \"\"\" + This will be included in the docs because it has a docstring + \"\"\" + return unicode(self).encode('utf-8') + + def __unicode__(self): + # This will NOT be included in the docs + return unicode(self.__class__.__name__) + + napoleon_use_admonition_for_examples : :obj:`bool` (Defaults to False) + True to use the ``.. admonition::`` directive for the **Example** and + **Examples** sections. False to use the ``.. rubric::`` directive + instead. One may look better than the other depending on what HTML + theme is used. + + This `NumPy style`_ snippet will be converted as follows:: + + Example + ------- + This is just a quick example + + **If True**:: + + .. admonition:: Example + + This is just a quick example + + **If False**:: + + .. rubric:: Example + + This is just a quick example + + napoleon_use_admonition_for_notes : :obj:`bool` (Defaults to False) + True to use the ``.. admonition::`` directive for **Notes** sections. + False to use the ``.. rubric::`` directive instead. + + Note + ---- + The singular **Note** section will always be converted to a + ``.. note::`` directive. + + See Also + -------- + :confval:`napoleon_use_admonition_for_examples` + + napoleon_use_admonition_for_references : :obj:`bool` (Defaults to False) + True to use the ``.. admonition::`` directive for **References** + sections. False to use the ``.. rubric::`` directive instead. + + See Also + -------- + :confval:`napoleon_use_admonition_for_examples` + + napoleon_use_ivar : :obj:`bool` (Defaults to False) + True to use the ``:ivar:`` role for instance variables. False to use + the ``.. attribute::`` directive instead. + + This `NumPy style`_ snippet will be converted as follows:: + + Attributes + ---------- + attr1 : int + Description of `attr1` + + **If True**:: + + :ivar attr1: Description of `attr1` + :vartype attr1: int + + **If False**:: + + .. attribute:: attr1 + + Description of `attr1` + + :type: int + + napoleon_use_param : :obj:`bool` (Defaults to True) + True to use a ``:param:`` role for each function parameter. False to + use a single ``:parameters:`` role for all the parameters. + + This `NumPy style`_ snippet will be converted as follows:: + + Parameters + ---------- + arg1 : str + Description of `arg1` + arg2 : int, optional + Description of `arg2`, defaults to 0 + + **If True**:: + + :param arg1: Description of `arg1` + :type arg1: str + :param arg2: Description of `arg2`, defaults to 0 + :type arg2: int, optional + + **If False**:: + + :parameters: * **arg1** (*str*) -- + Description of `arg1` + * **arg2** (*int, optional*) -- + Description of `arg2`, defaults to 0 + + napoleon_use_keyword : :obj:`bool` (Defaults to True) + True to use a ``:keyword:`` role for each function keyword argument. + False to use a single ``:keyword arguments:`` role for all the + keywords. + + This behaves similarly to :confval:`napoleon_use_param`. Note unlike + docutils, ``:keyword:`` and ``:param:`` will not be treated the same + way - there will be a separate "Keyword Arguments" section, rendered + in the same fashion as "Parameters" section (type links created if + possible) + + See Also + -------- + :confval:`napoleon_use_param` + + napoleon_use_rtype : :obj:`bool` (Defaults to True) + True to use the ``:rtype:`` role for the return type. False to output + the return type inline with the description. + + This `NumPy style`_ snippet will be converted as follows:: + + Returns + ------- + bool + True if successful, False otherwise + + **If True**:: + + :returns: True if successful, False otherwise + :rtype: bool + + **If False**:: + + :returns: *bool* -- True if successful, False otherwise + + napoleon_preprocess_types : :obj:`bool` (Defaults to False) + Enable the type preprocessor. + + napoleon_type_aliases : :obj:`dict` (Defaults to None) + Add a mapping of strings to string, translating types in numpy + style docstrings. Only works if ``napoleon_preprocess_types = True``. + + napoleon_custom_sections : :obj:`list` (Defaults to None) + Add a list of custom sections to include, expanding the list of parsed sections. + + The entries can either be strings or tuples, depending on the intention: + * To create a custom "generic" section, just pass a string. + * To create an alias for an existing section, pass a tuple containing the + alias name and the original, in that order. + * To create a custom section that displays like the parameters or returns + section, pass a tuple containing the custom section name and a string + value, "params_style" or "returns_style". + + If an entry is just a string, it is interpreted as a header for a generic + section. If the entry is a tuple/list/indexed container, the first entry + is the name of the section, the second is the section key to emulate. If the + second entry value is "params_style" or "returns_style", the custom section + will be displayed like the parameters section or returns section. + + napoleon_attr_annotations : :obj:`bool` (Defaults to True) + Use the type annotations of class attributes that are documented in the docstring + but do not have a type in the docstring. + + """ + _config_values = { + 'napoleon_google_docstring': (True, 'env'), + 'napoleon_numpy_docstring': (True, 'env'), + 'napoleon_include_init_with_doc': (False, 'env'), + 'napoleon_include_private_with_doc': (False, 'env'), + 'napoleon_include_special_with_doc': (False, 'env'), + 'napoleon_use_admonition_for_examples': (False, 'env'), + 'napoleon_use_admonition_for_notes': (False, 'env'), + 'napoleon_use_admonition_for_references': (False, 'env'), + 'napoleon_use_ivar': (False, 'env'), + 'napoleon_use_param': (True, 'env'), + 'napoleon_use_rtype': (True, 'env'), + 'napoleon_use_keyword': (True, 'env'), + 'napoleon_preprocess_types': (False, 'env'), + 'napoleon_type_aliases': (None, 'env'), + 'napoleon_custom_sections': (None, 'env'), + 'napoleon_attr_annotations': (True, 'env'), + } + + def __init__(self, **settings: Any) -> None: + for name, (default, _rebuild) in self._config_values.items(): + setattr(self, name, default) + for name, value in settings.items(): + setattr(self, name, value) + + +def setup(app: Sphinx) -> dict[str, Any]: + """Sphinx extension setup function. + + When the extension is loaded, Sphinx imports this module and executes + the ``setup()`` function, which in turn notifies Sphinx of everything + the extension offers. + + Parameters + ---------- + app : sphinx.application.Sphinx + Application object representing the Sphinx process + + See Also + -------- + `The Sphinx documentation on Extensions + <https://www.sphinx-doc.org/extensions.html>`_ + + `The Extension Tutorial <https://www.sphinx-doc.org/extdev/tutorial.html>`_ + + `The Extension API <https://www.sphinx-doc.org/extdev/appapi.html>`_ + + """ + if not isinstance(app, Sphinx): + # probably called by tests + return {'version': sphinx.__display_version__, 'parallel_read_safe': True} + + _patch_python_domain() + + app.setup_extension('sphinx.ext.autodoc') + app.connect('autodoc-process-docstring', _process_docstring) + app.connect('autodoc-skip-member', _skip_member) + + for name, (default, rebuild) in Config._config_values.items(): + app.add_config_value(name, default, rebuild) + return {'version': sphinx.__display_version__, 'parallel_read_safe': True} + + +def _patch_python_domain() -> None: + from sphinx.domains.python import PyObject, PyTypedField + from sphinx.locale import _ + for doc_field in PyObject.doc_field_types: + if doc_field.name == 'parameter': + doc_field.names = ('param', 'parameter', 'arg', 'argument') + break + PyObject.doc_field_types.append( + PyTypedField('keyword', label=_('Keyword Arguments'), + names=('keyword', 'kwarg', 'kwparam'), + typerolename='obj', typenames=('paramtype', 'kwtype'), + can_collapse=True)) + + +def _process_docstring(app: Sphinx, what: str, name: str, obj: Any, + options: Any, lines: list[str]) -> None: + """Process the docstring for a given python object. + + Called when autodoc has read and processed a docstring. `lines` is a list + of docstring lines that `_process_docstring` modifies in place to change + what Sphinx outputs. + + The following settings in conf.py control what styles of docstrings will + be parsed: + + * ``napoleon_google_docstring`` -- parse Google style docstrings + * ``napoleon_numpy_docstring`` -- parse NumPy style docstrings + + Parameters + ---------- + app : sphinx.application.Sphinx + Application object representing the Sphinx process. + what : str + A string specifying the type of the object to which the docstring + belongs. Valid values: "module", "class", "exception", "function", + "method", "attribute". + name : str + The fully qualified name of the object. + obj : module, class, exception, function, method, or attribute + The object to which the docstring belongs. + options : sphinx.ext.autodoc.Options + The options given to the directive: an object with attributes + inherited_members, undoc_members, show_inheritance and no_index that + are True if the flag option of same name was given to the auto + directive. + lines : list of str + The lines of the docstring, see above. + + .. note:: `lines` is modified *in place* + + """ + result_lines = lines + docstring: GoogleDocstring + if app.config.napoleon_numpy_docstring: + docstring = NumpyDocstring(result_lines, app.config, app, what, name, + obj, options) + result_lines = docstring.lines() + if app.config.napoleon_google_docstring: + docstring = GoogleDocstring(result_lines, app.config, app, what, name, + obj, options) + result_lines = docstring.lines() + lines[:] = result_lines[:] + + +def _skip_member(app: Sphinx, what: str, name: str, obj: Any, + skip: bool, options: Any) -> bool | None: + """Determine if private and special class members are included in docs. + + The following settings in conf.py determine if private and special class + members or init methods are included in the generated documentation: + + * ``napoleon_include_init_with_doc`` -- + include init methods if they have docstrings + * ``napoleon_include_private_with_doc`` -- + include private members if they have docstrings + * ``napoleon_include_special_with_doc`` -- + include special members if they have docstrings + + Parameters + ---------- + app : sphinx.application.Sphinx + Application object representing the Sphinx process + what : str + A string specifying the type of the object to which the member + belongs. Valid values: "module", "class", "exception", "function", + "method", "attribute". + name : str + The name of the member. + obj : module, class, exception, function, method, or attribute. + For example, if the member is the __init__ method of class A, then + `obj` will be `A.__init__`. + skip : bool + A boolean indicating if autodoc will skip this member if `_skip_member` + does not override the decision + options : sphinx.ext.autodoc.Options + The options given to the directive: an object with attributes + inherited_members, undoc_members, show_inheritance and no_index that + are True if the flag option of same name was given to the auto + directive. + + Returns + ------- + bool + True if the member should be skipped during creation of the docs, + False if it should be included in the docs. + + """ + has_doc = getattr(obj, '__doc__', False) + is_member = what in ('class', 'exception', 'module') + if name != '__weakref__' and has_doc and is_member: + cls_is_owner = False + if what in ('class', 'exception'): + qualname = getattr(obj, '__qualname__', '') + cls_path, _, _ = qualname.rpartition('.') + if cls_path: + try: + if '.' in cls_path: + import functools + import importlib + + mod = importlib.import_module(obj.__module__) + mod_path = cls_path.split('.') + cls = functools.reduce(getattr, mod_path, mod) + else: + cls = inspect.unwrap(obj).__globals__[cls_path] + except Exception: + cls_is_owner = False + else: + cls_is_owner = (cls and hasattr(cls, name) and # type: ignore[assignment] + name in cls.__dict__) + else: + cls_is_owner = False + + if what == 'module' or cls_is_owner: + is_init = (name == '__init__') + is_special = (not is_init and name.startswith('__') and + name.endswith('__')) + is_private = (not is_init and not is_special and + name.startswith('_')) + inc_init = app.config.napoleon_include_init_with_doc + inc_special = app.config.napoleon_include_special_with_doc + inc_private = app.config.napoleon_include_private_with_doc + if ((is_special and inc_special) or + (is_private and inc_private) or + (is_init and inc_init)): + return False + return None |