Skip to content

Commit

Permalink
autodoc.typehints can accurately represent overloads
Browse files Browse the repository at this point in the history
  • Loading branch information
AWhetter committed May 9, 2021
1 parent 78dbe07 commit 28d3f81
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 7 deletions.
16 changes: 14 additions & 2 deletions doc/usage/extensions/autodoc.rst
Expand Up @@ -573,15 +573,27 @@ There are also config values that you can set:
This value controls how to represent typehints. The setting takes the
following values:

* ``'signature'`` -- Show typehints as its signature (default)
* ``'description'`` -- Show typehints as content of function or method
* ``'signature'`` -- Show typehints in the signature (default)
* ``'description'`` -- Show typehints as content of the function or method
The typehints of overloaded functions or methods will still be represented
in the signature.
* ``'none'`` -- Do not show typehints
* ``'both'`` -- Show typehints in the signature and as content of
the function or method

Overloaded functions or methods will not have typehints included in the
description because it is impossible to accurately represent all possible
overloads as a list of parameters.

.. versionadded:: 2.1
.. versionadded:: 3.0

New option ``'description'`` is added.

.. versionadded:: 4.0

New option ``'both'`` is added.

.. confval:: autodoc_typehints_description_target

This value controls whether the types of undocumented parameters and return
Expand Down
8 changes: 4 additions & 4 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1314,7 +1314,7 @@ def format_signature(self, **kwargs: Any) -> str:
sigs = []
if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and
self.config.autodoc_typehints == 'signature'):
self.config.autodoc_typehints != 'none'):
# Use signatures for overloaded functions instead of the implementation function.
overloaded = True
else:
Expand Down Expand Up @@ -1560,7 +1560,7 @@ def format_signature(self, **kwargs: Any) -> str:
sigs = []

overloads = self.get_overloaded_signatures()
if overloads and self.config.autodoc_typehints == 'signature':
if overloads and self.config.autodoc_typehints != 'none':
# Use signatures for overloaded methods instead of the implementation method.
method = safe_getattr(self._signature_class, self._signature_method_name, None)
__globals__ = safe_getattr(method, '__globals__', {})
Expand Down Expand Up @@ -2109,7 +2109,7 @@ def format_signature(self, **kwargs: Any) -> str:
sigs = []
if (self.analyzer and
'.'.join(self.objpath) in self.analyzer.overloads and
self.config.autodoc_typehints == 'signature'):
self.config.autodoc_typehints != 'none'):
# Use signatures for overloaded methods instead of the implementation method.
overloaded = True
else:
Expand Down Expand Up @@ -2666,7 +2666,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('autodoc_docstring_signature', True, True)
app.add_config_value('autodoc_mock_imports', [], True)
app.add_config_value('autodoc_typehints', "signature", True,
ENUM("signature", "description", "none"))
ENUM("signature", "description", "none", "both"))
app.add_config_value('autodoc_typehints_description_target', 'all', True,
ENUM('all', 'documented'))
app.add_config_value('autodoc_type_aliases', {}, True)
Expand Down
2 changes: 1 addition & 1 deletion sphinx/ext/autodoc/typehints.py
Expand Up @@ -40,7 +40,7 @@ def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,
def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element) -> None:
if domain != 'py':
return
if app.config.autodoc_typehints != 'description':
if app.config.autodoc_typehints not in ('both', 'description'):
return

try:
Expand Down
2 changes: 2 additions & 0 deletions tests/roots/test-ext-autodoc/index.rst
Expand Up @@ -10,4 +10,6 @@

.. autofunction:: target.typehints.incr

.. autofunction:: target.overload.sum

.. autofunction:: target.typehints.tuple_args
48 changes: 48 additions & 0 deletions tests/test_ext_autodoc_configs.py
Expand Up @@ -695,6 +695,14 @@ def test_autodoc_typehints_description(app):
' Tuple[int, int]\n'
in context)

# Overloads still get displyed in the signature
assert ('target.overload.sum(x: int, y: int = 0) -> int\n'
'target.overload.sum(x: float, y: float = 0.0) -> float\n'
'target.overload.sum(x: str, y: str = None) -> str\n'
'\n'
' docstring\n'
in context)


@pytest.mark.sphinx('text', testroot='ext-autodoc',
confoverrides={'autodoc_typehints': "description",
Expand Down Expand Up @@ -787,6 +795,46 @@ def test_autodoc_typehints_description_for_invalid_node(app):
restructuredtext.parse(app, text) # raises no error


@pytest.mark.sphinx('text', testroot='ext-autodoc',
confoverrides={'autodoc_typehints': "both"})
def test_autodoc_typehints_both(app):
(app.srcdir / 'index.rst').write_text(
'.. autofunction:: target.typehints.incr\n'
'\n'
'.. autofunction:: target.typehints.tuple_args\n'
'\n'
'.. autofunction:: target.overload.sum\n'
)
app.build()
context = (app.outdir / 'index.txt').read_text()
assert ('target.typehints.incr(a: int, b: int = 1) -> int\n'
'\n'
' Parameters:\n'
' * **a** (*int*) --\n'
'\n'
' * **b** (*int*) --\n'
'\n'
' Return type:\n'
' int\n'
in context)
assert ('target.typehints.tuple_args(x: Tuple[int, Union[int, str]]) -> Tuple[int, int]\n'
'\n'
' Parameters:\n'
' **x** (*Tuple**[**int**, **Union**[**int**, **str**]**]*) --\n'
'\n'
' Return type:\n'
' Tuple[int, int]\n'
in context)

# Overloads still get displyed in the signature
assert ('target.overload.sum(x: int, y: int = 0) -> int\n'
'target.overload.sum(x: float, y: float = 0.0) -> float\n'
'target.overload.sum(x: str, y: str = None) -> str\n'
'\n'
' docstring\n'
in context)


@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
@pytest.mark.sphinx('text', testroot='ext-autodoc')
def test_autodoc_type_aliases(app):
Expand Down

0 comments on commit 28d3f81

Please sign in to comment.