Sphinx 8.1.3__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 +829 -480
  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.3.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
  321. {sphinx-8.1.3.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.3.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.3.dist-info/RECORD +0 -598
  328. {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
sphinx/ext/coverage.py CHANGED
@@ -8,23 +8,24 @@ from __future__ import annotations
8
8
 
9
9
  import glob
10
10
  import inspect
11
+ import os.path
11
12
  import pickle
12
13
  import pkgutil
13
14
  import re
14
15
  import sys
15
16
  from importlib import import_module
16
- from os import path
17
- from typing import IO, TYPE_CHECKING, Any, TextIO
17
+ from typing import TYPE_CHECKING
18
18
 
19
19
  import sphinx
20
+ from sphinx._cli.util.colour import red
20
21
  from sphinx.builders import Builder
21
22
  from sphinx.locale import __
22
23
  from sphinx.util import logging
23
- from sphinx.util.console import red
24
24
  from sphinx.util.inspect import safe_getattr
25
25
 
26
26
  if TYPE_CHECKING:
27
27
  from collections.abc import Iterable, Iterator, Sequence, Set
28
+ from typing import IO, Any, TextIO
28
29
 
29
30
  from sphinx.application import Sphinx
30
31
  from sphinx.util.typing import ExtensionMetadata
@@ -62,12 +63,17 @@ def _add_line(sizes: list[int], separator: str) -> str:
62
63
  return '+' + ''.join((separator * (size + 1)) + '+' for size in sizes)
63
64
 
64
65
 
65
- def _add_row(col_widths: list[int], columns: list[str], separator: str) -> Iterator[str]:
66
- yield ''.join(f'| {column: <{col_widths[i]}}' for i, column in enumerate(columns)) + '|'
66
+ def _add_row(
67
+ col_widths: list[int], columns: list[str], separator: str
68
+ ) -> Iterator[str]:
69
+ row = ''.join(f'| {column: <{col_widths[i]}}' for i, column in enumerate(columns))
70
+ yield f'{row}|'
67
71
  yield _add_line(col_widths, separator)
68
72
 
69
73
 
70
- def _load_modules(mod_name: str, ignored_module_exps: Iterable[re.Pattern[str]]) -> Set[str]:
74
+ def _load_modules(
75
+ mod_name: str, ignored_module_exps: Iterable[re.Pattern[str]]
76
+ ) -> Set[str]:
71
77
  """Recursively load all submodules.
72
78
 
73
79
  :param mod_name: The name of a module to load submodules for.
@@ -87,7 +93,7 @@ def _load_modules(mod_name: str, ignored_module_exps: Iterable[re.Pattern[str]])
87
93
  return modules
88
94
 
89
95
  search_locations = mod.__spec__.submodule_search_locations
90
- for (_, sub_mod_name, sub_mod_ispkg) in pkgutil.iter_modules(search_locations):
96
+ for _, sub_mod_name, sub_mod_ispkg in pkgutil.iter_modules(search_locations):
91
97
  if sub_mod_name == '__main__':
92
98
  continue
93
99
 
@@ -138,16 +144,20 @@ def _determine_py_coverage_modules(
138
144
  # if there are additional modules then we warn but continue scanning
139
145
  if additional_modules := seen_modules - modules:
140
146
  logger.warning(
141
- __('the following modules are documented but were not specified '
142
- 'in coverage_modules: %s'),
147
+ __(
148
+ 'the following modules are documented but were not specified '
149
+ 'in coverage_modules: %s'
150
+ ),
143
151
  ', '.join(additional_modules),
144
152
  )
145
153
 
146
154
  # likewise, if there are missing modules we warn but continue scanning
147
155
  if missing_modules := modules - seen_modules:
148
156
  logger.warning(
149
- __('the following modules are specified in coverage_modules '
150
- 'but were not documented'),
157
+ __(
158
+ 'the following modules are specified in coverage_modules '
159
+ 'but were not documented'
160
+ ),
151
161
  ', '.join(missing_modules),
152
162
  )
153
163
 
@@ -155,39 +165,43 @@ def _determine_py_coverage_modules(
155
165
 
156
166
 
157
167
  class CoverageBuilder(Builder):
158
- """
159
- Evaluates coverage of code in the documentation.
160
- """
168
+ """Evaluates coverage of code in the documentation."""
161
169
 
162
170
  name = 'coverage'
163
- epilog = __('Testing of coverage in the sources finished, look at the '
164
- 'results in %(outdir)s' + path.sep + 'python.txt.')
171
+ epilog = __(
172
+ 'Testing of coverage in the sources finished, look at the '
173
+ 'results in %(outdir)s{sep}python.txt.'
174
+ ).format(sep=os.path.sep)
165
175
 
166
176
  def init(self) -> None:
167
177
  self.c_sourcefiles: list[str] = []
168
178
  for pattern in self.config.coverage_c_path:
169
- pattern = path.join(self.srcdir, pattern)
170
- self.c_sourcefiles.extend(glob.glob(pattern))
179
+ pattern = self.srcdir / pattern
180
+ self.c_sourcefiles.extend(glob.glob(str(pattern))) # NoQA: PTH207
171
181
 
172
182
  self.c_regexes: list[tuple[str, re.Pattern[str]]] = []
173
- for (name, exp) in self.config.coverage_c_regexes.items():
183
+ for name, exp in self.config.coverage_c_regexes.items():
174
184
  try:
175
185
  self.c_regexes.append((name, re.compile(exp)))
176
186
  except Exception:
177
187
  logger.warning(__('invalid regex %r in coverage_c_regexes'), exp)
178
188
 
179
- self.c_ignorexps: dict[str, list[re.Pattern[str]]] = {}
180
- for (name, exps) in self.config.coverage_ignore_c_items.items():
181
- self.c_ignorexps[name] = compile_regex_list('coverage_ignore_c_items',
182
- exps)
183
- self.mod_ignorexps = compile_regex_list('coverage_ignore_modules',
184
- self.config.coverage_ignore_modules)
185
- self.cls_ignorexps = compile_regex_list('coverage_ignore_classes',
186
- self.config.coverage_ignore_classes)
187
- self.fun_ignorexps = compile_regex_list('coverage_ignore_functions',
188
- self.config.coverage_ignore_functions)
189
- self.py_ignorexps = compile_regex_list('coverage_ignore_pyobjects',
190
- self.config.coverage_ignore_pyobjects)
189
+ self.c_ignorexps: dict[str, list[re.Pattern[str]]] = {
190
+ name: compile_regex_list('coverage_ignore_c_items', exps)
191
+ for name, exps in self.config.coverage_ignore_c_items.items()
192
+ }
193
+ self.mod_ignorexps = compile_regex_list(
194
+ 'coverage_ignore_modules', self.config.coverage_ignore_modules
195
+ )
196
+ self.cls_ignorexps = compile_regex_list(
197
+ 'coverage_ignore_classes', self.config.coverage_ignore_classes
198
+ )
199
+ self.fun_ignorexps = compile_regex_list(
200
+ 'coverage_ignore_functions', self.config.coverage_ignore_functions
201
+ )
202
+ self.py_ignorexps = compile_regex_list(
203
+ 'coverage_ignore_pyobjects', self.config.coverage_ignore_pyobjects
204
+ )
191
205
 
192
206
  def get_outdated_docs(self) -> str:
193
207
  return 'coverage overview'
@@ -209,7 +223,7 @@ class CoverageBuilder(Builder):
209
223
  c_objects[obj[2]] = obj[1]
210
224
  for filename in self.c_sourcefiles:
211
225
  undoc: set[tuple[str, str]] = set()
212
- with open(filename, encoding="utf-8") as f:
226
+ with open(filename, encoding='utf-8') as f:
213
227
  for line in f:
214
228
  for key, regex in self.c_regexes:
215
229
  match = regex.match(line)
@@ -220,7 +234,7 @@ class CoverageBuilder(Builder):
220
234
  continue
221
235
 
222
236
  if name not in c_objects[key]:
223
- for exp in self.c_ignorexps.get(key, []):
237
+ for exp in self.c_ignorexps.get(key, ()):
224
238
  if exp.match(name):
225
239
  break
226
240
  else:
@@ -230,8 +244,8 @@ class CoverageBuilder(Builder):
230
244
  self.c_undoc[filename] = undoc
231
245
 
232
246
  def write_c_coverage(self) -> None:
233
- output_file = path.join(self.outdir, 'c.txt')
234
- with open(output_file, 'w', encoding="utf-8") as op:
247
+ output_file = self.outdir / 'c.txt'
248
+ with open(output_file, 'w', encoding='utf-8') as op:
235
249
  if self.config.coverage_write_headline:
236
250
  write_header(op, 'Undocumented C API elements', '=')
237
251
  op.write('\n')
@@ -239,22 +253,26 @@ class CoverageBuilder(Builder):
239
253
  for filename, undoc in self.c_undoc.items():
240
254
  write_header(op, filename)
241
255
  for typ, name in sorted(undoc):
242
- op.write(' * %-50s [%9s]\n' % (name, typ))
256
+ op.write(f' * {name:<50} [{typ:>9}]\n')
243
257
  if self.config.coverage_show_missing_items:
244
258
  if self.app.quiet:
245
- logger.warning(__('undocumented c api: %s [%s] in file %s'),
246
- name, typ, filename)
259
+ logger.warning(
260
+ __('undocumented c api: %s [%s] in file %s'),
261
+ name,
262
+ typ,
263
+ filename,
264
+ )
247
265
  else:
248
- logger.info(red('undocumented ') + 'c ' + 'api ' +
249
- '%-30s' % (name + " [%9s]" % typ) +
250
- red(' - in file ') + filename)
266
+ logger.info(
267
+ red('undocumented ') # NoQA: G003
268
+ + f'c api {f"{name} [{typ:>9}]":<30}'
269
+ + red(' - in file ')
270
+ + filename
271
+ )
251
272
  op.write('\n')
252
273
 
253
274
  def ignore_pyobj(self, full_name: str) -> bool:
254
- return any(
255
- exp.search(full_name)
256
- for exp in self.py_ignorexps
257
- )
275
+ return any(exp.search(full_name) for exp in self.py_ignorexps)
258
276
 
259
277
  def build_py_coverage(self) -> None:
260
278
  seen_objects = frozenset(self.env.domaindata['py']['objects'])
@@ -263,7 +281,10 @@ class CoverageBuilder(Builder):
263
281
  skip_undoc = self.config.coverage_skip_undoc_in_source
264
282
 
265
283
  modules = _determine_py_coverage_modules(
266
- self.config.coverage_modules, seen_modules, self.mod_ignorexps, self.py_undoc,
284
+ self.config.coverage_modules,
285
+ seen_modules,
286
+ self.mod_ignorexps,
287
+ self.py_undoc,
267
288
  )
268
289
  for mod_name in modules:
269
290
  ignore = False
@@ -336,8 +357,7 @@ class CoverageBuilder(Builder):
336
357
  attr = safe_getattr(obj, attr_name)
337
358
  except AttributeError:
338
359
  continue
339
- if not (inspect.ismethod(attr) or
340
- inspect.isfunction(attr)):
360
+ if not (inspect.ismethod(attr) or inspect.isfunction(attr)):
341
361
  continue
342
362
  if attr_name[0] == '_':
343
363
  # starts with an underscore, ignore it
@@ -380,7 +400,11 @@ class CoverageBuilder(Builder):
380
400
  else:
381
401
  value = 100.0
382
402
 
383
- table.append([module, '%.2f%%' % value, '%d' % len(self.py_undocumented[module])])
403
+ table.append([
404
+ module,
405
+ f'{value:.2f}%',
406
+ str(len(self.py_undocumented[module])),
407
+ ])
384
408
 
385
409
  if all_objects:
386
410
  table.append([
@@ -391,13 +415,12 @@ class CoverageBuilder(Builder):
391
415
  else:
392
416
  table.append(['TOTAL', '100', '0'])
393
417
 
394
- for line in _write_table(table):
395
- op.write(f'{line}\n')
418
+ op.writelines(f'{line}\n' for line in _write_table(table))
396
419
 
397
420
  def write_py_coverage(self) -> None:
398
- output_file = path.join(self.outdir, 'python.txt')
421
+ output_file = self.outdir / 'python.txt'
399
422
  failed = []
400
- with open(output_file, 'w', encoding="utf-8") as op:
423
+ with open(output_file, 'w', encoding='utf-8') as op:
401
424
  if self.config.coverage_write_headline:
402
425
  write_header(op, 'Undocumented Python objects', '=')
403
426
 
@@ -421,76 +444,114 @@ class CoverageBuilder(Builder):
421
444
  write_header(op, name)
422
445
  if undoc['funcs']:
423
446
  op.write('Functions:\n')
424
- op.writelines(' * %s\n' % x for x in undoc['funcs'])
447
+ op.writelines(f' * {x}\n' for x in undoc['funcs'])
425
448
  if self.config.coverage_show_missing_items:
426
449
  if self.app.quiet:
427
450
  for func in undoc['funcs']:
428
451
  logger.warning(
429
452
  __('undocumented python function: %s :: %s'),
430
- name, func)
453
+ name,
454
+ func,
455
+ )
431
456
  else:
432
457
  for func in undoc['funcs']:
433
- logger.info(red('undocumented ') + 'py ' + 'function ' +
434
- '%-30s' % func + red(' - in module ') + name)
458
+ logger.info(
459
+ red('undocumented ') # NoQA: G003
460
+ + f'py function {func:<30}'
461
+ + red(' - in module ')
462
+ + name
463
+ )
435
464
  op.write('\n')
436
465
  if undoc['classes']:
437
466
  op.write('Classes:\n')
438
- for class_name, methods in sorted(
439
- undoc['classes'].items()):
467
+ for class_name, methods in sorted(undoc['classes'].items()):
440
468
  if not methods:
441
- op.write(' * %s\n' % class_name)
469
+ op.write(f' * {class_name}\n')
442
470
  if self.config.coverage_show_missing_items:
443
471
  if self.app.quiet:
444
472
  logger.warning(
445
473
  __('undocumented python class: %s :: %s'),
446
- name, class_name)
474
+ name,
475
+ class_name,
476
+ )
447
477
  else:
448
- logger.info(red('undocumented ') + 'py ' +
449
- 'class ' + '%-30s' % class_name +
450
- red(' - in module ') + name)
478
+ logger.info(
479
+ red('undocumented ') # NoQA: G003
480
+ + f'py class {class_name:<30}'
481
+ + red(' - in module ')
482
+ + name
483
+ )
451
484
  else:
452
- op.write(' * %s -- missing methods:\n\n' % class_name)
453
- op.writelines(' - %s\n' % x for x in methods)
485
+ op.write(f' * {class_name} -- missing methods:\n\n')
486
+ op.writelines(f' - {x}\n' for x in methods)
454
487
  if self.config.coverage_show_missing_items:
455
488
  if self.app.quiet:
456
489
  for meth in methods:
457
490
  logger.warning(
458
- __('undocumented python method:'
459
- ' %s :: %s :: %s'),
460
- name, class_name, meth)
491
+ __(
492
+ 'undocumented python method:'
493
+ ' %s :: %s :: %s'
494
+ ),
495
+ name,
496
+ class_name,
497
+ meth,
498
+ )
461
499
  else:
462
500
  for meth in methods:
463
- logger.info(red('undocumented ') + 'py ' +
464
- 'method ' + '%-30s' %
465
- (class_name + '.' + meth) +
466
- red(' - in module ') + name)
501
+ logger.info(
502
+ red('undocumented ') # NoQA: G003
503
+ + f'py method {f"{class_name}.{meth}":<30}'
504
+ + red(' - in module ')
505
+ + name
506
+ )
467
507
  op.write('\n')
468
508
 
469
509
  if failed:
470
510
  write_header(op, 'Modules that failed to import')
471
- op.writelines(' * %s -- %s\n' % x for x in failed)
511
+ op.writelines(f' * {name} -- {err}\n' for name, err in failed)
472
512
 
473
513
  def finish(self) -> None:
474
514
  # dump the coverage data to a pickle file too
475
- picklepath = path.join(self.outdir, 'undoc.pickle')
515
+ picklepath = self.outdir / 'undoc.pickle'
476
516
  with open(picklepath, 'wb') as dumpfile:
477
- pickle.dump((self.py_undoc, self.c_undoc,
478
- self.py_undocumented, self.py_documented), dumpfile)
517
+ pickle.dump(
518
+ (self.py_undoc, self.c_undoc, self.py_undocumented, self.py_documented),
519
+ dumpfile,
520
+ )
479
521
 
480
522
 
481
523
  def setup(app: Sphinx) -> ExtensionMetadata:
482
524
  app.add_builder(CoverageBuilder)
483
- app.add_config_value('coverage_modules', (), '', types={tuple, list})
484
- app.add_config_value('coverage_ignore_modules', [], '')
485
- app.add_config_value('coverage_ignore_functions', [], '')
486
- app.add_config_value('coverage_ignore_classes', [], '')
487
- app.add_config_value('coverage_ignore_pyobjects', [], '')
488
- app.add_config_value('coverage_c_path', [], '')
489
- app.add_config_value('coverage_c_regexes', {}, '')
490
- app.add_config_value('coverage_ignore_c_items', {}, '')
491
- app.add_config_value('coverage_write_headline', True, '')
492
- app.add_config_value('coverage_statistics_to_report', True, '', bool)
493
- app.add_config_value('coverage_statistics_to_stdout', True, '', bool)
494
- app.add_config_value('coverage_skip_undoc_in_source', False, '')
495
- app.add_config_value('coverage_show_missing_items', False, '')
496
- return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
525
+ app.add_config_value('coverage_modules', (), '', types=frozenset({list, tuple}))
526
+ app.add_config_value(
527
+ 'coverage_ignore_modules', [], '', types=frozenset({list, tuple})
528
+ )
529
+ app.add_config_value(
530
+ 'coverage_ignore_functions', [], '', types=frozenset({list, tuple})
531
+ )
532
+ app.add_config_value(
533
+ 'coverage_ignore_classes', [], '', types=frozenset({list, tuple})
534
+ )
535
+ app.add_config_value(
536
+ 'coverage_ignore_pyobjects', [], '', types=frozenset({list, tuple})
537
+ )
538
+ app.add_config_value('coverage_c_path', [], '', types=frozenset({list, tuple}))
539
+ app.add_config_value('coverage_c_regexes', {}, '', types=frozenset({dict}))
540
+ app.add_config_value('coverage_ignore_c_items', {}, '', types=frozenset({dict}))
541
+ app.add_config_value('coverage_write_headline', True, '', types=frozenset({bool}))
542
+ app.add_config_value(
543
+ 'coverage_statistics_to_report', True, '', types=frozenset({bool})
544
+ )
545
+ app.add_config_value(
546
+ 'coverage_statistics_to_stdout', True, '', types=frozenset({bool})
547
+ )
548
+ app.add_config_value(
549
+ 'coverage_skip_undoc_in_source', False, '', types=frozenset({bool})
550
+ )
551
+ app.add_config_value(
552
+ 'coverage_show_missing_items', False, '', types=frozenset({bool})
553
+ )
554
+ return {
555
+ 'version': sphinx.__display_version__,
556
+ 'parallel_read_safe': True,
557
+ }