diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst index 13a2b30107f..e547e698b11 100644 --- a/doc/usage/extensions/autodoc.rst +++ b/doc/usage/extensions/autodoc.rst @@ -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.1 + + New option ``'both'`` is added. + .. confval:: autodoc_typehints_description_target This value controls whether the types of undocumented parameters and return diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ff6475c9442..d58f3598586 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -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: @@ -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__', {}) @@ -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: @@ -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) diff --git a/sphinx/ext/autodoc/typehints.py b/sphinx/ext/autodoc/typehints.py index 1cc2abd090a..af4b47bb059 100644 --- a/sphinx/ext/autodoc/typehints.py +++ b/sphinx/ext/autodoc/typehints.py @@ -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: diff --git a/tests/roots/test-ext-autodoc/index.rst b/tests/roots/test-ext-autodoc/index.rst index 1746a0a0313..eb10829dcff 100644 --- a/tests/roots/test-ext-autodoc/index.rst +++ b/tests/roots/test-ext-autodoc/index.rst @@ -10,4 +10,6 @@ .. autofunction:: target.typehints.incr +.. autofunction:: target.overload.sum + .. autofunction:: target.typehints.tuple_args diff --git a/tests/test_ext_autodoc_configs.py b/tests/test_ext_autodoc_configs.py index 04d35e3359a..b9bed16352e 100644 --- a/tests/test_ext_autodoc_configs.py +++ b/tests/test_ext_autodoc_configs.py @@ -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", @@ -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):