Skip to content

Commit aa345ca

Browse files
SimonHeybrockpre-commit-ci[bot]gaborbernat
authored
Add typehints_use_rtype option (#218)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bernát Gábor <[email protected]>
1 parent a022d1a commit aa345ca

File tree

6 files changed

+124
-2
lines changed

6 files changed

+124
-2
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ The following configuration options are accepted:
5959
`True`, add stub documentation for undocumented parameters to be able to add type info.
6060
- `typehints_document_rtype` (default: `True`): If `False`, never add an `:rtype:` directive. If `True`, add the
6161
`:rtype:` directive if no existing `:rtype:` is found.
62+
- `typehints_use_rtype` (default: `True`):
63+
Controls behavior when `typehints_document_rtype` is set to `True`.
64+
If `True`, document return type in the `:rtype:` directive.
65+
If `False`, document return type as part of the `:return:` directive, if present, otherwise fall back to using `:rtype:`.
66+
Use in conjunction with [napoleon_use_rtype](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#confval-napoleon_use_rtype) to avoid generation of duplicate or redundant return type information.
6267
- `typehints_defaults` (default: `None`): If `None`, defaults are not added. Otherwise adds a default annotation:
6368

6469
- `'comma'` adds it after the type, changing Sphinx’ default look to “**param** (_int_, default: `1`) -- text”.

src/sphinx_autodoc_typehints/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,20 @@ def _inject_types_to_docstring(
556556
insert_index = None
557557
break
558558
elif line.startswith(":return:") or line.startswith(":returns:"):
559+
if " -- " in line and not app.config.typehints_use_rtype:
560+
insert_index = None
561+
break
559562
insert_index = at
560563

561564
if insert_index is not None and app.config.typehints_document_rtype:
562565
if insert_index == len(lines): # ensure that :rtype: doesn't get joined with a paragraph of text
563566
lines.append("")
564567
insert_index += 1
565-
lines.insert(insert_index, f":rtype: {formatted_annotation}")
568+
if app.config.typehints_use_rtype or insert_index == len(lines):
569+
lines.insert(insert_index, f":rtype: {formatted_annotation}")
570+
else:
571+
line = lines[insert_index]
572+
lines[insert_index] = f":return: {formatted_annotation} --{line[line.find(' '):]}"
566573

567574

568575
def validate_config(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> None: # noqa: U100
@@ -579,6 +586,7 @@ def setup(app: Sphinx) -> dict[str, bool]:
579586
app.add_config_value("always_document_param_types", False, "html")
580587
app.add_config_value("typehints_fully_qualified", False, "env")
581588
app.add_config_value("typehints_document_rtype", True, "env")
589+
app.add_config_value("typehints_use_rtype", True, "env")
582590
app.add_config_value("typehints_defaults", None, "env")
583591
app.add_config_value("simplify_optional_unions", True, "env")
584592
app.add_config_value("typehints_formatter", None, "env")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
def function_no_returns(x: bool, y: int = 1) -> str: # noqa: U100
2+
"""
3+
Function docstring.
4+
5+
:param x: foo
6+
:param y: bar
7+
"""
8+
9+
10+
def function_returns_with_type(x: bool, y: int = 1) -> str: # noqa: U100
11+
"""
12+
Function docstring.
13+
14+
:param x: foo
15+
:param y: bar
16+
:returns: *CustomType* -- A string
17+
"""
18+
19+
20+
def function_returns_with_compound_type(x: bool, y: int = 1) -> str: # noqa: U100
21+
"""
22+
Function docstring.
23+
24+
:param x: foo
25+
:param y: bar
26+
:returns: Union[str, int] -- A string or int
27+
"""
28+
29+
30+
def function_returns_without_type(x: bool, y: int = 1) -> str: # noqa: U100
31+
"""
32+
Function docstring.
33+
34+
:param x: foo
35+
:param y: bar
36+
:returns: A string
37+
"""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Simple Module
2+
=============
3+
4+
.. autofunction:: dummy_module_simple_no_use_rtype.function_no_returns
5+
.. autofunction:: dummy_module_simple_no_use_rtype.function_returns_with_type
6+
.. autofunction:: dummy_module_simple_no_use_rtype.function_returns_with_compound_type
7+
.. autofunction:: dummy_module_simple_no_use_rtype.function_returns_without_type

tests/test_sphinx_autodoc_typehints.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,3 +916,68 @@ def test_no_source_code_type_guard() -> None:
916916
from csv import Error
917917

918918
_resolve_type_guarded_imports(Error)
919+
920+
921+
@pytest.mark.sphinx("text", testroot="dummy")
922+
@patch("sphinx.writers.text.MAXWIDTH", 2000)
923+
def test_sphinx_output_formatter_no_use_rtype(app: SphinxTestApp, status: StringIO) -> None:
924+
set_python_path()
925+
app.config.master_doc = "simple_no_use_rtype" # type: ignore # create flag
926+
app.config.typehints_use_rtype = False # type: ignore
927+
app.build()
928+
assert "build succeeded" in status.getvalue()
929+
text_path = pathlib.Path(app.srcdir) / "_build" / "text" / "simple_no_use_rtype.txt"
930+
text_contents = text_path.read_text().replace("–", "--")
931+
expected_contents = """\
932+
Simple Module
933+
*************
934+
935+
dummy_module_simple_no_use_rtype.function_no_returns(x, y=1)
936+
937+
Function docstring.
938+
939+
Parameters:
940+
* **x** ("bool") -- foo
941+
942+
* **y** ("int") -- bar
943+
944+
Return type:
945+
"str"
946+
947+
dummy_module_simple_no_use_rtype.function_returns_with_type(x, y=1)
948+
949+
Function docstring.
950+
951+
Parameters:
952+
* **x** ("bool") -- foo
953+
954+
* **y** ("int") -- bar
955+
956+
Returns:
957+
*CustomType* -- A string
958+
959+
dummy_module_simple_no_use_rtype.function_returns_with_compound_type(x, y=1)
960+
961+
Function docstring.
962+
963+
Parameters:
964+
* **x** ("bool") -- foo
965+
966+
* **y** ("int") -- bar
967+
968+
Returns:
969+
Union[str, int] -- A string or int
970+
971+
dummy_module_simple_no_use_rtype.function_returns_without_type(x, y=1)
972+
973+
Function docstring.
974+
975+
Parameters:
976+
* **x** ("bool") -- foo
977+
978+
* **y** ("int") -- bar
979+
980+
Returns:
981+
"str" -- A string
982+
"""
983+
assert text_contents == dedent(expected_contents)

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ description = run type check on code base
4545
setenv =
4646
{tty:MYPY_FORCE_COLOR = 1}
4747
deps =
48-
mypy==0.930
48+
mypy==0.931
4949
types-docutils
5050
commands =
5151
mypy --python-version 3.10 src

0 commit comments

Comments
 (0)