Add autodoc_typehint_undoc option

Previously, if autodoc_typehints="description", a :type: field would be
added for every parameter and return type appearing in the annotation,
including **kwargs and underscore-prefixed parameters that are meant to
be private, as well as None return types.

This commit introduces a new option, "autodoc_typehint_undoc".  By
default this option is True, requesting the old behavior. By setting
this option to False, :type: and :rtype: fields will only be added for
annotated parameters or return types if there is already a corresponding
:param: or :return: field, to put users in control over whether a given
parameter is documented or not.
This commit is contained in:
Matt Wozniski 2020-12-14 17:38:37 -05:00 committed by Matt Wozniski
parent e888a44249
commit 4785f32ddf
3 changed files with 66 additions and 2 deletions

View File

@ -571,6 +571,19 @@ There are also config values that you can set:
New option ``'description'`` is added.
.. confval:: autodoc_typehints_description_target
This value controls whether the types of undocumented parameters and return
values are documented when ``autodoc_typehints`` is set to ``description``.
The default value is ``"all"``, meaning that types are documented for all
parameters and return values, whether they are documented or not.
When set to ``"documented"``, types will only be documented for a parameter
or a return value that is already documented by the docstring.
.. versionadded:: 4.0
.. confval:: autodoc_type_aliases
A dictionary for users defined `type aliases`__ that maps a type name to the

View File

@ -2656,6 +2656,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('autodoc_mock_imports', [], True)
app.add_config_value('autodoc_typehints', "signature", True,
ENUM("signature", "description", "none"))
app.add_config_value('autodoc_typehints_description_target', 'all', True,
ENUM('all', 'documented'))
app.add_config_value('autodoc_type_aliases', {}, True)
app.add_config_value('autodoc_warningiserror', True, True)
app.add_config_value('autodoc_inherit_docstrings', True, True)

View File

@ -10,7 +10,7 @@
import re
from collections import OrderedDict
from typing import Any, Dict, Iterable, cast
from typing import Any, Dict, Iterable, Set, cast
from docutils import nodes
from docutils.nodes import Element
@ -63,7 +63,10 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element
field_lists.append(field_list)
for field_list in field_lists:
modify_field_list(field_list, annotations[fullname])
if app.config.autodoc_typehints_description_target == "all":
modify_field_list(field_list, annotations[fullname])
else:
augment_descriptions_with_types(field_list, annotations[fullname])
def insert_field_list(node: Element) -> nodes.field_list:
@ -126,6 +129,52 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
node += field
def augment_descriptions_with_types(
node: nodes.field_list,
annotations: Dict[str, str],
) -> None:
fields = cast(Iterable[nodes.field], node)
has_description = set() # type: Set[str]
has_type = set() # type: Set[str]
for field in fields:
field_name = field[0].astext()
parts = re.split(' +', field_name)
if parts[0] == 'param':
if len(parts) == 2:
# :param xxx:
has_description.add(parts[1])
elif len(parts) > 2:
# :param xxx yyy:
name = ' '.join(parts[2:])
has_description.add(name)
has_type.add(name)
elif parts[0] == 'type':
name = ' '.join(parts[1:])
has_type.add(name)
elif parts[0] == 'return':
has_description.add('return')
elif parts[0] == 'rtype':
has_type.add('return')
# Add 'type' for parameters with a description but no declared type.
for name in annotations:
if name == 'return':
continue
if name in has_description and name not in has_type:
field = nodes.field()
field += nodes.field_name('', 'type ' + name)
field += nodes.field_body('', nodes.paragraph('', annotations[name]))
node += field
# Add 'rtype' if 'return' is present and 'rtype' isn't.
if 'return' in annotations:
if 'return' in has_description and 'return' not in has_type:
field = nodes.field()
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotations['return']))
node += field
def setup(app: Sphinx) -> Dict[str, Any]:
app.connect('autodoc-process-signature', record_typehints)
app.connect('object-description-transform', merge_typehints)