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
@@ -33,17 +33,15 @@ from __future__ import annotations
33
33
  import builtins
34
34
  import hashlib
35
35
  import inspect
36
+ import os.path
36
37
  import re
37
- from collections.abc import Iterable, Sequence
38
38
  from importlib import import_module
39
- from os import path
40
- from typing import TYPE_CHECKING, Any, ClassVar, cast
39
+ from typing import TYPE_CHECKING, cast
41
40
 
42
41
  from docutils import nodes
43
42
  from docutils.parsers.rst import directives
44
43
 
45
44
  import sphinx
46
- from sphinx import addnodes
47
45
  from sphinx.ext.graphviz import (
48
46
  figure_wrapper,
49
47
  graphviz,
@@ -54,22 +52,30 @@ from sphinx.ext.graphviz import (
54
52
  from sphinx.util.docutils import SphinxDirective
55
53
 
56
54
  if TYPE_CHECKING:
55
+ from collections.abc import Collection, Iterable, Iterator, Sequence, Set
56
+ from typing import Any, ClassVar, Final
57
+
57
58
  from docutils.nodes import Node
58
59
 
60
+ from sphinx import addnodes
59
61
  from sphinx.application import Sphinx
62
+ from sphinx.config import Config
60
63
  from sphinx.environment import BuildEnvironment
61
64
  from sphinx.util.typing import ExtensionMetadata, OptionSpec
62
65
  from sphinx.writers.html5 import HTML5Translator
63
66
  from sphinx.writers.latex import LaTeXTranslator
64
67
  from sphinx.writers.texinfo import TexinfoTranslator
65
68
 
66
- module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
67
- (\w+) \s* $ # class/final module name
68
- ''', re.VERBOSE)
69
+ module_sig_re = re.compile(
70
+ r"""^
71
+ (?:([\w.]*)\.)? # module names
72
+ (\w+) \s* $ # class/final module name
73
+ """,
74
+ re.VERBOSE,
75
+ )
69
76
 
70
77
 
71
- py_builtins = [obj for obj in vars(builtins).values()
72
- if inspect.isclass(obj)]
78
+ PY_BUILTINS: Final = frozenset(filter(inspect.isclass, vars(builtins).values()))
73
79
 
74
80
 
75
81
  def try_import(objname: str) -> Any:
@@ -101,7 +107,7 @@ def try_import(objname: str) -> Any:
101
107
  return None
102
108
 
103
109
 
104
- def import_classes(name: str, currmodule: str) -> Any:
110
+ def import_classes(name: str, currmodule: str) -> list[type[Any]]:
105
111
  """Import a class using its fully-qualified *name*."""
106
112
  target = None
107
113
 
@@ -116,17 +122,21 @@ def import_classes(name: str, currmodule: str) -> Any:
116
122
  if target is None:
117
123
  raise InheritanceException(
118
124
  'Could not import class or module %r specified for '
119
- 'inheritance diagram' % name)
125
+ 'inheritance diagram' % name
126
+ )
120
127
 
121
128
  if inspect.isclass(target):
122
129
  # If imported object is a class, just return it
123
130
  return [target]
124
131
  elif inspect.ismodule(target):
125
132
  # If imported object is a module, return classes defined on it
126
- return [cls for cls in target.__dict__.values()
127
- if inspect.isclass(cls) and cls.__module__ == target.__name__]
128
- raise InheritanceException('%r specified for inheritance diagram is '
129
- 'not a class or module' % name)
133
+ return [
134
+ cls
135
+ for cls in target.__dict__.values()
136
+ if inspect.isclass(cls) and cls.__module__ == target.__name__
137
+ ]
138
+ msg = f'{name!r} specified for inheritance diagram is not a class or module'
139
+ raise InheritanceException(msg)
130
140
 
131
141
 
132
142
  class InheritanceException(Exception):
@@ -134,39 +144,59 @@ class InheritanceException(Exception):
134
144
 
135
145
 
136
146
  class InheritanceGraph:
137
- """
138
- Given a list of classes, determines the set of classes that they inherit
147
+ """Given a list of classes, determines the set of classes that they inherit
139
148
  from all the way to the root "object", and then is able to generate a
140
149
  graphviz dot graph from them.
141
150
  """
142
151
 
143
- def __init__(self, class_names: list[str], currmodule: str, show_builtins: bool = False,
144
- private_bases: bool = False, parts: int = 0,
145
- aliases: dict[str, str] | None = None, top_classes: Sequence[Any] = (),
146
- ) -> None:
152
+ def __init__(
153
+ self,
154
+ class_names: list[str],
155
+ currmodule: str,
156
+ show_builtins: bool = False,
157
+ private_bases: bool = False,
158
+ parts: int = 0,
159
+ aliases: dict[str, str] | None = None,
160
+ top_classes: Set[str] = frozenset(),
161
+ include_subclasses: bool = False,
162
+ ) -> None:
147
163
  """*class_names* is a list of child classes to show bases from.
148
164
 
149
165
  If *show_builtins* is True, then Python builtins will be shown
150
166
  in the graph.
151
167
  """
152
168
  self.class_names = class_names
153
- classes = self._import_classes(class_names, currmodule)
154
- self.class_info = self._class_info(classes, show_builtins,
155
- private_bases, parts, aliases, top_classes)
169
+ classes: Collection[type[Any]] = self._import_classes(class_names, currmodule)
170
+ if include_subclasses:
171
+ classes_set = {*classes}
172
+ for cls in tuple(classes_set):
173
+ classes_set.update(_subclasses(cls))
174
+ classes = classes_set
175
+ self.class_info = self._class_info(
176
+ classes, show_builtins, private_bases, parts, aliases, top_classes
177
+ )
156
178
  if not self.class_info:
157
179
  msg = 'No classes found for inheritance diagram'
158
180
  raise InheritanceException(msg)
159
181
 
160
- def _import_classes(self, class_names: list[str], currmodule: str) -> list[Any]:
182
+ def _import_classes(
183
+ self, class_names: list[str], currmodule: str
184
+ ) -> Sequence[type[Any]]:
161
185
  """Import a list of classes."""
162
- classes: list[Any] = []
186
+ classes: list[type[Any]] = []
163
187
  for name in class_names:
164
188
  classes.extend(import_classes(name, currmodule))
165
189
  return classes
166
190
 
167
- def _class_info(self, classes: list[Any], show_builtins: bool, private_bases: bool,
168
- parts: int, aliases: dict[str, str] | None, top_classes: Sequence[Any],
169
- ) -> list[tuple[str, str, list[str], str]]:
191
+ def _class_info(
192
+ self,
193
+ classes: Collection[type[Any]],
194
+ show_builtins: bool,
195
+ private_bases: bool,
196
+ parts: int,
197
+ aliases: dict[str, str] | None,
198
+ top_classes: Set[str],
199
+ ) -> list[tuple[str, str, Sequence[str], str | None]]:
170
200
  """Return name and bases for all classes that are ancestors of
171
201
  *classes*.
172
202
 
@@ -184,8 +214,8 @@ class InheritanceGraph:
184
214
  """
185
215
  all_classes = {}
186
216
 
187
- def recurse(cls: Any) -> None:
188
- if not show_builtins and cls in py_builtins:
217
+ def recurse(cls: type[Any]) -> None:
218
+ if not show_builtins and cls in PY_BUILTINS:
189
219
  return
190
220
  if not private_bases and cls.__name__.startswith('_'):
191
221
  return
@@ -197,7 +227,7 @@ class InheritanceGraph:
197
227
  tooltip = None
198
228
  try:
199
229
  if cls.__doc__:
200
- doc = cls.__doc__.strip().split("\n")[0]
230
+ doc = cls.__doc__.strip().split('\n')[0]
201
231
  if doc:
202
232
  tooltip = '"%s"' % doc.replace('"', '\\"')
203
233
  except Exception: # might raise AttributeError for strange classes
@@ -210,7 +240,7 @@ class InheritanceGraph:
210
240
  return
211
241
 
212
242
  for base in cls.__bases__:
213
- if not show_builtins and base in py_builtins:
243
+ if not show_builtins and base in PY_BUILTINS:
214
244
  continue
215
245
  if not private_bases and base.__name__.startswith('_'):
216
246
  continue
@@ -221,10 +251,13 @@ class InheritanceGraph:
221
251
  for cls in classes:
222
252
  recurse(cls)
223
253
 
224
- return list(all_classes.values()) # type: ignore[arg-type]
254
+ return [
255
+ (cls_name, fullname, tuple(bases), tooltip)
256
+ for (cls_name, fullname, bases, tooltip) in all_classes.values()
257
+ ]
225
258
 
226
259
  def class_name(
227
- self, cls: Any, parts: int = 0, aliases: dict[str, str] | None = None,
260
+ self, cls: type[Any], parts: int = 0, aliases: dict[str, str] | None = None
228
261
  ) -> str:
229
262
  """Given a class object, return a fully-qualified name.
230
263
 
@@ -232,7 +265,7 @@ class InheritanceGraph:
232
265
  completely general.
233
266
  """
234
267
  module = cls.__module__
235
- if module in ('__builtin__', 'builtins'):
268
+ if module in {'__builtin__', 'builtins'}:
236
269
  fullname = cls.__name__
237
270
  else:
238
271
  fullname = f'{module}.{cls.__qualname__}'
@@ -250,37 +283,53 @@ class InheritanceGraph:
250
283
  return [fullname for (_, fullname, _, _) in self.class_info]
251
284
 
252
285
  # These are the default attrs for graphviz
253
- default_graph_attrs = {
286
+ default_graph_attrs: dict[str, float | int | str] = {
254
287
  'rankdir': 'LR',
255
288
  'size': '"8.0, 12.0"',
256
289
  'bgcolor': 'transparent',
257
290
  }
258
- default_node_attrs = {
291
+ default_node_attrs: dict[str, float | int | str] = {
259
292
  'shape': 'box',
260
293
  'fontsize': 10,
261
294
  'height': 0.25,
262
- 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
263
- 'Arial, Helvetica, sans"',
295
+ 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans"',
264
296
  'style': '"setlinewidth(0.5),filled"',
265
297
  'fillcolor': 'white',
266
298
  }
267
- default_edge_attrs = {
299
+ default_edge_attrs: dict[str, float | int | str] = {
268
300
  'arrowsize': 0.5,
269
301
  'style': '"setlinewidth(0.5)"',
270
302
  }
271
303
 
272
- def _format_node_attrs(self, attrs: dict[str, Any]) -> str:
304
+ def _format_node_attrs(self, attrs: dict[str, float | int | str]) -> str:
273
305
  return ','.join(f'{k}={v}' for k, v in sorted(attrs.items()))
274
306
 
275
- def _format_graph_attrs(self, attrs: dict[str, Any]) -> str:
307
+ def _format_graph_attrs(self, attrs: dict[str, float | int | str]) -> str:
276
308
  return ''.join(f'{k}={v};\n' for k, v in sorted(attrs.items()))
277
309
 
278
- def generate_dot(self, name: str, urls: dict[str, str] | None = None,
279
- env: BuildEnvironment | None = None,
280
- graph_attrs: dict | None = None,
281
- node_attrs: dict | None = None,
282
- edge_attrs: dict | None = None,
283
- ) -> str:
310
+ def generate_dot(
311
+ self,
312
+ name: str,
313
+ urls: dict[str, str] | None = None,
314
+ env: BuildEnvironment | None = None,
315
+ graph_attrs: dict[str, float | int | str] | None = None,
316
+ node_attrs: dict[str, float | int | str] | None = None,
317
+ edge_attrs: dict[str, float | int | str] | None = None,
318
+ ) -> str:
319
+ config = env.config if env is not None else None
320
+ return self._generate_dot(
321
+ name, urls, config, graph_attrs, node_attrs, edge_attrs
322
+ )
323
+
324
+ def _generate_dot(
325
+ self,
326
+ name: str,
327
+ urls: dict[str, str] | None = None,
328
+ config: Config | None = None,
329
+ graph_attrs: dict[str, float | int | str] | None = None,
330
+ node_attrs: dict[str, float | int | str] | None = None,
331
+ edge_attrs: dict[str, float | int | str] | None = None,
332
+ ) -> str:
284
333
  """Generate a graphviz dot graph from the classes that were passed in
285
334
  to __init__.
286
335
 
@@ -302,47 +351,45 @@ class InheritanceGraph:
302
351
  n_attrs.update(node_attrs)
303
352
  if edge_attrs is not None:
304
353
  e_attrs.update(edge_attrs)
305
- if env:
306
- g_attrs.update(env.config.inheritance_graph_attrs)
307
- n_attrs.update(env.config.inheritance_node_attrs)
308
- e_attrs.update(env.config.inheritance_edge_attrs)
354
+ if config:
355
+ g_attrs.update(config.inheritance_graph_attrs)
356
+ n_attrs.update(config.inheritance_node_attrs)
357
+ e_attrs.update(config.inheritance_edge_attrs)
309
358
 
310
359
  res: list[str] = [
311
360
  f'digraph {name} {{\n',
312
361
  self._format_graph_attrs(g_attrs),
313
362
  ]
314
363
 
315
- for name, fullname, bases, tooltip in sorted(self.class_info):
364
+ for cls_name, fullname, bases, tooltip in sorted(self.class_info):
316
365
  # Write the node
317
366
  this_node_attrs = n_attrs.copy()
318
367
  if fullname in urls:
319
- this_node_attrs["URL"] = '"%s"' % urls[fullname]
320
- this_node_attrs["target"] = '"_top"'
368
+ this_node_attrs['URL'] = f'"{urls[fullname]}"'
369
+ this_node_attrs['target'] = '"_top"'
321
370
  if tooltip:
322
- this_node_attrs["tooltip"] = tooltip
323
- res.append(' "%s" [%s];\n' % (name, self._format_node_attrs(this_node_attrs)))
371
+ this_node_attrs['tooltip'] = tooltip
372
+ res.append(
373
+ f' "{cls_name}" [{self._format_node_attrs(this_node_attrs)}];\n'
374
+ )
324
375
 
325
376
  # Write the edges
326
377
  res.extend(
327
- ' "%s" -> "%s" [%s];\n' % (base_name, name, self._format_node_attrs(e_attrs))
378
+ f' "{base_name}" -> "{cls_name}" [{self._format_node_attrs(e_attrs)}];\n'
328
379
  for base_name in bases
329
380
  )
330
- res.append("}\n")
331
- return "".join(res)
381
+ res.append('}\n')
382
+ return ''.join(res)
332
383
 
333
384
 
334
385
  class inheritance_diagram(graphviz):
335
- """
336
- A docutils node to use as a placeholder for the inheritance diagram.
337
- """
386
+ """A docutils node to use as a placeholder for the inheritance diagram."""
338
387
 
339
388
  pass
340
389
 
341
390
 
342
391
  class InheritanceDiagram(SphinxDirective):
343
- """
344
- Run when the inheritance_diagram directive is first encountered.
345
- """
392
+ """Run when the inheritance_diagram directive is first encountered."""
346
393
 
347
394
  has_content = False
348
395
  required_arguments = 1
@@ -353,6 +400,7 @@ class InheritanceDiagram(SphinxDirective):
353
400
  'private-bases': directives.flag,
354
401
  'caption': directives.unchanged,
355
402
  'top-classes': directives.unchanged_required,
403
+ 'include-subclasses': directives.flag,
356
404
  }
357
405
 
358
406
  def run(self) -> list[Node]:
@@ -363,20 +411,23 @@ class InheritanceDiagram(SphinxDirective):
363
411
  # Store the original content for use as a hash
364
412
  node['parts'] = self.options.get('parts', 0)
365
413
  node['content'] = ', '.join(class_names)
366
- node['top-classes'] = []
367
- for cls in self.options.get('top-classes', '').split(','):
368
- cls = cls.strip()
369
- if cls:
370
- node['top-classes'].append(cls)
414
+ node['top-classes'] = frozenset({
415
+ cls_stripped
416
+ for cls in self.options.get('top-classes', '').split(',')
417
+ if (cls_stripped := cls.strip())
418
+ })
371
419
 
372
420
  # Create a graph starting with the list of classes
373
421
  try:
374
422
  graph = InheritanceGraph(
375
- class_names, self.env.ref_context.get('py:module'), # type: ignore[arg-type]
423
+ class_names,
424
+ self.env.ref_context.get('py:module'), # type: ignore[arg-type]
376
425
  parts=node['parts'],
377
426
  private_bases='private-bases' in self.options,
378
427
  aliases=self.config.inheritance_alias,
379
- top_classes=node['top-classes'])
428
+ top_classes=node['top-classes'],
429
+ include_subclasses='include-subclasses' in self.options,
430
+ )
380
431
  except InheritanceException as err:
381
432
  return [node.document.reporter.warning(err, line=self.lineno)]
382
433
 
@@ -386,7 +437,8 @@ class InheritanceDiagram(SphinxDirective):
386
437
  # removed from the doctree after we're done with them.
387
438
  for name in graph.get_all_class_names():
388
439
  refnodes, x = class_role( # type: ignore[misc]
389
- 'class', ':class:`%s`' % name, name, 0, self.state.inliner)
440
+ 'class', f':class:`{name}`', name, 0, self.state.inliner
441
+ )
390
442
  node.extend(refnodes)
391
443
  # Store the graph object so we can use it to generate the
392
444
  # dot file later
@@ -401,14 +453,21 @@ class InheritanceDiagram(SphinxDirective):
401
453
  return [figure]
402
454
 
403
455
 
456
+ def _subclasses(cls: type[Any]) -> Iterator[type[Any]]:
457
+ yield cls
458
+ for sub_cls in cls.__subclasses__():
459
+ yield from _subclasses(sub_cls)
460
+
461
+
404
462
  def get_graph_hash(node: inheritance_diagram) -> str:
405
463
  encoded = (node['content'] + str(node['parts'])).encode()
406
464
  return hashlib.md5(encoded, usedforsecurity=False).hexdigest()[-10:]
407
465
 
408
466
 
409
- def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diagram) -> None:
410
- """
411
- Output the graph for HTML. This will insert a PNG with clickable
467
+ def html_visit_inheritance_diagram(
468
+ self: HTML5Translator, node: inheritance_diagram
469
+ ) -> None:
470
+ """Output the graph for HTML. This will insert a PNG with clickable
412
471
  image map.
413
472
  """
414
473
  graph = node['graph']
@@ -417,10 +476,12 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag
417
476
  name = 'inheritance%s' % graph_hash
418
477
 
419
478
  # Create a mapping from fully-qualified class names to URLs.
420
- graphviz_output_format = self.builder.env.config.graphviz_output_format.upper()
421
- current_filename = path.basename(self.builder.current_docname + self.builder.out_suffix)
479
+ graphviz_output_format = self.config.graphviz_output_format.upper()
480
+ current_filename = os.path.basename(
481
+ self.builder.current_docname + self.builder.out_suffix
482
+ )
422
483
  urls = {}
423
- pending_xrefs = cast(Iterable[addnodes.pending_xref], node)
484
+ pending_xrefs = cast('Iterable[addnodes.pending_xref]', node)
424
485
  for child in pending_xrefs:
425
486
  if child.get('refuri') is not None:
426
487
  # Construct the name from the URI if the reference is external via intersphinx
@@ -436,39 +497,48 @@ def html_visit_inheritance_diagram(self: HTML5Translator, node: inheritance_diag
436
497
  else:
437
498
  urls[child['reftitle']] = '#' + child.get('refid')
438
499
 
439
- dotcode = graph.generate_dot(name, urls, env=self.builder.env)
440
- render_dot_html(self, node, dotcode, {}, 'inheritance', 'inheritance',
441
- alt='Inheritance diagram of ' + node['content'])
500
+ dotcode = graph._generate_dot(name, urls, config=self.config)
501
+ render_dot_html(
502
+ self,
503
+ node,
504
+ dotcode,
505
+ {},
506
+ 'inheritance',
507
+ 'inheritance',
508
+ alt='Inheritance diagram of ' + node['content'],
509
+ )
442
510
  raise nodes.SkipNode
443
511
 
444
512
 
445
- def latex_visit_inheritance_diagram(self: LaTeXTranslator, node: inheritance_diagram) -> None:
446
- """
447
- Output the graph for LaTeX. This will insert a PDF.
448
- """
513
+ def latex_visit_inheritance_diagram(
514
+ self: LaTeXTranslator, node: inheritance_diagram
515
+ ) -> None:
516
+ """Output the graph for LaTeX. This will insert a PDF."""
449
517
  graph = node['graph']
450
518
 
451
519
  graph_hash = get_graph_hash(node)
452
520
  name = 'inheritance%s' % graph_hash
453
521
 
454
- dotcode = graph.generate_dot(name, env=self.builder.env,
455
- graph_attrs={'size': '"6.0,6.0"'})
522
+ dotcode = graph._generate_dot(
523
+ name, config=self.config, graph_attrs={'size': '"6.0,6.0"'}
524
+ )
456
525
  render_dot_latex(self, node, dotcode, {}, 'inheritance')
457
526
  raise nodes.SkipNode
458
527
 
459
528
 
460
- def texinfo_visit_inheritance_diagram(self: TexinfoTranslator, node: inheritance_diagram,
461
- ) -> None:
462
- """
463
- Output the graph for Texinfo. This will insert a PNG.
464
- """
529
+ def texinfo_visit_inheritance_diagram(
530
+ self: TexinfoTranslator,
531
+ node: inheritance_diagram,
532
+ ) -> None:
533
+ """Output the graph for Texinfo. This will insert a PNG."""
465
534
  graph = node['graph']
466
535
 
467
536
  graph_hash = get_graph_hash(node)
468
537
  name = 'inheritance%s' % graph_hash
469
538
 
470
- dotcode = graph.generate_dot(name, env=self.builder.env,
471
- graph_attrs={'size': '"6.0,6.0"'})
539
+ dotcode = graph._generate_dot(
540
+ name, config=self.config, graph_attrs={'size': '"6.0,6.0"'}
541
+ )
472
542
  render_dot_texinfo(self, node, dotcode, {}, 'inheritance')
473
543
  raise nodes.SkipNode
474
544
 
@@ -485,10 +555,14 @@ def setup(app: Sphinx) -> ExtensionMetadata:
485
555
  html=(html_visit_inheritance_diagram, None),
486
556
  text=(skip, None),
487
557
  man=(skip, None),
488
- texinfo=(texinfo_visit_inheritance_diagram, None))
558
+ texinfo=(texinfo_visit_inheritance_diagram, None),
559
+ )
489
560
  app.add_directive('inheritance-diagram', InheritanceDiagram)
490
- app.add_config_value('inheritance_graph_attrs', {}, '')
491
- app.add_config_value('inheritance_node_attrs', {}, '')
492
- app.add_config_value('inheritance_edge_attrs', {}, '')
493
- app.add_config_value('inheritance_alias', {}, '')
494
- return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
561
+ app.add_config_value('inheritance_graph_attrs', {}, '', types=frozenset({dict}))
562
+ app.add_config_value('inheritance_node_attrs', {}, '', types=frozenset({dict}))
563
+ app.add_config_value('inheritance_edge_attrs', {}, '', types=frozenset({dict}))
564
+ app.add_config_value('inheritance_alias', {}, '', types=frozenset({dict}))
565
+ return {
566
+ 'version': sphinx.__display_version__,
567
+ 'parallel_read_safe': True,
568
+ }
@@ -19,22 +19,23 @@ This works as follows:
19
19
  from __future__ import annotations
20
20
 
21
21
  __all__ = (
22
+ 'IntersphinxDispatcher',
23
+ 'IntersphinxRole',
24
+ 'IntersphinxRoleResolver',
22
25
  'InventoryAdapter',
23
26
  'fetch_inventory',
24
- 'load_mappings',
25
- 'validate_intersphinx_mapping',
26
- 'IntersphinxRoleResolver',
27
- 'inventory_exists',
27
+ 'inspect_main',
28
28
  'install_dispatcher',
29
- 'resolve_reference_in_inventory',
29
+ 'inventory_exists',
30
+ 'load_mappings',
31
+ 'missing_reference',
30
32
  'resolve_reference_any_inventory',
31
33
  'resolve_reference_detect_inventory',
32
- 'missing_reference',
33
- 'IntersphinxDispatcher',
34
- 'IntersphinxRole',
35
- 'inspect_main',
34
+ 'resolve_reference_in_inventory',
35
+ 'validate_intersphinx_mapping',
36
36
  )
37
37
 
38
+ from types import NoneType
38
39
  from typing import TYPE_CHECKING
39
40
 
40
41
  import sphinx
@@ -63,10 +64,18 @@ if TYPE_CHECKING:
63
64
 
64
65
 
65
66
  def setup(app: Sphinx) -> ExtensionMetadata:
66
- app.add_config_value('intersphinx_mapping', {}, 'env')
67
- app.add_config_value('intersphinx_cache_limit', 5, '')
68
- app.add_config_value('intersphinx_timeout', None, '')
69
- app.add_config_value('intersphinx_disabled_reftypes', ['std:doc'], 'env')
67
+ app.add_config_value('intersphinx_mapping', {}, 'env', types=frozenset({dict}))
68
+ app.add_config_value('intersphinx_resolve_self', '', 'env', types=frozenset({str}))
69
+ app.add_config_value('intersphinx_cache_limit', 5, '', types=frozenset({int}))
70
+ app.add_config_value(
71
+ 'intersphinx_timeout', None, '', types=frozenset({float, int, NoneType})
72
+ )
73
+ app.add_config_value(
74
+ 'intersphinx_disabled_reftypes',
75
+ ['std:doc'],
76
+ 'env',
77
+ types=frozenset({frozenset, list, set, tuple}),
78
+ )
70
79
  app.connect('config-inited', validate_intersphinx_mapping, priority=800)
71
80
  app.connect('builder-inited', load_mappings)
72
81
  app.connect('source-read', install_dispatcher)
@@ -1,9 +1,11 @@
1
1
  """Command line interface for the intersphinx extension."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import logging as _logging
4
6
  import sys
5
7
 
6
- from sphinx.ext.intersphinx import inspect_main
8
+ from sphinx.ext.intersphinx._cli import inspect_main
7
9
 
8
10
  _logging.basicConfig()
9
11
 
@@ -3,8 +3,9 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import sys
6
+ from pathlib import Path
6
7
 
7
- from sphinx.ext.intersphinx._load import _fetch_inventory
8
+ from sphinx.ext.intersphinx._load import _fetch_inventory, _InvConfig
8
9
 
9
10
 
10
11
  def inspect_main(argv: list[str], /) -> int:
@@ -17,26 +18,29 @@ def inspect_main(argv: list[str], /) -> int:
17
18
  )
18
19
  return 1
19
20
 
20
- class MockConfig:
21
- intersphinx_timeout: int | None = None
22
- tls_verify = False
23
- tls_cacerts: str | dict[str, str] | None = None
24
- user_agent: str = ''
21
+ filename = argv[0]
22
+ config = _InvConfig(
23
+ intersphinx_cache_limit=5,
24
+ intersphinx_timeout=None,
25
+ tls_verify=False,
26
+ tls_cacerts=None,
27
+ user_agent='',
28
+ )
25
29
 
26
30
  try:
27
- filename = argv[0]
28
- inv_data = _fetch_inventory(
31
+ inv = _fetch_inventory(
29
32
  target_uri='',
30
33
  inv_location=filename,
31
- config=MockConfig(), # type: ignore[arg-type]
32
- srcdir='', # type: ignore[arg-type]
34
+ config=config,
35
+ srcdir=Path(),
33
36
  )
34
- for key in sorted(inv_data or {}):
37
+ for key in sorted(inv.data):
35
38
  print(key)
36
- inv_entries = sorted(inv_data[key].items())
37
- for entry, (_proj, _ver, url_path, display_name) in inv_entries:
39
+ inv_entries = sorted(inv.data[key].items())
40
+ for entry, inv_item in inv_entries:
41
+ display_name = inv_item.display_name
38
42
  display_name = display_name * (display_name != '-')
39
- print(f' {entry:<40} {display_name:<40}: {url_path}')
43
+ print(f' {entry:<40} {display_name:<40}: {inv_item.uri}')
40
44
  except ValueError as exc:
41
45
  print(exc.args[0] % exc.args[1:], file=sys.stderr)
42
46
  return 1