Sphinx 7.1.1__py3-none-any.whl → 7.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 (313) hide show
  1. sphinx/__init__.py +6 -6
  2. sphinx/__main__.py +3 -1
  3. sphinx/addnodes.py +35 -22
  4. sphinx/application.py +40 -38
  5. sphinx/builders/__init__.py +16 -12
  6. sphinx/builders/_epub_base.py +15 -11
  7. sphinx/builders/changes.py +6 -4
  8. sphinx/builders/dirhtml.py +4 -2
  9. sphinx/builders/dummy.py +6 -4
  10. sphinx/builders/epub3.py +16 -8
  11. sphinx/builders/gettext.py +40 -43
  12. sphinx/builders/html/__init__.py +166 -196
  13. sphinx/builders/html/_assets.py +116 -0
  14. sphinx/builders/html/transforms.py +4 -2
  15. sphinx/builders/latex/__init__.py +12 -7
  16. sphinx/builders/latex/theming.py +5 -2
  17. sphinx/builders/latex/transforms.py +6 -3
  18. sphinx/builders/linkcheck.py +21 -13
  19. sphinx/builders/manpage.py +6 -4
  20. sphinx/builders/singlehtml.py +16 -9
  21. sphinx/builders/texinfo.py +11 -6
  22. sphinx/builders/text.py +8 -3
  23. sphinx/builders/xml.py +9 -4
  24. sphinx/cmd/build.py +27 -14
  25. sphinx/cmd/make_mode.py +13 -4
  26. sphinx/cmd/quickstart.py +13 -4
  27. sphinx/config.py +17 -14
  28. sphinx/deprecation.py +4 -2
  29. sphinx/directives/__init__.py +44 -12
  30. sphinx/directives/code.py +5 -4
  31. sphinx/directives/other.py +92 -44
  32. sphinx/directives/patches.py +1 -1
  33. sphinx/domains/__init__.py +11 -8
  34. sphinx/domains/c.py +67 -57
  35. sphinx/domains/changeset.py +3 -2
  36. sphinx/domains/citation.py +2 -1
  37. sphinx/domains/cpp.py +136 -93
  38. sphinx/domains/index.py +9 -5
  39. sphinx/domains/javascript.py +32 -19
  40. sphinx/domains/math.py +5 -3
  41. sphinx/domains/python.py +69 -57
  42. sphinx/domains/rst.py +20 -11
  43. sphinx/domains/std.py +21 -15
  44. sphinx/environment/__init__.py +97 -65
  45. sphinx/environment/adapters/indexentries.py +13 -10
  46. sphinx/environment/adapters/toctree.py +485 -308
  47. sphinx/environment/collectors/__init__.py +3 -4
  48. sphinx/environment/collectors/asset.py +10 -4
  49. sphinx/environment/collectors/dependencies.py +7 -4
  50. sphinx/environment/collectors/metadata.py +7 -5
  51. sphinx/environment/collectors/title.py +5 -3
  52. sphinx/environment/collectors/toctree.py +13 -8
  53. sphinx/errors.py +1 -1
  54. sphinx/events.py +5 -5
  55. sphinx/ext/apidoc.py +49 -27
  56. sphinx/ext/autodoc/__init__.py +179 -161
  57. sphinx/ext/autodoc/directive.py +10 -6
  58. sphinx/ext/autodoc/importer.py +22 -13
  59. sphinx/ext/autodoc/mock.py +4 -1
  60. sphinx/ext/autodoc/preserve_defaults.py +80 -12
  61. sphinx/ext/autodoc/type_comment.py +14 -10
  62. sphinx/ext/autodoc/typehints.py +7 -3
  63. sphinx/ext/autosectionlabel.py +6 -3
  64. sphinx/ext/autosummary/__init__.py +21 -15
  65. sphinx/ext/autosummary/generate.py +176 -126
  66. sphinx/ext/coverage.py +93 -8
  67. sphinx/ext/doctest.py +28 -17
  68. sphinx/ext/duration.py +19 -17
  69. sphinx/ext/extlinks.py +11 -6
  70. sphinx/ext/githubpages.py +8 -7
  71. sphinx/ext/graphviz.py +61 -17
  72. sphinx/ext/ifconfig.py +7 -4
  73. sphinx/ext/imgconverter.py +4 -2
  74. sphinx/ext/imgmath.py +29 -23
  75. sphinx/ext/inheritance_diagram.py +41 -27
  76. sphinx/ext/intersphinx.py +45 -38
  77. sphinx/ext/linkcode.py +8 -5
  78. sphinx/ext/mathjax.py +13 -9
  79. sphinx/ext/napoleon/__init__.py +3 -3
  80. sphinx/ext/napoleon/docstring.py +40 -31
  81. sphinx/ext/todo.py +10 -7
  82. sphinx/ext/viewcode.py +46 -25
  83. sphinx/extension.py +1 -1
  84. sphinx/highlighting.py +20 -12
  85. sphinx/io.py +5 -4
  86. sphinx/jinja2glue.py +24 -19
  87. sphinx/locale/__init__.py +8 -2
  88. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  89. sphinx/locale/ar/LC_MESSAGES/sphinx.po +756 -740
  90. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  91. sphinx/locale/bg/LC_MESSAGES/sphinx.po +754 -738
  92. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  93. sphinx/locale/bn/LC_MESSAGES/sphinx.po +755 -739
  94. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  95. sphinx/locale/ca/LC_MESSAGES/sphinx.po +768 -752
  96. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  97. sphinx/locale/cak/LC_MESSAGES/sphinx.po +754 -738
  98. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/cs/LC_MESSAGES/sphinx.po +758 -742
  100. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/cy/LC_MESSAGES/sphinx.po +759 -743
  102. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/da/LC_MESSAGES/sphinx.po +760 -744
  104. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/de/LC_MESSAGES/sphinx.po +759 -743
  106. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +754 -738
  108. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/el/LC_MESSAGES/sphinx.po +763 -747
  110. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +754 -738
  112. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +754 -738
  114. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +768 -752
  116. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +754 -738
  118. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/eo/LC_MESSAGES/sphinx.po +754 -738
  120. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/es/LC_MESSAGES/sphinx.po +767 -751
  122. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +754 -738
  124. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/et/LC_MESSAGES/sphinx.po +762 -746
  126. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/eu/LC_MESSAGES/sphinx.po +755 -739
  128. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/fa/LC_MESSAGES/sphinx.po +766 -750
  130. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/fi/LC_MESSAGES/sphinx.po +754 -738
  132. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/fr/LC_MESSAGES/sphinx.po +768 -752
  134. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +754 -738
  136. sphinx/locale/gl/LC_MESSAGES/sphinx.js +60 -0
  137. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/gl/LC_MESSAGES/sphinx.po +3695 -0
  139. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/he/LC_MESSAGES/sphinx.po +755 -739
  141. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/hi/LC_MESSAGES/sphinx.po +763 -747
  143. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +754 -738
  145. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/hr/LC_MESSAGES/sphinx.po +760 -744
  147. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/hu/LC_MESSAGES/sphinx.po +759 -743
  149. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/id/LC_MESSAGES/sphinx.po +765 -749
  151. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/is/LC_MESSAGES/sphinx.po +760 -744
  153. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/it/LC_MESSAGES/sphinx.po +760 -744
  155. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/ja/LC_MESSAGES/sphinx.po +767 -751
  157. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/ka/LC_MESSAGES/sphinx.po +759 -743
  159. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/ko/LC_MESSAGES/sphinx.po +767 -751
  161. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/lt/LC_MESSAGES/sphinx.po +755 -739
  163. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/lv/LC_MESSAGES/sphinx.po +755 -739
  165. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/mk/LC_MESSAGES/sphinx.po +754 -738
  167. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +755 -739
  169. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ne/LC_MESSAGES/sphinx.po +755 -739
  171. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/nl/LC_MESSAGES/sphinx.po +760 -744
  173. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/pl/LC_MESSAGES/sphinx.po +762 -745
  175. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/pt/LC_MESSAGES/sphinx.po +754 -738
  177. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +768 -752
  179. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +755 -739
  181. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/ro/LC_MESSAGES/sphinx.po +759 -743
  183. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/ru/LC_MESSAGES/sphinx.po +760 -744
  185. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/si/LC_MESSAGES/sphinx.po +754 -738
  187. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/sk/LC_MESSAGES/sphinx.po +765 -749
  189. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/sl/LC_MESSAGES/sphinx.po +755 -739
  191. sphinx/locale/sphinx.pot +748 -740
  192. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/sq/LC_MESSAGES/sphinx.po +768 -752
  194. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/sr/LC_MESSAGES/sphinx.po +754 -738
  196. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +754 -738
  198. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +754 -738
  200. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sv/LC_MESSAGES/sphinx.po +755 -739
  202. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/ta/LC_MESSAGES/sphinx.po +754 -738
  204. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/te/LC_MESSAGES/sphinx.po +754 -738
  206. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/tr/LC_MESSAGES/sphinx.po +763 -747
  208. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +760 -749
  210. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/ur/LC_MESSAGES/sphinx.po +759 -748
  212. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/vi/LC_MESSAGES/sphinx.po +754 -738
  214. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  215. sphinx/locale/yue/LC_MESSAGES/sphinx.po +754 -738
  216. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  217. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +768 -752
  218. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  219. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +754 -738
  220. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  221. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +767 -751
  222. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  223. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +754 -738
  224. sphinx/parsers.py +5 -4
  225. sphinx/project.py +52 -34
  226. sphinx/pycode/__init__.py +2 -1
  227. sphinx/pycode/ast.py +7 -13
  228. sphinx/pycode/parser.py +42 -38
  229. sphinx/registry.py +35 -29
  230. sphinx/roles.py +9 -4
  231. sphinx/search/__init__.py +5 -17
  232. sphinx/search/da.py +1 -1
  233. sphinx/search/de.py +1 -1
  234. sphinx/search/en.py +1 -1
  235. sphinx/search/es.py +1 -1
  236. sphinx/search/fi.py +1 -1
  237. sphinx/search/fr.py +1 -1
  238. sphinx/search/hu.py +1 -1
  239. sphinx/search/it.py +1 -1
  240. sphinx/search/ja.py +1 -1
  241. sphinx/search/nl.py +1 -1
  242. sphinx/search/no.py +1 -1
  243. sphinx/search/pt.py +1 -1
  244. sphinx/search/ro.py +1 -1
  245. sphinx/search/ru.py +1 -1
  246. sphinx/search/sv.py +1 -1
  247. sphinx/search/tr.py +1 -1
  248. sphinx/search/zh.py +1 -1
  249. sphinx/testing/fixtures.py +23 -30
  250. sphinx/testing/path.py +9 -0
  251. sphinx/testing/restructuredtext.py +13 -5
  252. sphinx/testing/util.py +20 -63
  253. sphinx/texinputs/sphinxlatexobjects.sty +15 -15
  254. sphinx/themes/agogo/static/agogo.css_t +10 -4
  255. sphinx/themes/basic/layout.html +1 -1
  256. sphinx/themes/basic/static/basic.css_t +4 -0
  257. sphinx/themes/basic/static/documentation_options.js_t +1 -2
  258. sphinx/themes/basic/static/searchtools.js +17 -9
  259. sphinx/themes/basic/static/sphinx_highlight.js +13 -3
  260. sphinx/themes/bizstyle/static/bizstyle.css_t +4 -0
  261. sphinx/themes/classic/theme.conf +1 -1
  262. sphinx/themes/epub/static/epub.css_t +6 -1
  263. sphinx/themes/haiku/theme.conf +1 -1
  264. sphinx/themes/nature/static/nature.css_t +4 -0
  265. sphinx/themes/nonav/static/nonav.css_t +6 -1
  266. sphinx/themes/pyramid/static/pyramid.css_t +4 -0
  267. sphinx/themes/scrolls/static/scrolls.css_t +4 -0
  268. sphinx/themes/scrolls/theme.conf +1 -1
  269. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +4 -0
  270. sphinx/theming.py +9 -7
  271. sphinx/transforms/__init__.py +79 -3
  272. sphinx/transforms/compact_bullet_list.py +6 -3
  273. sphinx/transforms/i18n.py +26 -10
  274. sphinx/transforms/post_transforms/__init__.py +21 -8
  275. sphinx/transforms/post_transforms/code.py +6 -3
  276. sphinx/transforms/post_transforms/images.py +13 -9
  277. sphinx/util/__init__.py +21 -92
  278. sphinx/util/cfamily.py +7 -4
  279. sphinx/util/display.py +3 -2
  280. sphinx/util/docfields.py +7 -6
  281. sphinx/util/docstrings.py +1 -1
  282. sphinx/util/docutils.py +41 -31
  283. sphinx/util/fileutil.py +9 -6
  284. sphinx/util/i18n.py +21 -18
  285. sphinx/util/images.py +2 -1
  286. sphinx/util/index_entries.py +27 -0
  287. sphinx/util/inspect.py +83 -67
  288. sphinx/util/inventory.py +4 -2
  289. sphinx/util/logging.py +9 -6
  290. sphinx/util/matching.py +5 -2
  291. sphinx/util/math.py +6 -3
  292. sphinx/util/nodes.py +70 -31
  293. sphinx/util/osutil.py +22 -40
  294. sphinx/util/parallel.py +4 -1
  295. sphinx/util/rst.py +7 -3
  296. sphinx/util/tags.py +11 -4
  297. sphinx/util/template.py +17 -14
  298. sphinx/util/typing.py +61 -20
  299. sphinx/versioning.py +6 -4
  300. sphinx/writers/html.py +1 -1
  301. sphinx/writers/html5.py +32 -24
  302. sphinx/writers/latex.py +67 -53
  303. sphinx/writers/manpage.py +9 -5
  304. sphinx/writers/texinfo.py +11 -9
  305. sphinx/writers/text.py +14 -9
  306. sphinx/writers/xml.py +3 -2
  307. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/METADATA +7 -5
  308. sphinx-7.2.0.dist-info/RECORD +568 -0
  309. sphinx/testing/comparer.py +0 -97
  310. sphinx-7.1.1.dist-info/RECORD +0 -564
  311. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/LICENSE +0 -0
  312. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/WHEEL +0 -0
  313. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/entry_points.txt +0 -0
@@ -31,19 +31,18 @@ LaTeX.
31
31
  from __future__ import annotations
32
32
 
33
33
  import builtins
34
+ import hashlib
34
35
  import inspect
35
36
  import re
37
+ from collections.abc import Iterable, Sequence
36
38
  from importlib import import_module
37
- from typing import Any, Iterable, cast
39
+ from typing import TYPE_CHECKING, Any, cast
38
40
 
39
41
  from docutils import nodes
40
- from docutils.nodes import Node
41
42
  from docutils.parsers.rst import directives
42
43
 
43
44
  import sphinx
44
45
  from sphinx import addnodes
45
- from sphinx.application import Sphinx
46
- from sphinx.environment import BuildEnvironment
47
46
  from sphinx.ext.graphviz import (
48
47
  figure_wrapper,
49
48
  graphviz,
@@ -51,12 +50,17 @@ from sphinx.ext.graphviz import (
51
50
  render_dot_latex,
52
51
  render_dot_texinfo,
53
52
  )
54
- from sphinx.util import md5
55
53
  from sphinx.util.docutils import SphinxDirective
56
- from sphinx.util.typing import OptionSpec
57
- from sphinx.writers.html import HTML5Translator
58
- from sphinx.writers.latex import LaTeXTranslator
59
- from sphinx.writers.texinfo import TexinfoTranslator
54
+
55
+ if TYPE_CHECKING:
56
+ from docutils.nodes import Node
57
+
58
+ from sphinx.application import Sphinx
59
+ from sphinx.environment import BuildEnvironment
60
+ from sphinx.util.typing import OptionSpec
61
+ from sphinx.writers.html import HTML5Translator
62
+ from sphinx.writers.latex import LaTeXTranslator
63
+ from sphinx.writers.texinfo import TexinfoTranslator
60
64
 
61
65
  module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
62
66
  (\w+) \s* $ # class/final module name
@@ -139,7 +143,7 @@ class InheritanceGraph:
139
143
  """
140
144
  def __init__(self, class_names: list[str], currmodule: str, show_builtins: bool = False,
141
145
  private_bases: bool = False, parts: int = 0,
142
- aliases: dict[str, str] | None = None, top_classes: list[Any] = [],
146
+ aliases: dict[str, str] | None = None, top_classes: Sequence[Any] = (),
143
147
  ) -> None:
144
148
  """*class_names* is a list of child classes to show bases from.
145
149
 
@@ -151,8 +155,8 @@ class InheritanceGraph:
151
155
  self.class_info = self._class_info(classes, show_builtins,
152
156
  private_bases, parts, aliases, top_classes)
153
157
  if not self.class_info:
154
- raise InheritanceException('No classes found for '
155
- 'inheritance diagram')
158
+ msg = 'No classes found for inheritance diagram'
159
+ raise InheritanceException(msg)
156
160
 
157
161
  def _import_classes(self, class_names: list[str], currmodule: str) -> list[Any]:
158
162
  """Import a list of classes."""
@@ -162,7 +166,7 @@ class InheritanceGraph:
162
166
  return classes
163
167
 
164
168
  def _class_info(self, classes: list[Any], show_builtins: bool, private_bases: bool,
165
- parts: int, aliases: dict[str, str], top_classes: list[Any],
169
+ parts: int, aliases: dict[str, str] | None, top_classes: Sequence[Any],
166
170
  ) -> list[tuple[str, str, list[str], str]]:
167
171
  """Return name and bases for all classes that are ancestors of
168
172
  *classes*.
@@ -218,7 +222,7 @@ class InheritanceGraph:
218
222
  for cls in classes:
219
223
  recurse(cls)
220
224
 
221
- return list(all_classes.values())
225
+ return list(all_classes.values()) # type: ignore[arg-type]
222
226
 
223
227
  def class_name(
224
228
  self, cls: Any, parts: int = 0, aliases: dict[str, str] | None = None,
@@ -272,9 +276,11 @@ class InheritanceGraph:
272
276
  def _format_graph_attrs(self, attrs: dict[str, Any]) -> str:
273
277
  return ''.join(['%s=%s;\n' % x for x in sorted(attrs.items())])
274
278
 
275
- def generate_dot(self, name: str, urls: dict[str, str] = {},
279
+ def generate_dot(self, name: str, urls: dict[str, str] | None = None,
276
280
  env: BuildEnvironment | None = None,
277
- graph_attrs: dict = {}, node_attrs: dict = {}, edge_attrs: dict = {},
281
+ graph_attrs: dict | None = None,
282
+ node_attrs: dict | None = None,
283
+ edge_attrs: dict | None = None,
278
284
  ) -> str:
279
285
  """Generate a graphviz dot graph from the classes that were passed in
280
286
  to __init__.
@@ -286,12 +292,17 @@ class InheritanceGraph:
286
292
  *graph_attrs*, *node_attrs*, *edge_attrs* are dictionaries containing
287
293
  key/value pairs to pass on as graphviz properties.
288
294
  """
295
+ if urls is None:
296
+ urls = {}
289
297
  g_attrs = self.default_graph_attrs.copy()
290
298
  n_attrs = self.default_node_attrs.copy()
291
299
  e_attrs = self.default_edge_attrs.copy()
292
- g_attrs.update(graph_attrs)
293
- n_attrs.update(node_attrs)
294
- e_attrs.update(edge_attrs)
300
+ if graph_attrs is not None:
301
+ g_attrs.update(graph_attrs)
302
+ if node_attrs is not None:
303
+ n_attrs.update(node_attrs)
304
+ if edge_attrs is not None:
305
+ e_attrs.update(edge_attrs)
295
306
  if env:
296
307
  g_attrs.update(env.config.inheritance_graph_attrs)
297
308
  n_attrs.update(env.config.inheritance_node_attrs)
@@ -360,7 +371,7 @@ class InheritanceDiagram(SphinxDirective):
360
371
  # Create a graph starting with the list of classes
361
372
  try:
362
373
  graph = InheritanceGraph(
363
- class_names, self.env.ref_context.get('py:module'),
374
+ class_names, self.env.ref_context.get('py:module'), # type: ignore[arg-type]
364
375
  parts=node['parts'],
365
376
  private_bases='private-bases' in self.options,
366
377
  aliases=self.config.inheritance_alias,
@@ -373,8 +384,8 @@ class InheritanceDiagram(SphinxDirective):
373
384
  # references to real URLs later. These nodes will eventually be
374
385
  # removed from the doctree after we're done with them.
375
386
  for name in graph.get_all_class_names():
376
- refnodes, x = class_role( # type: ignore
377
- 'class', ':class:`%s`' % name, name, 0, self.state) # type: ignore
387
+ refnodes, x = class_role( # type: ignore[call-arg,misc]
388
+ 'class', ':class:`%s`' % name, name, 0, self.state) # type: ignore[arg-type]
378
389
  node.extend(refnodes)
379
390
  # Store the graph object so we can use it to generate the
380
391
  # dot file later
@@ -391,7 +402,7 @@ class InheritanceDiagram(SphinxDirective):
391
402
 
392
403
  def get_graph_hash(node: inheritance_diagram) -> str:
393
404
  encoded = (node['content'] + str(node['parts'])).encode()
394
- return md5(encoded).hexdigest()[-10:]
405
+ return hashlib.md5(encoded, usedforsecurity=False).hexdigest()[-10:]
395
406
 
396
407
 
397
408
  def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diagram) -> None:
@@ -411,13 +422,16 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag
411
422
  pending_xrefs = cast(Iterable[addnodes.pending_xref], node)
412
423
  for child in pending_xrefs:
413
424
  if child.get('refuri') is not None:
414
- if graphviz_output_format == 'SVG':
415
- urls[child['reftitle']] = "../" + child.get('refuri')
425
+ # Construct the name from the URI if the reference is external via intersphinx
426
+ if not child.get('internal', True):
427
+ refname = child['refuri'].rsplit('#', 1)[-1]
416
428
  else:
417
- urls[child['reftitle']] = child.get('refuri')
429
+ refname = child['reftitle']
430
+
431
+ urls[refname] = child.get('refuri')
418
432
  elif child.get('refid') is not None:
419
433
  if graphviz_output_format == 'SVG':
420
- urls[child['reftitle']] = '../' + current_filename + '#' + child.get('refid')
434
+ urls[child['reftitle']] = current_filename + '#' + child.get('refid')
421
435
  else:
422
436
  urls[child['reftitle']] = '#' + child.get('refid')
423
437
 
sphinx/ext/intersphinx.py CHANGED
@@ -25,7 +25,7 @@ import re
25
25
  import sys
26
26
  import time
27
27
  from os import path
28
- from typing import IO, TYPE_CHECKING, Any, Iterable, cast
28
+ from typing import TYPE_CHECKING, cast
29
29
  from urllib.parse import urlsplit, urlunsplit
30
30
 
31
31
  from docutils import nodes
@@ -42,8 +42,9 @@ from sphinx.util.docutils import CustomReSTDispatcher, SphinxRole
42
42
  from sphinx.util.inventory import InventoryFile
43
43
 
44
44
  if TYPE_CHECKING:
45
+ from collections.abc import Iterable
45
46
  from types import ModuleType
46
- from typing import Tuple, Union
47
+ from typing import IO, Any, Union
47
48
 
48
49
  from docutils.nodes import Node, TextElement, system_message
49
50
  from docutils.utils import Reporter
@@ -54,7 +55,7 @@ if TYPE_CHECKING:
54
55
  from sphinx.environment import BuildEnvironment
55
56
  from sphinx.util.typing import Inventory, InventoryItem, RoleFunction
56
57
 
57
- InventoryCacheEntry = Tuple[Union[str, None], int, Inventory]
58
+ InventoryCacheEntry = tuple[Union[str, None], int, Inventory]
58
59
 
59
60
  logger = logging.getLogger(__name__)
60
61
 
@@ -67,10 +68,10 @@ class InventoryAdapter:
67
68
 
68
69
  if not hasattr(env, 'intersphinx_cache'):
69
70
  # initial storage when fetching inventories before processing
70
- self.env.intersphinx_cache = {} # type: ignore
71
+ self.env.intersphinx_cache = {} # type: ignore[attr-defined]
71
72
 
72
- self.env.intersphinx_inventory = {} # type: ignore
73
- self.env.intersphinx_named_inventory = {} # type: ignore
73
+ self.env.intersphinx_inventory = {} # type: ignore[attr-defined]
74
+ self.env.intersphinx_named_inventory = {} # type: ignore[attr-defined]
74
75
 
75
76
  @property
76
77
  def cache(self) -> dict[str, InventoryCacheEntry]:
@@ -82,19 +83,19 @@ class InventoryAdapter:
82
83
  - Element two is a time value for cache invalidation, a float
83
84
  - Element three is the loaded remote inventory, type Inventory
84
85
  """
85
- return self.env.intersphinx_cache # type: ignore
86
+ return self.env.intersphinx_cache # type: ignore[attr-defined]
86
87
 
87
88
  @property
88
89
  def main_inventory(self) -> Inventory:
89
- return self.env.intersphinx_inventory # type: ignore
90
+ return self.env.intersphinx_inventory # type: ignore[attr-defined]
90
91
 
91
92
  @property
92
93
  def named_inventory(self) -> dict[str, Inventory]:
93
- return self.env.intersphinx_named_inventory # type: ignore
94
+ return self.env.intersphinx_named_inventory # type: ignore[attr-defined]
94
95
 
95
96
  def clear(self) -> None:
96
- self.env.intersphinx_inventory.clear() # type: ignore
97
- self.env.intersphinx_named_inventory.clear() # type: ignore
97
+ self.env.intersphinx_inventory.clear() # type: ignore[attr-defined]
98
+ self.env.intersphinx_named_inventory.clear() # type: ignore[attr-defined]
98
99
 
99
100
 
100
101
  def _strip_basic_auth(url: str) -> str:
@@ -118,7 +119,7 @@ def _strip_basic_auth(url: str) -> str:
118
119
  return urlunsplit(frags)
119
120
 
120
121
 
121
- def _read_from_url(url: str, config: Config | None = None) -> IO:
122
+ def _read_from_url(url: str, *, config: Config) -> IO:
122
123
  """Reads data from *url* with an HTTP *GET*.
123
124
 
124
125
  This function supports fetching from resources which use basic HTTP auth as
@@ -174,15 +175,14 @@ def fetch_inventory(app: Sphinx, uri: str, inv: str) -> Inventory:
174
175
  """Fetch, parse and return an intersphinx inventory file."""
175
176
  # both *uri* (base URI of the links to generate) and *inv* (actual
176
177
  # location of the inventory file) can be local or remote URIs
177
- localuri = '://' not in uri
178
- if not localuri:
178
+ if '://' in uri:
179
179
  # case: inv URI points to remote resource; strip any existing auth
180
180
  uri = _strip_basic_auth(uri)
181
181
  try:
182
182
  if '://' in inv:
183
183
  f = _read_from_url(inv, config=app.config)
184
184
  else:
185
- f = open(path.join(app.srcdir, inv), 'rb')
185
+ f = open(path.join(app.srcdir, inv), 'rb') # NoQA: SIM115
186
186
  except Exception as err:
187
187
  err.args = ('intersphinx inventory %r not fetchable due to %s: %s',
188
188
  inv, err.__class__, str(err))
@@ -197,8 +197,7 @@ def fetch_inventory(app: Sphinx, uri: str, inv: str) -> Inventory:
197
197
  uri = path.dirname(newinv)
198
198
  with f:
199
199
  try:
200
- join = path.join if localuri else posixpath.join
201
- invdata = InventoryFile.load(f, uri, join)
200
+ invdata = InventoryFile.load(f, uri, posixpath.join)
202
201
  except ValueError as exc:
203
202
  raise ValueError('unknown or unsupported inventory version: %r' % exc) from exc
204
203
  except Exception as err:
@@ -298,7 +297,7 @@ def _create_element_from_result(domain: Domain, inv_name: str | None,
298
297
  proj, version, uri, dispname = data
299
298
  if '://' not in uri and node.get('refdoc'):
300
299
  # get correct path in case of subdirectories
301
- uri = path.join(relative_path(node['refdoc'], '.'), uri)
300
+ uri = posixpath.join(relative_path(node['refdoc'], '.'), uri)
302
301
  if version:
303
302
  reftitle = _('(in %s v%s)') % (proj, version)
304
303
  else:
@@ -429,7 +428,7 @@ def _resolve_reference(env: BuildEnvironment, inv_name: str | None, inventory: I
429
428
  and (domain_name + ":*") in env.config.intersphinx_disabled_reftypes:
430
429
  return None
431
430
  domain = env.get_domain(domain_name)
432
- objtypes = domain.objtypes_for_role(typ)
431
+ objtypes = domain.objtypes_for_role(typ) or ()
433
432
  if not objtypes:
434
433
  return None
435
434
  return _resolve_reference_in_domain(env, inv_name, inventory,
@@ -554,15 +553,21 @@ class IntersphinxRole(SphinxRole):
554
553
 
555
554
  def get_inventory_and_name_suffix(self, name: str) -> tuple[str | None, str]:
556
555
  assert name.startswith('external'), name
557
- assert name[8] in ':+', name
558
556
  # either we have an explicit inventory name, i.e,
559
557
  # :external+inv:role: or
560
558
  # :external+inv:domain:role:
561
559
  # or we look in all inventories, i.e.,
562
560
  # :external:role: or
563
561
  # :external:domain:role:
564
- inv, suffix = IntersphinxRole._re_inv_ref.fullmatch(name, 8).group(2, 3)
565
- return inv, suffix
562
+ suffix = name[9:]
563
+ if name[8] == '+':
564
+ inv_name, suffix = suffix.split(':', 1)
565
+ return inv_name, suffix
566
+ elif name[8] == ':':
567
+ return None, suffix
568
+ else:
569
+ msg = f'Malformed :external: role name: {name}'
570
+ raise ValueError(msg)
566
571
 
567
572
  def get_role_name(self, name: str) -> tuple[str, str] | None:
568
573
  names = name.split(':')
@@ -596,6 +601,7 @@ class IntersphinxRole(SphinxRole):
596
601
  domain = self.env.get_domain(role[0])
597
602
  if domain:
598
603
  role_func = domain.role(role[1])
604
+ assert role_func is not None
599
605
 
600
606
  return role_func(':'.join(role), self.rawtext, self.text, self.lineno,
601
607
  self.inliner, self.options, self.content)
@@ -692,44 +698,45 @@ def setup(app: Sphinx) -> dict[str, Any]:
692
698
  }
693
699
 
694
700
 
695
- def inspect_main(argv: list[str]) -> None:
701
+ def inspect_main(argv: list[str], /) -> int:
696
702
  """Debug functionality to print out an inventory"""
697
703
  if len(argv) < 1:
698
704
  print("Print out an inventory file.\n"
699
705
  "Error: must specify local path or URL to an inventory file.",
700
706
  file=sys.stderr)
701
- raise SystemExit(1)
707
+ return 1
702
708
 
703
709
  class MockConfig:
704
710
  intersphinx_timeout: int | None = None
705
711
  tls_verify = False
706
- tls_cacerts = None
707
- user_agent = None
712
+ tls_cacerts: str | dict[str, str] | None = None
713
+ user_agent: str = ''
708
714
 
709
715
  class MockApp:
710
716
  srcdir = ''
711
717
  config = MockConfig()
712
718
 
713
- def warn(self, msg: str) -> None:
714
- print(msg, file=sys.stderr)
715
-
716
719
  try:
717
720
  filename = argv[0]
718
- invdata = fetch_inventory(MockApp(), '', filename) # type: ignore
719
- for key in sorted(invdata or {}):
721
+ inv_data = fetch_inventory(MockApp(), '', filename) # type: ignore[arg-type]
722
+ for key in sorted(inv_data or {}):
720
723
  print(key)
721
- for entry, einfo in sorted(invdata[key].items()):
722
- print('\t%-40s %s%s' % (entry,
723
- '%-40s: ' % einfo[3] if einfo[3] != '-' else '',
724
- einfo[2]))
724
+ inv_entries = sorted(inv_data[key].items())
725
+ for entry, (_proj, _ver, url_path, display_name) in inv_entries:
726
+ display_name = display_name * (display_name != '-')
727
+ print(f' {entry:<40} {display_name:<40}: {url_path}')
725
728
  except ValueError as exc:
726
- print(exc.args[0] % exc.args[1:])
729
+ print(exc.args[0] % exc.args[1:], file=sys.stderr)
730
+ return 1
727
731
  except Exception as exc:
728
- print('Unknown error: %r' % exc)
732
+ print(f'Unknown error: {exc!r}', file=sys.stderr)
733
+ return 1
734
+ else:
735
+ return 0
729
736
 
730
737
 
731
738
  if __name__ == '__main__':
732
739
  import logging as _logging
733
740
  _logging.basicConfig()
734
741
 
735
- inspect_main(argv=sys.argv[1:])
742
+ raise SystemExit(inspect_main(sys.argv[1:]))
sphinx/ext/linkcode.py CHANGED
@@ -2,17 +2,20 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from docutils import nodes
8
- from docutils.nodes import Node
9
8
 
10
9
  import sphinx
11
10
  from sphinx import addnodes
12
- from sphinx.application import Sphinx
13
11
  from sphinx.errors import SphinxError
14
12
  from sphinx.locale import _
15
13
 
14
+ if TYPE_CHECKING:
15
+ from docutils.nodes import Node
16
+
17
+ from sphinx.application import Sphinx
18
+
16
19
 
17
20
  class LinkcodeError(SphinxError):
18
21
  category = "linkcode error"
@@ -23,8 +26,8 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
23
26
 
24
27
  resolve_target = getattr(env.config, 'linkcode_resolve', None)
25
28
  if not callable(env.config.linkcode_resolve):
26
- raise LinkcodeError(
27
- "Function `linkcode_resolve` is not given in conf.py")
29
+ msg = 'Function `linkcode_resolve` is not given in conf.py'
30
+ raise LinkcodeError(msg)
28
31
  assert resolve_target is not None # for mypy
29
32
 
30
33
  domain_keys = {
sphinx/ext/mathjax.py CHANGED
@@ -8,17 +8,20 @@ This requires the MathJax JavaScript library on your webserver/computer.
8
8
  from __future__ import annotations
9
9
 
10
10
  import json
11
- from typing import Any, cast
11
+ from typing import TYPE_CHECKING, Any, cast
12
12
 
13
13
  from docutils import nodes
14
14
 
15
15
  import sphinx
16
- from sphinx.application import Sphinx
16
+ from sphinx.builders.html import StandaloneHTMLBuilder
17
17
  from sphinx.domains.math import MathDomain
18
18
  from sphinx.errors import ExtensionError
19
19
  from sphinx.locale import _
20
20
  from sphinx.util.math import get_node_equation_number
21
- from sphinx.writers.html import HTML5Translator
21
+
22
+ if TYPE_CHECKING:
23
+ from sphinx.application import Sphinx
24
+ from sphinx.writers.html import HTML5Translator
22
25
 
23
26
  # more information for mathjax secure url is here:
24
27
  # https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
@@ -46,7 +49,7 @@ def html_visit_displaymath(self: HTML5Translator, node: nodes.math_block) -> Non
46
49
  if node['number']:
47
50
  number = get_node_equation_number(self, node)
48
51
  self.body.append('<span class="eqno">(%s)' % number)
49
- self.add_permalink_ref(node, _('Permalink to this equation'))
52
+ self.add_permalink_ref(node, _('Link to this equation'))
50
53
  self.body.append('</span>')
51
54
  self.body.append(self.builder.config.mathjax_display[0])
52
55
  parts = [prt for prt in node.astext().split('\n\n') if prt.strip()]
@@ -75,10 +78,11 @@ def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: dict
75
78
  ):
76
79
  return
77
80
  if not app.config.mathjax_path:
78
- raise ExtensionError('mathjax_path config value must be set for the '
79
- 'mathjax extension to work')
81
+ msg = 'mathjax_path config value must be set for the mathjax extension to work'
82
+ raise ExtensionError(msg)
80
83
 
81
84
  domain = cast(MathDomain, app.env.get_domain('math'))
85
+ builder = cast(StandaloneHTMLBuilder, app.builder)
82
86
  if app.registry.html_assets_policy == 'always' or domain.has_equations(pagename):
83
87
  # Enable mathjax only if equations exists
84
88
  if app.config.mathjax2_config:
@@ -87,10 +91,10 @@ def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: dict
87
91
  'mathjax_config/mathjax2_config does not work '
88
92
  'for the current MathJax version, use mathjax3_config instead')
89
93
  body = 'MathJax.Hub.Config(%s)' % json.dumps(app.config.mathjax2_config)
90
- app.add_js_file(None, type='text/x-mathjax-config', body=body)
94
+ builder.add_js_file('', type='text/x-mathjax-config', body=body)
91
95
  if app.config.mathjax3_config:
92
96
  body = 'window.MathJax = %s' % json.dumps(app.config.mathjax3_config)
93
- app.add_js_file(None, body=body)
97
+ builder.add_js_file('', body=body)
94
98
 
95
99
  options = {}
96
100
  if app.config.mathjax_options:
@@ -102,7 +106,7 @@ def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: dict
102
106
  else:
103
107
  # Load other MathJax via "async" method
104
108
  options['async'] = 'async'
105
- app.add_js_file(app.config.mathjax_path, **options)
109
+ builder.add_js_file(app.config.mathjax_path, **options)
106
110
 
107
111
 
108
112
  def setup(app: Sphinx) -> dict[str, Any]:
@@ -367,7 +367,7 @@ def _process_docstring(app: Sphinx, what: str, name: str, obj: Any,
367
367
  The object to which the docstring belongs.
368
368
  options : sphinx.ext.autodoc.Options
369
369
  The options given to the directive: an object with attributes
370
- inherited_members, undoc_members, show_inheritance and noindex that
370
+ inherited_members, undoc_members, show_inheritance and no_index that
371
371
  are True if the flag option of same name was given to the auto
372
372
  directive.
373
373
  lines : list of str
@@ -421,7 +421,7 @@ def _skip_member(app: Sphinx, what: str, name: str, obj: Any,
421
421
  does not override the decision
422
422
  options : sphinx.ext.autodoc.Options
423
423
  The options given to the directive: an object with attributes
424
- inherited_members, undoc_members, show_inheritance and noindex that
424
+ inherited_members, undoc_members, show_inheritance and no_index that
425
425
  are True if the flag option of same name was given to the auto
426
426
  directive.
427
427
 
@@ -453,7 +453,7 @@ def _skip_member(app: Sphinx, what: str, name: str, obj: Any,
453
453
  except Exception:
454
454
  cls_is_owner = False
455
455
  else:
456
- cls_is_owner = (cls and hasattr(cls, name) and # type: ignore
456
+ cls_is_owner = (cls and hasattr(cls, name) and # type: ignore[assignment]
457
457
  name in cls.__dict__)
458
458
  else:
459
459
  cls_is_owner = False