Skip to content

Commit

Permalink
Patch docutils rst parser to add line numbers to more nodes (#316)
Browse files Browse the repository at this point in the history
* Patch docutils rst parser to add line numbers to more nodes

This resolves issue 312. The missing line numbers make it impossible
for us to correctly calculate where to place the rtype.

See upstream issue:
https://sourceforge.net/p/docutils/bugs/465/

I submitted a patch to docutils to fix these things but it is currently
waiting to get through a spam filter. The docutils test suite has no
coverage checking whether this field is filled correctly.

* Remove noqa for spelling error
  • Loading branch information
hoodmane committed Jan 23, 2023
1 parent fa5bd3f commit d9c4a06
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/sphinx_autodoc_typehints/__init__.py
Expand Up @@ -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:
Expand Down
34 changes: 34 additions & 0 deletions src/sphinx_autodoc_typehints/patches.py
Expand Up @@ -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
Expand Down Expand Up @@ -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"]
168 changes: 168 additions & 0 deletions tests/test_integration.py
Expand Up @@ -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.{}
Expand Down
2 changes: 2 additions & 0 deletions whitelist.txt
Expand Up @@ -39,6 +39,7 @@ isfunction
iterdir
kwonlyargs
libs
lineno
lru
metaclass
ModuleType
Expand Down Expand Up @@ -73,6 +74,7 @@ stmt
stringify
subclasses
supertype
tagname
tempdir
testroot
textwrap
Expand Down

0 comments on commit d9c4a06

Please sign in to comment.