diff --git a/src/sphinx_autodoc_typehints/__init__.py b/src/sphinx_autodoc_typehints/__init__.py index 94cd45e8..3176651a 100644 --- a/src/sphinx_autodoc_typehints/__init__.py +++ b/src/sphinx_autodoc_typehints/__init__.py @@ -678,7 +678,7 @@ def node_line_no(node: Node) -> int | None: def tag_name(node: Node) -> str: - return node.tagname # type:ignore[attr-defined,no-any-return] # noqa: SC200 + return node.tagname # type:ignore[attr-defined,no-any-return] def get_insert_index(app: Sphinx, lines: list[str]) -> InsertIndexInfo | None: diff --git a/src/sphinx_autodoc_typehints/patches.py b/src/sphinx_autodoc_typehints/patches.py index b91f839e..4cc6e96c 100644 --- a/src/sphinx_autodoc_typehints/patches.py +++ b/src/sphinx_autodoc_typehints/patches.py @@ -3,6 +3,8 @@ from functools import lru_cache from typing import Any +from docutils.parsers.rst.directives.admonitions import BaseAdmonition +from docutils.parsers.rst.states import Text from sphinx.application import Sphinx from sphinx.ext.autodoc import Options from sphinx.ext.napoleon.docstring import GoogleDocstring @@ -86,11 +88,43 @@ def patch_google_docstring_lookup_annotation() -> None: GoogleDocstring._lookup_annotation = patched_lookup_annotation # type: ignore[assignment] +orig_base_admonition_run = BaseAdmonition.run + + +def patched_base_admonition_run(self: BaseAdmonition) -> Any: + result = orig_base_admonition_run(self) + result[0].line = self.lineno + return result + + +orig_text_indent = Text.indent + + +def patched_text_indent(self: Text, *args: Any) -> Any: + _, line = self.state_machine.get_source_and_line() + result = orig_text_indent(self, *args) + node = self.parent[-1] + if node.tagname == "system_message": + node = self.parent[-2] + node.line = line + return result + + +def patch_line_numbers() -> None: + """Make the rst parser put line numbers on more nodes. + + When the line numbers are missing, we have a hard time placing the :rtype:. + """ + Text.indent = patched_text_indent + BaseAdmonition.run = patched_base_admonition_run + + def install_patches(app: Sphinx) -> None: fix_autodoc_typehints_for_overloaded_methods() patch_attribute_handling(app) patch_google_docstring_lookup_annotation() fix_napoleon_numpy_docstring_return_type(app) + patch_line_numbers() ___all__ = ["install_patches"] diff --git a/tests/test_integration.py b/tests/test_integration.py index 04130224..ace46091 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -999,6 +999,174 @@ def google_docstrings(arg1: CodeType, arg2: ModuleType) -> CodeType: # noqa: U1 """ +@expected( + """ + mod.docstring_with_multiline_note_after_params(param) + + Do something. + + Parameters: + **param** ("int") -- A parameter. + + Return type: + "None" + + Note: + + Some notes. More notes + + """ +) +def docstring_with_multiline_note_after_params(param: int) -> None: # noqa: U100 + """Do something. + + Args: + param: A parameter. + + Note: + + Some notes. + More notes + """ + + +@expected( + """ + mod.docstring_with_bullet_list_after_params(param) + + Do something. + + Parameters: + **param** ("int") -- A parameter. + + Return type: + "None" + + * A: B + + * C: D + + """ +) +def docstring_with_bullet_list_after_params(param: int) -> None: # noqa: U100 + """Do something. + + Args: + param: A parameter. + + * A: B + * C: D + """ + + +@expected( + """ + mod.docstring_with_definition_list_after_params(param) + + Do something. + + Parameters: + **param** ("int") -- A parameter. + + Return type: + "None" + + Term + A description + + maybe multiple lines + + Next Term + Somethign about it + + """ +) +def docstring_with_definition_list_after_params(param: int) -> None: # noqa: U100 + """Do something. + + Args: + param: A parameter. + + Term + A description + + maybe multiple lines + + Next Term + Somethign about it + """ + + +@expected( + """ + mod.docstring_with_enum_list_after_params(param) + + Do something. + + Parameters: + **param** ("int") -- A parameter. + + Return type: + "None" + + 1. A: B + + 2. C: D + + """ +) +def docstring_with_enum_list_after_params(param: int) -> None: # noqa: U100 + """Do something. + + Args: + param: A parameter. + + 1. A: B + 2. C: D + """ + + +@warns("Definition list ends without a blank line") +@expected( + """ + mod.docstring_with_definition_list_after_params_no_blank_line(param) + + Do something. + + Parameters: + **param** ("int") -- A parameter. + + Return type: + "None" + + Term + A description + + maybe multiple lines + + Next Term + Somethign about it + + -[ Example ]- + """ +) +def docstring_with_definition_list_after_params_no_blank_line(param: int) -> None: # noqa: U100 + """Do something. + + Args: + param: A parameter. + + Term + A description + + maybe multiple lines + + Next Term + Somethign about it + .. rubric:: Example + """ + + AUTO_FUNCTION = ".. autofunction:: mod.{}" AUTO_CLASS = """\ .. autoclass:: mod.{} diff --git a/whitelist.txt b/whitelist.txt index 7a2e21de..0e748bdc 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -39,6 +39,7 @@ isfunction iterdir kwonlyargs libs +lineno lru metaclass ModuleType @@ -73,6 +74,7 @@ stmt stringify subclasses supertype +tagname tempdir testroot textwrap