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
@@ -3,10 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import concurrent.futures
6
+ import dataclasses
7
+ import os.path
6
8
  import posixpath
7
9
  import time
8
10
  from operator import itemgetter
9
- from os import path
10
11
  from typing import TYPE_CHECKING
11
12
  from urllib.parse import urlsplit, urlunsplit
12
13
 
@@ -20,8 +21,6 @@ from sphinx.util.inventory import InventoryFile
20
21
  if TYPE_CHECKING:
21
22
  from pathlib import Path
22
23
 
23
- from urllib3.response import HTTPResponse
24
-
25
24
  from sphinx.application import Sphinx
26
25
  from sphinx.config import Config
27
26
  from sphinx.ext.intersphinx._shared import (
@@ -31,7 +30,8 @@ if TYPE_CHECKING:
31
30
  InventoryName,
32
31
  InventoryURI,
33
32
  )
34
- from sphinx.util.typing import Inventory, _ReadableStream
33
+ from sphinx.util.inventory import _Inventory
34
+ from sphinx.util.typing import Inventory
35
35
 
36
36
 
37
37
  def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
@@ -82,7 +82,7 @@ def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
82
82
  'Invalid value `%r` in intersphinx_mapping[%r]. '
83
83
  'Values must be a (target URI, inventory locations) pair.'
84
84
  )
85
- LOGGER.error(msg, value, name)
85
+ LOGGER.error(msg, value, name) # NoQA: TRY400
86
86
  del config.intersphinx_mapping[name]
87
87
  continue
88
88
 
@@ -140,8 +140,9 @@ def load_mappings(app: Sphinx) -> None:
140
140
 
141
141
  The intersphinx mappings are expected to be normalized.
142
142
  """
143
+ env = app.env
143
144
  now = int(time.time())
144
- inventories = InventoryAdapter(app.builder.env)
145
+ inventories = InventoryAdapter(env)
145
146
  intersphinx_cache: dict[InventoryURI, InventoryCacheEntry] = inventories.cache
146
147
  intersphinx_mapping: IntersphinxMapping = app.config.intersphinx_mapping
147
148
 
@@ -170,6 +171,7 @@ def load_mappings(app: Sphinx) -> None:
170
171
  # This happens when the URI in `intersphinx_mapping` is changed.
171
172
  del intersphinx_cache[uri]
172
173
 
174
+ inv_config = _InvConfig.from_config(app.config)
173
175
  with concurrent.futures.ThreadPoolExecutor() as pool:
174
176
  futures = [
175
177
  pool.submit(
@@ -177,7 +179,7 @@ def load_mappings(app: Sphinx) -> None:
177
179
  project=project,
178
180
  cache=intersphinx_cache,
179
181
  now=now,
180
- config=app.config,
182
+ config=inv_config,
181
183
  srcdir=app.srcdir,
182
184
  )
183
185
  for project in projects
@@ -202,12 +204,31 @@ def load_mappings(app: Sphinx) -> None:
202
204
  inventories.main_inventory.setdefault(objtype, {}).update(objects)
203
205
 
204
206
 
207
+ @dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
208
+ class _InvConfig:
209
+ intersphinx_cache_limit: int
210
+ intersphinx_timeout: int | float | None
211
+ tls_verify: bool
212
+ tls_cacerts: str | dict[str, str] | None
213
+ user_agent: str
214
+
215
+ @classmethod
216
+ def from_config(cls, config: Config) -> _InvConfig:
217
+ return cls(
218
+ intersphinx_cache_limit=config.intersphinx_cache_limit,
219
+ intersphinx_timeout=config.intersphinx_timeout,
220
+ tls_verify=config.tls_verify,
221
+ tls_cacerts=config.tls_cacerts,
222
+ user_agent=config.user_agent,
223
+ )
224
+
225
+
205
226
  def _fetch_inventory_group(
206
227
  *,
207
228
  project: _IntersphinxProject,
208
229
  cache: dict[InventoryURI, InventoryCacheEntry],
209
230
  now: int,
210
- config: Config,
231
+ config: _InvConfig,
211
232
  srcdir: Path,
212
233
  ) -> bool:
213
234
  if config.intersphinx_cache_limit >= 0:
@@ -225,27 +246,27 @@ def _fetch_inventory_group(
225
246
  for location in project.locations:
226
247
  # location is either None or a non-empty string
227
248
  if location is None:
228
- inv = posixpath.join(project.target_uri, INVENTORY_FILENAME)
249
+ inv_location = posixpath.join(project.target_uri, INVENTORY_FILENAME)
229
250
  else:
230
- inv = location
251
+ inv_location = location
231
252
 
232
253
  # decide whether the inventory must be read: always read local
233
254
  # files; remote ones only if the cache time is expired
234
255
  if (
235
- '://' not in inv
256
+ '://' not in inv_location
236
257
  or project.target_uri not in cache
237
258
  or cache[project.target_uri][1] < cache_time
238
259
  ):
239
260
  LOGGER.info(
240
261
  __("loading intersphinx inventory '%s' from %s ..."),
241
262
  project.name,
242
- _get_safe_url(inv),
263
+ _get_safe_url(inv_location),
243
264
  )
244
265
 
245
266
  try:
246
- invdata = _fetch_inventory(
267
+ inv = _fetch_inventory(
247
268
  target_uri=project.target_uri,
248
- inv_location=inv,
269
+ inv_location=inv_location,
249
270
  config=config,
250
271
  srcdir=srcdir,
251
272
  )
@@ -253,8 +274,8 @@ def _fetch_inventory_group(
253
274
  failures.append(err.args)
254
275
  continue
255
276
 
256
- if invdata:
257
- cache[project.target_uri] = project.name, now, invdata
277
+ if inv:
278
+ cache[project.target_uri] = project.name, now, inv.data
258
279
  updated = True
259
280
  break
260
281
 
@@ -272,9 +293,9 @@ def _fetch_inventory_group(
272
293
  else:
273
294
  issues = '\n'.join(f[0] % f[1:] for f in failures)
274
295
  LOGGER.warning(
275
- __('failed to reach any of the inventories ' 'with the following issues:')
276
- + '\n'
277
- + issues
296
+ '%s\n%s',
297
+ __('failed to reach any of the inventories with the following issues:'),
298
+ issues,
278
299
  )
279
300
  return updated
280
301
 
@@ -284,26 +305,49 @@ def fetch_inventory(app: Sphinx, uri: InventoryURI, inv: str) -> Inventory:
284
305
  return _fetch_inventory(
285
306
  target_uri=uri,
286
307
  inv_location=inv,
287
- config=app.config,
308
+ config=_InvConfig.from_config(app.config),
288
309
  srcdir=app.srcdir,
289
- )
310
+ ).data
290
311
 
291
312
 
292
313
  def _fetch_inventory(
293
- *, target_uri: InventoryURI, inv_location: str, config: Config, srcdir: Path
294
- ) -> Inventory:
314
+ *, target_uri: InventoryURI, inv_location: str, config: _InvConfig, srcdir: Path
315
+ ) -> _Inventory:
295
316
  """Fetch, parse and return an intersphinx inventory file."""
296
317
  # both *target_uri* (base URI of the links to generate)
297
318
  # and *inv_location* (actual location of the inventory file)
298
319
  # can be local or remote URIs
299
320
  if '://' in target_uri:
300
- # case: inv URI points to remote resource; strip any existing auth
321
+ # inv URI points to remote resource; strip any existing auth
301
322
  target_uri = _strip_basic_auth(target_uri)
323
+ if '://' in inv_location:
324
+ raw_data, target_uri = _fetch_inventory_url(
325
+ target_uri=target_uri, inv_location=inv_location, config=config
326
+ )
327
+ else:
328
+ raw_data = _fetch_inventory_file(inv_location=inv_location, srcdir=srcdir)
329
+
302
330
  try:
303
- if '://' in inv_location:
304
- f: _ReadableStream[bytes] = _read_from_url(inv_location, config=config)
305
- else:
306
- f = open(path.join(srcdir, inv_location), 'rb') # NoQA: SIM115
331
+ inv = InventoryFile.loads(raw_data, uri=target_uri)
332
+ except ValueError as exc:
333
+ msg = f'unknown or unsupported inventory version: {exc!r}'
334
+ raise ValueError(msg) from exc
335
+ return inv
336
+
337
+
338
+ def _fetch_inventory_url(
339
+ *, target_uri: InventoryURI, inv_location: str, config: _InvConfig
340
+ ) -> tuple[bytes, str]:
341
+ try:
342
+ with requests.get(
343
+ inv_location,
344
+ timeout=config.intersphinx_timeout,
345
+ _user_agent=config.user_agent,
346
+ _tls_info=(config.tls_verify, config.tls_cacerts),
347
+ ) as r:
348
+ r.raise_for_status()
349
+ raw_data = r.content
350
+ new_inv_location = r.url
307
351
  except Exception as err:
308
352
  err.args = (
309
353
  'intersphinx inventory %r not fetchable due to %s: %s',
@@ -312,25 +356,25 @@ def _fetch_inventory(
312
356
  str(err),
313
357
  )
314
358
  raise
359
+
360
+ if inv_location != new_inv_location:
361
+ msg = __('intersphinx inventory has moved: %s -> %s')
362
+ LOGGER.info(msg, inv_location, new_inv_location)
363
+
364
+ if target_uri in {
365
+ inv_location,
366
+ os.path.dirname(inv_location),
367
+ os.path.dirname(inv_location) + '/',
368
+ }:
369
+ target_uri = os.path.dirname(new_inv_location)
370
+
371
+ return raw_data, target_uri
372
+
373
+
374
+ def _fetch_inventory_file(*, inv_location: str, srcdir: Path) -> bytes:
315
375
  try:
316
- if hasattr(f, 'url'):
317
- new_inv_location = f.url
318
- if inv_location != new_inv_location:
319
- msg = __('intersphinx inventory has moved: %s -> %s')
320
- LOGGER.info(msg, inv_location, new_inv_location)
321
-
322
- if target_uri in {
323
- inv_location,
324
- path.dirname(inv_location),
325
- path.dirname(inv_location) + '/',
326
- }:
327
- target_uri = path.dirname(new_inv_location)
328
- with f:
329
- try:
330
- invdata = InventoryFile.load(f, target_uri, posixpath.join)
331
- except ValueError as exc:
332
- msg = f'unknown or unsupported inventory version: {exc!r}'
333
- raise ValueError(msg) from exc
376
+ with open(srcdir / inv_location, 'rb') as f:
377
+ raw_data = f.read()
334
378
  except Exception as err:
335
379
  err.args = (
336
380
  'intersphinx inventory %r not readable due to %s: %s',
@@ -339,8 +383,7 @@ def _fetch_inventory(
339
383
  str(err),
340
384
  )
341
385
  raise
342
- else:
343
- return invdata
386
+ return raw_data
344
387
 
345
388
 
346
389
  def _get_safe_url(url: str) -> str:
@@ -387,37 +430,3 @@ def _strip_basic_auth(url: str) -> str:
387
430
  if '@' in frags[1]:
388
431
  frags[1] = frags[1].split('@')[1]
389
432
  return urlunsplit(frags)
390
-
391
-
392
- def _read_from_url(url: str, *, config: Config) -> HTTPResponse:
393
- """Reads data from *url* with an HTTP *GET*.
394
-
395
- This function supports fetching from resources which use basic HTTP auth as
396
- laid out by RFC1738 § 3.1. See § 5 for grammar definitions for URLs.
397
-
398
- .. seealso:
399
-
400
- https://www.ietf.org/rfc/rfc1738.txt
401
-
402
- :param url: URL of an HTTP resource
403
- :type url: ``str``
404
-
405
- :return: data read from resource described by *url*
406
- :rtype: ``file``-like object
407
- """
408
- r = requests.get(
409
- url,
410
- stream=True,
411
- timeout=config.intersphinx_timeout,
412
- _user_agent=config.user_agent,
413
- _tls_info=(config.tls_verify, config.tls_cacerts),
414
- )
415
- r.raise_for_status()
416
-
417
- # For inv_location / new_inv_location
418
- r.raw.url = r.url # type: ignore[union-attr]
419
-
420
- # Decode content-body based on the header.
421
- # xref: https://github.com/psf/requests/issues/2155
422
- r.raw.decode_content = True
423
- return r.raw