Repository: tox-dev/sphinx-autodoc-typehints (python)

Issue:
`rtype` of function that returns None is injected into code block
Example: https://jsonyx.readthedocs.io/en/latest/api/jsonyx.dump.html

```python
def dump(...) -> None:
    r"""Serialize a Python object to an open JSON file.

    :raises TypeError: for unserializable values
    :raises ValueError: for invalid values

    >>> import jsonyx as json
    >>> json.dump(["foo", {"bar": ("baz", None, 1.0, 2)}])
    ["foo", {"bar": ["baz", null, 1.0, 2]}]
    >>> from io import StringIO
    >>> io = StringIO()
    >>> json.dump(["streaming API"], io)
    >>> io.getvalue()
    '["streaming API"]\n'
    """
```

<img width="775" alt="Screenshot 2024-09-11 at 19 46 12" src="https://github.com/user-attachments/assets/df99eccf-813a-4ef7-ad1b-986a582c42e5">

Pull request:
Fix placement of return type when there is a doctest
Resolves #480. See upstream bug report here: https://sourceforge.net/p/docutils/patches/211/

Patch:
diff --git a/src/sphinx_autodoc_typehints/patches.py b/src/sphinx_autodoc_typehints/patches.py
index e29a6dc..2307f53 100644
--- a/src/sphinx_autodoc_typehints/patches.py
+++ b/src/sphinx_autodoc_typehints/patches.py
@@ -5,8 +5,9 @@ from __future__ import annotations
 from functools import lru_cache
 from typing import TYPE_CHECKING, Any
 
+from docutils import nodes
 from docutils.parsers.rst.directives.admonitions import BaseAdmonition
-from docutils.parsers.rst.states import Text
+from docutils.parsers.rst.states import Body, Text
 from sphinx.ext.napoleon.docstring import GoogleDocstring
 
 from .attributes_patch import patch_attribute_handling
@@ -110,6 +111,17 @@ def _patched_text_indent(self: Text, *args: Any) -> Any:
     return result
 
 
+def _patched_body_doctest(
+    self: Body, _match: None, _context: None, next_state: str | None
+) -> tuple[list[Any], str | None, list[Any]]:
+    line = self.document.current_line + 1
+    data = "\n".join(self.state_machine.get_text_block())
+    n = nodes.doctest_block(data, data)
+    n.line = line
+    self.parent += n
+    return [], next_state, []
+
+
 def _patch_line_numbers() -> None:
     """
     Make the rst parser put line numbers on more nodes.
@@ -118,6 +130,7 @@ def _patch_line_numbers() -> None:
     """
     Text.indent = _patched_text_indent
     BaseAdmonition.run = _patched_base_admonition_run
+    Body.doctest = _patched_body_doctest
 
 
 def install_patches(app: Sphinx) -> None:


Test patch:
diff --git a/tests/test_integration.py b/tests/test_integration.py
index cbd218e..3339916 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -1359,6 +1359,32 @@ def docstring_with_see_also() -> str:
     return ""
 
 
+@expected(
+    """
+    mod.has_doctest1()
+
+       Test that we place the return type correctly when the function has
+       a doctest.
+
+       Return type:
+          "None"
+
+       >>> this is a fake doctest
+       a
+       >>> more doctest
+       b
+    """
+)
+def has_doctest1() -> None:
+    r"""Test that we place the return type correctly when the function has a doctest.
+
+    >>> this is a fake doctest
+    a
+    >>> more doctest
+    b
+    """
+
+
 # Config settings for each test run.
 # Config Name: Sphinx Options as Dict.
 configs = {