Sphinx 8.1.2__py3-none-any.whl → 8.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Sphinx might be problematic. Click here for more details.

Files changed (328) hide show
  1. sphinx/__init__.py +8 -4
  2. sphinx/__main__.py +2 -0
  3. sphinx/_cli/__init__.py +2 -5
  4. sphinx/_cli/util/colour.py +34 -11
  5. sphinx/_cli/util/errors.py +128 -61
  6. sphinx/addnodes.py +51 -35
  7. sphinx/application.py +362 -230
  8. sphinx/builders/__init__.py +87 -64
  9. sphinx/builders/_epub_base.py +65 -56
  10. sphinx/builders/changes.py +17 -23
  11. sphinx/builders/dirhtml.py +8 -13
  12. sphinx/builders/epub3.py +70 -38
  13. sphinx/builders/gettext.py +93 -73
  14. sphinx/builders/html/__init__.py +240 -186
  15. sphinx/builders/html/_assets.py +9 -2
  16. sphinx/builders/html/_build_info.py +3 -0
  17. sphinx/builders/latex/__init__.py +64 -54
  18. sphinx/builders/latex/constants.py +14 -11
  19. sphinx/builders/latex/nodes.py +2 -0
  20. sphinx/builders/latex/theming.py +8 -9
  21. sphinx/builders/latex/transforms.py +7 -5
  22. sphinx/builders/linkcheck.py +193 -149
  23. sphinx/builders/manpage.py +17 -17
  24. sphinx/builders/singlehtml.py +28 -16
  25. sphinx/builders/texinfo.py +28 -21
  26. sphinx/builders/text.py +10 -15
  27. sphinx/builders/xml.py +10 -19
  28. sphinx/cmd/build.py +49 -119
  29. sphinx/cmd/make_mode.py +35 -31
  30. sphinx/cmd/quickstart.py +78 -62
  31. sphinx/config.py +265 -163
  32. sphinx/directives/__init__.py +51 -54
  33. sphinx/directives/admonitions.py +107 -0
  34. sphinx/directives/code.py +24 -19
  35. sphinx/directives/other.py +21 -42
  36. sphinx/directives/patches.py +28 -16
  37. sphinx/domains/__init__.py +54 -31
  38. sphinx/domains/_domains_container.py +22 -17
  39. sphinx/domains/_index.py +5 -8
  40. sphinx/domains/c/__init__.py +366 -245
  41. sphinx/domains/c/_ast.py +378 -256
  42. sphinx/domains/c/_ids.py +89 -31
  43. sphinx/domains/c/_parser.py +283 -214
  44. sphinx/domains/c/_symbol.py +269 -198
  45. sphinx/domains/changeset.py +39 -24
  46. sphinx/domains/citation.py +54 -24
  47. sphinx/domains/cpp/__init__.py +517 -362
  48. sphinx/domains/cpp/_ast.py +999 -682
  49. sphinx/domains/cpp/_ids.py +133 -65
  50. sphinx/domains/cpp/_parser.py +746 -588
  51. sphinx/domains/cpp/_symbol.py +692 -489
  52. sphinx/domains/index.py +10 -8
  53. sphinx/domains/javascript.py +152 -74
  54. sphinx/domains/math.py +50 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +134 -61
  57. sphinx/domains/python/_object.py +155 -68
  58. sphinx/domains/rst.py +94 -49
  59. sphinx/domains/std/__init__.py +510 -249
  60. sphinx/environment/__init__.py +345 -61
  61. sphinx/environment/adapters/asset.py +7 -1
  62. sphinx/environment/adapters/indexentries.py +15 -20
  63. sphinx/environment/adapters/toctree.py +19 -9
  64. sphinx/environment/collectors/__init__.py +3 -1
  65. sphinx/environment/collectors/asset.py +18 -15
  66. sphinx/environment/collectors/dependencies.py +8 -10
  67. sphinx/environment/collectors/metadata.py +6 -4
  68. sphinx/environment/collectors/title.py +3 -1
  69. sphinx/environment/collectors/toctree.py +4 -4
  70. sphinx/errors.py +1 -3
  71. sphinx/events.py +4 -4
  72. sphinx/ext/apidoc/__init__.py +66 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_extension.py +262 -0
  76. sphinx/ext/apidoc/_generate.py +356 -0
  77. sphinx/ext/apidoc/_shared.py +99 -0
  78. sphinx/ext/autodoc/__init__.py +837 -483
  79. sphinx/ext/autodoc/directive.py +57 -21
  80. sphinx/ext/autodoc/importer.py +184 -67
  81. sphinx/ext/autodoc/mock.py +25 -10
  82. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  83. sphinx/ext/autodoc/type_comment.py +56 -29
  84. sphinx/ext/autodoc/typehints.py +49 -26
  85. sphinx/ext/autosectionlabel.py +28 -11
  86. sphinx/ext/autosummary/__init__.py +281 -142
  87. sphinx/ext/autosummary/generate.py +121 -51
  88. sphinx/ext/coverage.py +152 -91
  89. sphinx/ext/doctest.py +169 -101
  90. sphinx/ext/duration.py +12 -6
  91. sphinx/ext/extlinks.py +33 -21
  92. sphinx/ext/githubpages.py +8 -8
  93. sphinx/ext/graphviz.py +175 -109
  94. sphinx/ext/ifconfig.py +11 -6
  95. sphinx/ext/imgconverter.py +48 -25
  96. sphinx/ext/imgmath.py +127 -97
  97. sphinx/ext/inheritance_diagram.py +177 -103
  98. sphinx/ext/intersphinx/__init__.py +22 -13
  99. sphinx/ext/intersphinx/__main__.py +3 -1
  100. sphinx/ext/intersphinx/_cli.py +18 -14
  101. sphinx/ext/intersphinx/_load.py +91 -82
  102. sphinx/ext/intersphinx/_resolve.py +108 -74
  103. sphinx/ext/intersphinx/_shared.py +2 -2
  104. sphinx/ext/linkcode.py +28 -12
  105. sphinx/ext/mathjax.py +60 -29
  106. sphinx/ext/napoleon/__init__.py +19 -7
  107. sphinx/ext/napoleon/docstring.py +229 -231
  108. sphinx/ext/todo.py +44 -49
  109. sphinx/ext/viewcode.py +105 -57
  110. sphinx/extension.py +3 -1
  111. sphinx/highlighting.py +13 -7
  112. sphinx/io.py +9 -13
  113. sphinx/jinja2glue.py +29 -26
  114. sphinx/locale/__init__.py +8 -9
  115. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  116. sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
  117. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  118. sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
  119. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  120. sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
  121. sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
  122. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
  124. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
  125. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
  126. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
  127. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  128. sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
  129. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  130. sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
  131. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  132. sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
  133. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  134. sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
  135. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  136. sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
  137. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
  139. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
  141. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
  143. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
  145. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
  147. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
  149. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
  151. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
  153. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
  155. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
  157. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
  159. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
  161. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
  163. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
  165. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
  167. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
  169. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
  171. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
  173. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
  175. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
  177. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
  179. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
  181. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
  183. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
  185. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
  187. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
  189. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
  191. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  192. sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
  193. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  194. sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
  195. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  196. sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
  197. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  198. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
  199. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  200. sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
  201. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  202. sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
  203. sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
  204. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
  206. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
  208. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
  210. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
  212. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
  214. sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
  215. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
  217. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
  219. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
  221. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
  223. sphinx/locale/sphinx.pot +2069 -1964
  224. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  225. sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
  226. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  227. sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
  228. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  229. sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
  230. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  231. sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
  232. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  233. sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
  234. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
  236. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
  238. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  239. sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
  240. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  241. sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
  242. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  243. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
  244. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  245. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
  246. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  247. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
  248. sphinx/parsers.py +8 -7
  249. sphinx/project.py +2 -2
  250. sphinx/pycode/__init__.py +31 -21
  251. sphinx/pycode/ast.py +6 -3
  252. sphinx/pycode/parser.py +14 -8
  253. sphinx/pygments_styles.py +4 -5
  254. sphinx/registry.py +192 -92
  255. sphinx/roles.py +58 -7
  256. sphinx/search/__init__.py +75 -54
  257. sphinx/search/en.py +11 -13
  258. sphinx/search/fi.py +1 -1
  259. sphinx/search/ja.py +8 -6
  260. sphinx/search/nl.py +1 -1
  261. sphinx/search/zh.py +19 -21
  262. sphinx/testing/fixtures.py +26 -29
  263. sphinx/testing/path.py +26 -62
  264. sphinx/testing/restructuredtext.py +14 -8
  265. sphinx/testing/util.py +21 -19
  266. sphinx/texinputs/make.bat.jinja +50 -50
  267. sphinx/texinputs/sphinx.sty +4 -3
  268. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  269. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  270. sphinx/themes/basic/static/searchtools.js +8 -5
  271. sphinx/theming.py +49 -61
  272. sphinx/transforms/__init__.py +17 -38
  273. sphinx/transforms/compact_bullet_list.py +5 -3
  274. sphinx/transforms/i18n.py +8 -21
  275. sphinx/transforms/post_transforms/__init__.py +142 -93
  276. sphinx/transforms/post_transforms/code.py +5 -5
  277. sphinx/transforms/post_transforms/images.py +28 -24
  278. sphinx/transforms/references.py +3 -1
  279. sphinx/util/__init__.py +109 -60
  280. sphinx/util/_files.py +39 -23
  281. sphinx/util/_importer.py +4 -1
  282. sphinx/util/_inventory_file_reader.py +76 -0
  283. sphinx/util/_io.py +2 -2
  284. sphinx/util/_lines.py +6 -3
  285. sphinx/util/_pathlib.py +40 -2
  286. sphinx/util/build_phase.py +2 -0
  287. sphinx/util/cfamily.py +19 -14
  288. sphinx/util/console.py +44 -179
  289. sphinx/util/display.py +9 -10
  290. sphinx/util/docfields.py +140 -122
  291. sphinx/util/docstrings.py +1 -1
  292. sphinx/util/docutils.py +118 -77
  293. sphinx/util/fileutil.py +25 -26
  294. sphinx/util/http_date.py +2 -0
  295. sphinx/util/i18n.py +77 -64
  296. sphinx/util/images.py +8 -6
  297. sphinx/util/inspect.py +147 -38
  298. sphinx/util/inventory.py +215 -116
  299. sphinx/util/logging.py +33 -33
  300. sphinx/util/matching.py +12 -4
  301. sphinx/util/nodes.py +18 -13
  302. sphinx/util/osutil.py +38 -39
  303. sphinx/util/parallel.py +22 -13
  304. sphinx/util/parsing.py +2 -1
  305. sphinx/util/png.py +6 -2
  306. sphinx/util/requests.py +33 -2
  307. sphinx/util/rst.py +3 -2
  308. sphinx/util/tags.py +1 -1
  309. sphinx/util/template.py +18 -10
  310. sphinx/util/texescape.py +8 -6
  311. sphinx/util/typing.py +148 -122
  312. sphinx/versioning.py +3 -3
  313. sphinx/writers/html.py +3 -1
  314. sphinx/writers/html5.py +63 -52
  315. sphinx/writers/latex.py +83 -67
  316. sphinx/writers/manpage.py +19 -38
  317. sphinx/writers/texinfo.py +47 -47
  318. sphinx/writers/text.py +50 -32
  319. sphinx/writers/xml.py +11 -8
  320. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
  321. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
  322. sphinx-8.2.0.dist-info/RECORD +606 -0
  323. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
  324. sphinx/builders/html/transforms.py +0 -90
  325. sphinx/ext/apidoc.py +0 -721
  326. sphinx/util/exceptions.py +0 -74
  327. sphinx-8.1.2.dist-info/RECORD +0 -598
  328. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
@@ -2,13 +2,13 @@ from __future__ import annotations
2
2
 
3
3
  import contextlib
4
4
  import re
5
- from typing import TYPE_CHECKING, ClassVar
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from docutils import nodes
8
8
  from docutils.parsers.rst import directives
9
9
 
10
10
  from sphinx import addnodes
11
- from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
11
+ from sphinx.addnodes import pending_xref, pending_xref_condition
12
12
  from sphinx.directives import ObjectDescription
13
13
  from sphinx.domains.python._annotations import (
14
14
  _parse_annotation,
@@ -25,9 +25,13 @@ from sphinx.util.nodes import (
25
25
  )
26
26
 
27
27
  if TYPE_CHECKING:
28
+ from collections.abc import Sequence
29
+ from typing import ClassVar
30
+
28
31
  from docutils.nodes import Node
29
32
  from docutils.parsers.rst.states import Inliner
30
33
 
34
+ from sphinx.addnodes import desc_signature
31
35
  from sphinx.environment import BuildEnvironment
32
36
  from sphinx.util.typing import OptionSpec, TextlikeNode
33
37
 
@@ -35,13 +39,15 @@ logger = logging.getLogger(__name__)
35
39
 
36
40
  # REs for Python signatures
37
41
  py_sig_re = re.compile(
38
- r'''^ ([\w.]*\.)? # class name(s)
42
+ r"""^ ([\w.]*\.)? # class name(s)
39
43
  (\w+) \s* # thing name
40
- (?: \[\s*(.*)\s*])? # optional: type parameters list
44
+ (?: \[\s*(.*?)\s*])? # optional: type parameters list
41
45
  (?: \(\s*(.*)\s*\) # optional: arguments
42
46
  (?:\s* -> \s* (.*))? # return annotation
43
47
  )? $ # and nothing more
44
- ''', re.VERBOSE)
48
+ """,
49
+ re.VERBOSE,
50
+ )
45
51
 
46
52
 
47
53
  # This override allows our inline type specifiers to behave like :class: link
@@ -60,9 +66,16 @@ class PyXrefMixin:
60
66
  ) -> Node:
61
67
  # we use inliner=None to make sure we get the old behaviour with a single
62
68
  # pending_xref node
63
- result = super().make_xref(rolename, domain, target, # type: ignore[misc]
64
- innernode, contnode,
65
- env, inliner=None, location=None)
69
+ result = super().make_xref( # type: ignore[misc]
70
+ rolename,
71
+ domain,
72
+ target,
73
+ innernode,
74
+ contnode,
75
+ env,
76
+ inliner=None,
77
+ location=None,
78
+ )
66
79
  if isinstance(result, pending_xref):
67
80
  assert env is not None
68
81
  result['refspecific'] = True
@@ -82,8 +95,10 @@ class PyXrefMixin:
82
95
 
83
96
  shortname = target.split('.')[-1]
84
97
  textnode = innernode('', shortname) # type: ignore[call-arg]
85
- contnodes = [pending_xref_condition('', '', textnode, condition='resolved'),
86
- pending_xref_condition('', '', *children, condition='*')]
98
+ contnodes = [
99
+ pending_xref_condition('', '', textnode, condition='resolved'),
100
+ pending_xref_condition('', '', *children, condition='*'),
101
+ ]
87
102
  result.extend(contnodes)
88
103
 
89
104
  return result
@@ -116,8 +131,18 @@ class PyXrefMixin:
116
131
  if in_literal or self._delimiters_re.match(sub_target):
117
132
  results.append(contnode or innernode(sub_target, sub_target)) # type: ignore[call-arg]
118
133
  else:
119
- results.append(self.make_xref(rolename, domain, sub_target,
120
- innernode, contnode, env, inliner, location))
134
+ results.append(
135
+ self.make_xref(
136
+ rolename,
137
+ domain,
138
+ sub_target,
139
+ innernode,
140
+ contnode,
141
+ env,
142
+ inliner,
143
+ location,
144
+ )
145
+ )
121
146
 
122
147
  if sub_target in {'Literal', 'typing.Literal', '~typing.Literal'}:
123
148
  in_literal = True
@@ -138,8 +163,7 @@ class PyTypedField(PyXrefMixin, TypedField):
138
163
 
139
164
 
140
165
  class PyObject(ObjectDescription[tuple[str, str]]):
141
- """
142
- Description of a general Python object.
166
+ """Description of a general Python object.
143
167
 
144
168
  :cvar allow_nesting: Class is an object that allows for nested namespaces
145
169
  :vartype allow_nesting: bool
@@ -161,27 +185,55 @@ class PyObject(ObjectDescription[tuple[str, str]]):
161
185
  }
162
186
 
163
187
  doc_field_types = [
164
- PyTypedField('parameter', label=_('Parameters'),
165
- names=('param', 'parameter', 'arg', 'argument',
166
- 'keyword', 'kwarg', 'kwparam'),
167
- typerolename='class', typenames=('paramtype', 'type'),
168
- can_collapse=True),
169
- PyTypedField('variable', label=_('Variables'),
170
- names=('var', 'ivar', 'cvar'),
171
- typerolename='class', typenames=('vartype',),
172
- can_collapse=True),
173
- PyGroupedField('exceptions', label=_('Raises'), rolename='exc',
174
- names=('raises', 'raise', 'exception', 'except'),
175
- can_collapse=True),
176
- Field('returnvalue', label=_('Returns'), has_arg=False,
177
- names=('returns', 'return')),
178
- PyField('returntype', label=_('Return type'), has_arg=False,
179
- names=('rtype',), bodyrolename='class'),
188
+ PyTypedField(
189
+ 'parameter',
190
+ label=_('Parameters'),
191
+ names=(
192
+ 'param',
193
+ 'parameter',
194
+ 'arg',
195
+ 'argument',
196
+ 'keyword',
197
+ 'kwarg',
198
+ 'kwparam',
199
+ ),
200
+ typerolename='class',
201
+ typenames=('paramtype', 'type'),
202
+ can_collapse=True,
203
+ ),
204
+ PyTypedField(
205
+ 'variable',
206
+ label=_('Variables'),
207
+ names=('var', 'ivar', 'cvar'),
208
+ typerolename='class',
209
+ typenames=('vartype',),
210
+ can_collapse=True,
211
+ ),
212
+ PyGroupedField(
213
+ 'exceptions',
214
+ label=_('Raises'),
215
+ rolename='exc',
216
+ names=('raises', 'raise', 'exception', 'except'),
217
+ can_collapse=True,
218
+ ),
219
+ Field(
220
+ 'returnvalue',
221
+ label=_('Returns'),
222
+ has_arg=False,
223
+ names=('returns', 'return'),
224
+ ),
225
+ PyField(
226
+ 'returntype',
227
+ label=_('Return type'),
228
+ has_arg=False,
229
+ names=('rtype',),
230
+ bodyrolename='class',
231
+ ),
180
232
  ]
181
233
 
182
234
  allow_nesting = False
183
235
 
184
- def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
236
+ def get_signature_prefix(self, sig: str) -> Sequence[nodes.Node]:
185
237
  """May return a prefix to put before the object name in the
186
238
  signature.
187
239
  """
@@ -212,18 +264,17 @@ class PyObject(ObjectDescription[tuple[str, str]]):
212
264
  classname = self.env.ref_context.get('py:class')
213
265
  if classname:
214
266
  add_module = False
215
- if prefix and (prefix == classname or
216
- prefix.startswith(classname + ".")):
267
+ if prefix and (prefix == classname or prefix.startswith(f'{classname}.')):
217
268
  fullname = prefix + name
218
269
  # class name is given again in the signature
219
- prefix = prefix[len(classname):].lstrip('.')
270
+ prefix = prefix[len(classname) :].lstrip('.')
220
271
  elif prefix:
221
272
  # class name is given in the signature, but different
222
273
  # (shouldn't happen)
223
- fullname = classname + '.' + prefix + name
274
+ fullname = f'{classname}.{prefix}{name}'
224
275
  else:
225
276
  # class name is not given in the signature
226
- fullname = classname + '.' + name
277
+ fullname = f'{classname}.{name}'
227
278
  else:
228
279
  add_module = True
229
280
  if prefix:
@@ -237,9 +288,11 @@ class PyObject(ObjectDescription[tuple[str, str]]):
237
288
  signode['class'] = classname
238
289
  signode['fullname'] = fullname
239
290
 
240
- max_len = (self.env.config.python_maximum_signature_line_length
241
- or self.env.config.maximum_signature_line_length
242
- or 0)
291
+ max_len = (
292
+ self.config.python_maximum_signature_line_length
293
+ or self.config.maximum_signature_line_length
294
+ or 0
295
+ )
243
296
 
244
297
  # determine if the function arguments (without its type parameters)
245
298
  # should be formatted on a multiline or not by removing the width of
@@ -258,44 +311,72 @@ class PyObject(ObjectDescription[tuple[str, str]]):
258
311
  and (sig_len - (arglist_span[1] - arglist_span[0])) > max_len > 0
259
312
  )
260
313
 
314
+ trailing_comma = self.env.config.python_trailing_comma_in_multi_line_signatures
261
315
  sig_prefix = self.get_signature_prefix(sig)
262
316
  if sig_prefix:
263
317
  if type(sig_prefix) is str:
264
- msg = ("Python directive method get_signature_prefix()"
265
- " must return a list of nodes."
266
- f" Return value was '{sig_prefix}'.")
318
+ msg = (
319
+ 'Python directive method get_signature_prefix()'
320
+ ' must return a list of nodes.'
321
+ f" Return value was '{sig_prefix}'."
322
+ )
267
323
  raise TypeError(msg)
268
324
  signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
269
325
 
270
326
  if prefix:
271
327
  signode += addnodes.desc_addname(prefix, prefix)
272
- elif modname and add_module and self.env.config.add_module_names:
273
- nodetext = modname + '.'
328
+ elif modname and add_module and self.config.add_module_names:
329
+ nodetext = f'{modname}.'
274
330
  signode += addnodes.desc_addname(nodetext, nodetext)
275
331
 
276
332
  signode += addnodes.desc_name(name, name)
277
333
 
278
334
  if tp_list:
279
335
  try:
280
- signode += _parse_type_list(tp_list, self.env, multi_line_type_parameter_list)
336
+ signode += _parse_type_list(
337
+ tp_list,
338
+ self.env,
339
+ multi_line_type_parameter_list,
340
+ trailing_comma,
341
+ )
281
342
  except Exception as exc:
282
- logger.warning("could not parse tp_list (%r): %s", tp_list, exc,
283
- location=signode)
343
+ logger.warning(
344
+ 'could not parse tp_list (%r): %s', tp_list, exc, location=signode
345
+ )
284
346
 
285
347
  if arglist:
286
348
  try:
287
- signode += _parse_arglist(arglist, self.env, multi_line_parameter_list)
288
- except SyntaxError:
349
+ signode += _parse_arglist(
350
+ arglist,
351
+ self.env,
352
+ multi_line_parameter_list,
353
+ trailing_comma,
354
+ )
355
+ except SyntaxError as exc:
289
356
  # fallback to parse arglist original parser
290
357
  # (this may happen if the argument list is incorrectly used
291
358
  # as a list of bases when documenting a class)
292
359
  # it supports to represent optional arguments (ex. "func(foo [, bar])")
293
- _pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
360
+ logger.debug(
361
+ 'syntax error in arglist (%r): %s', arglist, exc, location=signode
362
+ )
363
+ _pseudo_parse_arglist(
364
+ signode,
365
+ arglist,
366
+ multi_line_parameter_list,
367
+ trailing_comma,
368
+ )
294
369
  except (NotImplementedError, ValueError) as exc:
295
370
  # duplicated parameter names raise ValueError and not a SyntaxError
296
- logger.warning("could not parse arglist (%r): %s", arglist, exc,
297
- location=signode)
298
- _pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
371
+ logger.warning(
372
+ 'could not parse arglist (%r): %s', arglist, exc, location=signode
373
+ )
374
+ _pseudo_parse_arglist(
375
+ signode,
376
+ arglist,
377
+ multi_line_parameter_list,
378
+ trailing_comma,
379
+ )
299
380
  else:
300
381
  if self.needs_arglist():
301
382
  # for callables, add an empty parameter list
@@ -307,9 +388,9 @@ class PyObject(ObjectDescription[tuple[str, str]]):
307
388
 
308
389
  anno = self.options.get('annotation')
309
390
  if anno:
310
- signode += addnodes.desc_annotation(' ' + anno, '',
311
- addnodes.desc_sig_space(),
312
- nodes.Text(anno))
391
+ signode += addnodes.desc_annotation(
392
+ f' {anno}', '', addnodes.desc_sig_space(), nodes.Text(anno)
393
+ )
313
394
 
314
395
  return fullname, prefix
315
396
 
@@ -329,10 +410,11 @@ class PyObject(ObjectDescription[tuple[str, str]]):
329
410
  msg = 'must be implemented in subclasses'
330
411
  raise NotImplementedError(msg)
331
412
 
332
- def add_target_and_index(self, name_cls: tuple[str, str], sig: str,
333
- signode: desc_signature) -> None:
334
- modname = self.options.get('module', self.env.ref_context.get('py:module'))
335
- fullname = (modname + '.' if modname else '') + name_cls[0]
413
+ def add_target_and_index(
414
+ self, name_cls: tuple[str, str], sig: str, signode: desc_signature
415
+ ) -> None:
416
+ mod_name = self.options.get('module', self.env.ref_context.get('py:module'))
417
+ fullname = (f'{mod_name}.' if mod_name else '') + name_cls[0]
336
418
  node_id = make_id(self.env, self.state.document, '', fullname)
337
419
  signode['ids'].append(node_id)
338
420
  self.state.document.note_explicit_target(signode)
@@ -342,13 +424,19 @@ class PyObject(ObjectDescription[tuple[str, str]]):
342
424
 
343
425
  canonical_name = self.options.get('canonical')
344
426
  if canonical_name:
345
- domain.note_object(canonical_name, self.objtype, node_id, aliased=True,
346
- location=signode)
427
+ domain.note_object(
428
+ canonical_name, self.objtype, node_id, aliased=True, location=signode
429
+ )
347
430
 
348
431
  if 'no-index-entry' not in self.options:
349
- indextext = self.get_index_text(modname, name_cls)
350
- if indextext:
351
- self.indexnode['entries'].append(('single', indextext, node_id, '', None))
432
+ if index_text := self.get_index_text(mod_name, name_cls):
433
+ self.indexnode['entries'].append((
434
+ 'single',
435
+ index_text,
436
+ node_id,
437
+ '',
438
+ None,
439
+ ))
352
440
 
353
441
  def before_content(self) -> None:
354
442
  """Handle object nesting before content
@@ -398,8 +486,7 @@ class PyObject(ObjectDescription[tuple[str, str]]):
398
486
  with contextlib.suppress(IndexError):
399
487
  classes.pop()
400
488
 
401
- self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0
402
- else None)
489
+ self.env.ref_context['py:class'] = classes[-1] if len(classes) > 0 else None
403
490
  if 'module' in self.options:
404
491
  modules = self.env.ref_context.setdefault('py:modules', [])
405
492
  if modules:
@@ -411,7 +498,7 @@ class PyObject(ObjectDescription[tuple[str, str]]):
411
498
  if not sig_node.get('_toc_parts'):
412
499
  return ''
413
500
 
414
- config = self.env.app.config
501
+ config = self.config
415
502
  objtype = sig_node.parent.get('objtype')
416
503
  if config.add_function_parentheses and objtype in {'function', 'method'}:
417
504
  parens = '()'
sphinx/domains/rst.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import re
6
- from typing import TYPE_CHECKING, Any, ClassVar
6
+ from typing import TYPE_CHECKING
7
7
 
8
8
  from docutils.parsers.rst import directives
9
9
 
@@ -17,7 +17,9 @@ from sphinx.util.nodes import make_id, make_refnode
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from collections.abc import Iterator, Set
20
+ from typing import Any, ClassVar
20
21
 
22
+ from docutils import nodes
21
23
  from docutils.nodes import Element
22
24
 
23
25
  from sphinx.addnodes import desc_signature, pending_xref
@@ -32,9 +34,7 @@ dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$')
32
34
 
33
35
 
34
36
  class ReSTMarkup(ObjectDescription[str]):
35
- """
36
- Description of generic reST markup.
37
- """
37
+ """Description of generic reST markup."""
38
38
 
39
39
  option_spec: ClassVar[OptionSpec] = {
40
40
  'no-index': directives.flag,
@@ -46,7 +46,9 @@ class ReSTMarkup(ObjectDescription[str]):
46
46
  'nocontentsentry': directives.flag,
47
47
  }
48
48
 
49
- def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
49
+ def add_target_and_index(
50
+ self, name: str, sig: str, signode: desc_signature
51
+ ) -> None:
50
52
  node_id = make_id(self.env, self.state.document, self.objtype, name)
51
53
  signode['ids'].append(node_id)
52
54
  self.state.document.note_explicit_target(signode)
@@ -55,9 +57,14 @@ class ReSTMarkup(ObjectDescription[str]):
55
57
  domain.note_object(self.objtype, name, node_id, location=signode)
56
58
 
57
59
  if 'no-index-entry' not in self.options:
58
- indextext = self.get_index_text(self.objtype, name)
59
- if indextext:
60
- self.indexnode['entries'].append(('single', indextext, node_id, '', None))
60
+ if index_text := self.get_index_text(self.objtype, name):
61
+ self.indexnode['entries'].append((
62
+ 'single',
63
+ index_text,
64
+ node_id,
65
+ '',
66
+ None,
67
+ ))
61
68
 
62
69
  def get_index_text(self, objectname: str, name: str) -> str:
63
70
  return ''
@@ -75,12 +82,11 @@ class ReSTMarkup(ObjectDescription[str]):
75
82
  if not sig_node.get('_toc_parts'):
76
83
  return ''
77
84
 
78
- config = self.env.app.config
79
85
  objtype = sig_node.parent.get('objtype')
80
86
  *parents, name = sig_node['_toc_parts']
81
87
  if objtype == 'directive:option':
82
88
  return f':{name}:'
83
- if config.toc_object_entries_show_parents in {'domain', 'all'}:
89
+ if self.config.toc_object_entries_show_parents in {'domain', 'all'}:
84
90
  name = ':'.join(sig_node['_toc_parts'])
85
91
  if objtype == 'role':
86
92
  return f':{name}:'
@@ -98,21 +104,19 @@ def parse_directive(d: str) -> tuple[str, str]:
98
104
  dir = d.strip()
99
105
  if not dir.startswith('.'):
100
106
  # Assume it is a directive without syntax
101
- return (dir, '')
107
+ return dir, ''
102
108
  m = dir_sig_re.match(dir)
103
109
  if not m:
104
- return (dir, '')
110
+ return dir, ''
105
111
  parsed_dir, parsed_args = m.groups()
106
112
  if parsed_args.strip():
107
- return (parsed_dir.strip(), ' ' + parsed_args.strip())
113
+ return parsed_dir.strip(), ' ' + parsed_args.strip()
108
114
  else:
109
- return (parsed_dir.strip(), '')
115
+ return parsed_dir.strip(), ''
110
116
 
111
117
 
112
118
  class ReSTDirective(ReSTMarkup):
113
- """
114
- Description of a reST directive.
115
- """
119
+ """Description of a reST directive."""
116
120
 
117
121
  def handle_signature(self, sig: str, signode: desc_signature) -> str:
118
122
  name, args = parse_directive(sig)
@@ -138,9 +142,7 @@ class ReSTDirective(ReSTMarkup):
138
142
 
139
143
 
140
144
  class ReSTDirectiveOption(ReSTMarkup):
141
- """
142
- Description of an option for reST directive.
143
- """
145
+ """Description of an option for reST directive."""
144
146
 
145
147
  option_spec: ClassVar[OptionSpec] = ReSTMarkup.option_spec.copy()
146
148
  option_spec.update({
@@ -157,13 +159,16 @@ class ReSTDirectiveOption(ReSTMarkup):
157
159
  signode['fullname'] = name.strip()
158
160
  signode += addnodes.desc_name(desc_name, desc_name)
159
161
  if argument:
160
- signode += addnodes.desc_annotation(' ' + argument, ' ' + argument)
162
+ text = f' {argument}'
163
+ signode += addnodes.desc_annotation(text, text)
161
164
  if self.options.get('type'):
162
165
  text = ' (%s)' % self.options['type']
163
166
  signode += addnodes.desc_annotation(text, text)
164
167
  return name
165
168
 
166
- def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
169
+ def add_target_and_index(
170
+ self, name: str, sig: str, signode: desc_signature
171
+ ) -> None:
167
172
  domain = self.env.domains.restructuredtext_domain
168
173
 
169
174
  directive_name = self.current_directive
@@ -181,9 +186,17 @@ class ReSTDirectiveOption(ReSTMarkup):
181
186
 
182
187
  if directive_name:
183
188
  key = name[0].upper()
184
- pair = [_('%s (directive)') % directive_name,
185
- _(':%s: (directive option)') % name]
186
- self.indexnode['entries'].append(('pair', '; '.join(pair), node_id, '', key))
189
+ pair = [
190
+ _('%s (directive)') % directive_name,
191
+ _(':%s: (directive option)') % name,
192
+ ]
193
+ self.indexnode['entries'].append((
194
+ 'pair',
195
+ '; '.join(pair),
196
+ node_id,
197
+ '',
198
+ key,
199
+ ))
187
200
  else:
188
201
  key = name[0].upper()
189
202
  text = _(':%s: (directive option)') % name
@@ -199,9 +212,7 @@ class ReSTDirectiveOption(ReSTMarkup):
199
212
 
200
213
 
201
214
  class ReSTRole(ReSTMarkup):
202
- """
203
- Description of a reST role.
204
- """
215
+ """Description of a reST role."""
205
216
 
206
217
  def handle_signature(self, sig: str, signode: desc_signature) -> str:
207
218
  desc_name = f':{sig}:'
@@ -220,17 +231,17 @@ class ReSTDomain(Domain):
220
231
  label = 'reStructuredText'
221
232
 
222
233
  object_types = {
223
- 'directive': ObjType(_('directive'), 'dir'),
234
+ 'directive': ObjType(_('directive'), 'dir'),
224
235
  'directive:option': ObjType(_('directive-option'), 'dir'),
225
- 'role': ObjType(_('role'), 'role'),
236
+ 'role': ObjType(_('role'), 'role'),
226
237
  }
227
238
  directives = {
228
239
  'directive': ReSTDirective,
229
240
  'directive:option': ReSTDirectiveOption,
230
- 'role': ReSTRole,
241
+ 'role': ReSTRole,
231
242
  }
232
243
  roles = {
233
- 'dir': XRefRole(),
244
+ 'dir': XRefRole(),
234
245
  'role': XRefRole(),
235
246
  }
236
247
  initial_data: dict[str, dict[tuple[str, str], str]] = {
@@ -239,13 +250,21 @@ class ReSTDomain(Domain):
239
250
 
240
251
  @property
241
252
  def objects(self) -> dict[tuple[str, str], tuple[str, str]]:
242
- return self.data.setdefault('objects', {}) # (objtype, fullname) -> (docname, node_id)
253
+ # (objtype, fullname) -> (docname, node_id)
254
+ return self.data.setdefault('objects', {})
243
255
 
244
- def note_object(self, objtype: str, name: str, node_id: str, location: Any = None) -> None:
256
+ def note_object(
257
+ self, objtype: str, name: str, node_id: str, location: Any = None
258
+ ) -> None:
245
259
  if (objtype, name) in self.objects:
246
260
  docname, node_id = self.objects[objtype, name]
247
- logger.warning(__('duplicate description of %s %s, other instance in %s'),
248
- objtype, name, docname, location=location)
261
+ logger.warning(
262
+ __('duplicate description of %s %s, other instance in %s'),
263
+ objtype,
264
+ name,
265
+ docname,
266
+ location=location,
267
+ )
249
268
 
250
269
  self.objects[objtype, name] = (self.env.docname, node_id)
251
270
 
@@ -260,9 +279,16 @@ class ReSTDomain(Domain):
260
279
  if doc in docnames:
261
280
  self.objects[typ, name] = (doc, node_id)
262
281
 
263
- def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
264
- typ: str, target: str, node: pending_xref, contnode: Element,
265
- ) -> Element | None:
282
+ def resolve_xref(
283
+ self,
284
+ env: BuildEnvironment,
285
+ fromdocname: str,
286
+ builder: Builder,
287
+ typ: str,
288
+ target: str,
289
+ node: pending_xref,
290
+ contnode: Element,
291
+ ) -> nodes.reference | None:
266
292
  objtypes = self.objtypes_for_role(typ)
267
293
  if not objtypes:
268
294
  return None
@@ -270,22 +296,41 @@ class ReSTDomain(Domain):
270
296
  result = self.objects.get((objtype, target))
271
297
  if result:
272
298
  todocname, node_id = result
273
- return make_refnode(builder, fromdocname, todocname, node_id,
274
- contnode, target + ' ' + objtype)
299
+ return make_refnode(
300
+ builder,
301
+ fromdocname,
302
+ todocname,
303
+ node_id,
304
+ contnode,
305
+ f'{target} {objtype}',
306
+ )
275
307
  return None
276
308
 
277
- def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
278
- target: str, node: pending_xref, contnode: Element,
279
- ) -> list[tuple[str, Element]]:
280
- results: list[tuple[str, Element]] = []
309
+ def resolve_any_xref(
310
+ self,
311
+ env: BuildEnvironment,
312
+ fromdocname: str,
313
+ builder: Builder,
314
+ target: str,
315
+ node: pending_xref,
316
+ contnode: Element,
317
+ ) -> list[tuple[str, nodes.reference]]:
318
+ results: list[tuple[str, nodes.reference]] = []
281
319
  for objtype in self.object_types:
282
320
  result = self.objects.get((objtype, target))
283
321
  if result:
284
322
  todocname, node_id = result
285
- results.append(
286
- ('rst:' + self.role_for_objtype(objtype), # type: ignore[operator]
287
- make_refnode(builder, fromdocname, todocname, node_id,
288
- contnode, target + ' ' + objtype)))
323
+ results.append((
324
+ f'rst:{self.role_for_objtype(objtype)}',
325
+ make_refnode(
326
+ builder,
327
+ fromdocname,
328
+ todocname,
329
+ node_id,
330
+ contnode,
331
+ f'{target} {objtype}',
332
+ ),
333
+ ))
289
334
  return results
290
335
 
291
336
  def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]: