Skip to content

Commit

Permalink
Don't inject :type: for params with no description
Browse files Browse the repository at this point in the history
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 and `None` return types.

After this commit, annotated parameters or return types will only result
in a :type: or a :rtype: field being added if there is already
a corresponding :param: or :return: field, to put users in control over
whether a given parameter is documented.
  • Loading branch information
godlygeek committed Dec 15, 2020
1 parent 00db1ea commit 94e9384
Showing 1 changed file with 20 additions and 24 deletions.
44 changes: 20 additions & 24 deletions sphinx/ext/autodoc/typehints.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -80,51 +80,47 @@ def insert_field_list(node: Element) -> nodes.field_list:


def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> None:
arguments = {} # type: Dict[str, Dict[str, bool]]
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:
arg = arguments.setdefault(parts[1], {})
arg['param'] = True
has_description.add(parts[1])
elif len(parts) > 2:
# :param xxx yyy:
name = ' '.join(parts[2:])
arg = arguments.setdefault(name, {})
arg['param'] = True
arg['type'] = True
has_description.add(name)
has_type.add(name)
elif parts[0] == 'type':
name = ' '.join(parts[1:])
arg = arguments.setdefault(name, {})
arg['type'] = True
has_type.add(name)
elif parts[0] == 'return':
has_description.add('return')
elif parts[0] == 'rtype':
arguments['return'] = {'type': True}
has_type.add('return')

for name, annotation in annotations.items():
# Add 'type' for parameters with a description but no declared type.
for name in annotations:
if name == 'return':
continue

arg = arguments.get(name, {})
if not arg.get('type'):
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('', annotation))
field += nodes.field_body('', nodes.paragraph('', annotations[name]))
node += field
if not arg.get('param'):

# 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('', 'param ' + name)
field += nodes.field_body('', nodes.paragraph('', ''))
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotations['return']))
node += field

if 'return' in annotations and 'return' not in arguments:
field = nodes.field()
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotation))
node += field


def setup(app: Sphinx) -> Dict[str, Any]:
app.connect('autodoc-process-signature', record_typehints)
Expand Down

0 comments on commit 94e9384

Please sign in to comment.