Skip to content

Commit d9c4a06

Browse files
authored
Patch docutils rst parser to add line numbers to more nodes (#316)
* 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
1 parent fa5bd3f commit d9c4a06

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

src/sphinx_autodoc_typehints/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ def node_line_no(node: Node) -> int | None:
678678

679679

680680
def tag_name(node: Node) -> str:
681-
return node.tagname # type:ignore[attr-defined,no-any-return] # noqa: SC200
681+
return node.tagname # type:ignore[attr-defined,no-any-return]
682682

683683

684684
def get_insert_index(app: Sphinx, lines: list[str]) -> InsertIndexInfo | None:

src/sphinx_autodoc_typehints/patches.py

+34
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from functools import lru_cache
44
from typing import Any
55

6+
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
7+
from docutils.parsers.rst.states import Text
68
from sphinx.application import Sphinx
79
from sphinx.ext.autodoc import Options
810
from sphinx.ext.napoleon.docstring import GoogleDocstring
@@ -86,11 +88,43 @@ def patch_google_docstring_lookup_annotation() -> None:
8688
GoogleDocstring._lookup_annotation = patched_lookup_annotation # type: ignore[assignment]
8789

8890

91+
orig_base_admonition_run = BaseAdmonition.run
92+
93+
94+
def patched_base_admonition_run(self: BaseAdmonition) -> Any:
95+
result = orig_base_admonition_run(self)
96+
result[0].line = self.lineno
97+
return result
98+
99+
100+
orig_text_indent = Text.indent
101+
102+
103+
def patched_text_indent(self: Text, *args: Any) -> Any:
104+
_, line = self.state_machine.get_source_and_line()
105+
result = orig_text_indent(self, *args)
106+
node = self.parent[-1]
107+
if node.tagname == "system_message":
108+
node = self.parent[-2]
109+
node.line = line
110+
return result
111+
112+
113+
def patch_line_numbers() -> None:
114+
"""Make the rst parser put line numbers on more nodes.
115+
116+
When the line numbers are missing, we have a hard time placing the :rtype:.
117+
"""
118+
Text.indent = patched_text_indent
119+
BaseAdmonition.run = patched_base_admonition_run
120+
121+
89122
def install_patches(app: Sphinx) -> None:
90123
fix_autodoc_typehints_for_overloaded_methods()
91124
patch_attribute_handling(app)
92125
patch_google_docstring_lookup_annotation()
93126
fix_napoleon_numpy_docstring_return_type(app)
127+
patch_line_numbers()
94128

95129

96130
___all__ = ["install_patches"]

tests/test_integration.py

+168
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,174 @@ def google_docstrings(arg1: CodeType, arg2: ModuleType) -> CodeType: # noqa: U1
999999
"""
10001000

10011001

1002+
@expected(
1003+
"""
1004+
mod.docstring_with_multiline_note_after_params(param)
1005+
1006+
Do something.
1007+
1008+
Parameters:
1009+
**param** ("int") -- A parameter.
1010+
1011+
Return type:
1012+
"None"
1013+
1014+
Note:
1015+
1016+
Some notes. More notes
1017+
1018+
"""
1019+
)
1020+
def docstring_with_multiline_note_after_params(param: int) -> None: # noqa: U100
1021+
"""Do something.
1022+
1023+
Args:
1024+
param: A parameter.
1025+
1026+
Note:
1027+
1028+
Some notes.
1029+
More notes
1030+
"""
1031+
1032+
1033+
@expected(
1034+
"""
1035+
mod.docstring_with_bullet_list_after_params(param)
1036+
1037+
Do something.
1038+
1039+
Parameters:
1040+
**param** ("int") -- A parameter.
1041+
1042+
Return type:
1043+
"None"
1044+
1045+
* A: B
1046+
1047+
* C: D
1048+
1049+
"""
1050+
)
1051+
def docstring_with_bullet_list_after_params(param: int) -> None: # noqa: U100
1052+
"""Do something.
1053+
1054+
Args:
1055+
param: A parameter.
1056+
1057+
* A: B
1058+
* C: D
1059+
"""
1060+
1061+
1062+
@expected(
1063+
"""
1064+
mod.docstring_with_definition_list_after_params(param)
1065+
1066+
Do something.
1067+
1068+
Parameters:
1069+
**param** ("int") -- A parameter.
1070+
1071+
Return type:
1072+
"None"
1073+
1074+
Term
1075+
A description
1076+
1077+
maybe multiple lines
1078+
1079+
Next Term
1080+
Somethign about it
1081+
1082+
"""
1083+
)
1084+
def docstring_with_definition_list_after_params(param: int) -> None: # noqa: U100
1085+
"""Do something.
1086+
1087+
Args:
1088+
param: A parameter.
1089+
1090+
Term
1091+
A description
1092+
1093+
maybe multiple lines
1094+
1095+
Next Term
1096+
Somethign about it
1097+
"""
1098+
1099+
1100+
@expected(
1101+
"""
1102+
mod.docstring_with_enum_list_after_params(param)
1103+
1104+
Do something.
1105+
1106+
Parameters:
1107+
**param** ("int") -- A parameter.
1108+
1109+
Return type:
1110+
"None"
1111+
1112+
1. A: B
1113+
1114+
2. C: D
1115+
1116+
"""
1117+
)
1118+
def docstring_with_enum_list_after_params(param: int) -> None: # noqa: U100
1119+
"""Do something.
1120+
1121+
Args:
1122+
param: A parameter.
1123+
1124+
1. A: B
1125+
2. C: D
1126+
"""
1127+
1128+
1129+
@warns("Definition list ends without a blank line")
1130+
@expected(
1131+
"""
1132+
mod.docstring_with_definition_list_after_params_no_blank_line(param)
1133+
1134+
Do something.
1135+
1136+
Parameters:
1137+
**param** ("int") -- A parameter.
1138+
1139+
Return type:
1140+
"None"
1141+
1142+
Term
1143+
A description
1144+
1145+
maybe multiple lines
1146+
1147+
Next Term
1148+
Somethign about it
1149+
1150+
-[ Example ]-
1151+
"""
1152+
)
1153+
def docstring_with_definition_list_after_params_no_blank_line(param: int) -> None: # noqa: U100
1154+
"""Do something.
1155+
1156+
Args:
1157+
param: A parameter.
1158+
1159+
Term
1160+
A description
1161+
1162+
maybe multiple lines
1163+
1164+
Next Term
1165+
Somethign about it
1166+
.. rubric:: Example
1167+
"""
1168+
1169+
10021170
AUTO_FUNCTION = ".. autofunction:: mod.{}"
10031171
AUTO_CLASS = """\
10041172
.. autoclass:: mod.{}

whitelist.txt

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ isfunction
3939
iterdir
4040
kwonlyargs
4141
libs
42+
lineno
4243
lru
4344
metaclass
4445
ModuleType
@@ -73,6 +74,7 @@ stmt
7374
stringify
7475
subclasses
7576
supertype
77+
tagname
7678
tempdir
7779
testroot
7880
textwrap

0 commit comments

Comments
 (0)