Sphinx 7.1.1__py3-none-any.whl → 7.2.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (313) hide show
  1. sphinx/__init__.py +6 -6
  2. sphinx/__main__.py +3 -1
  3. sphinx/addnodes.py +35 -22
  4. sphinx/application.py +40 -38
  5. sphinx/builders/__init__.py +16 -12
  6. sphinx/builders/_epub_base.py +15 -11
  7. sphinx/builders/changes.py +6 -4
  8. sphinx/builders/dirhtml.py +4 -2
  9. sphinx/builders/dummy.py +6 -4
  10. sphinx/builders/epub3.py +16 -8
  11. sphinx/builders/gettext.py +40 -43
  12. sphinx/builders/html/__init__.py +166 -196
  13. sphinx/builders/html/_assets.py +116 -0
  14. sphinx/builders/html/transforms.py +4 -2
  15. sphinx/builders/latex/__init__.py +12 -7
  16. sphinx/builders/latex/theming.py +5 -2
  17. sphinx/builders/latex/transforms.py +6 -3
  18. sphinx/builders/linkcheck.py +21 -13
  19. sphinx/builders/manpage.py +6 -4
  20. sphinx/builders/singlehtml.py +16 -9
  21. sphinx/builders/texinfo.py +11 -6
  22. sphinx/builders/text.py +8 -3
  23. sphinx/builders/xml.py +9 -4
  24. sphinx/cmd/build.py +27 -14
  25. sphinx/cmd/make_mode.py +13 -4
  26. sphinx/cmd/quickstart.py +13 -4
  27. sphinx/config.py +17 -14
  28. sphinx/deprecation.py +4 -2
  29. sphinx/directives/__init__.py +44 -12
  30. sphinx/directives/code.py +5 -4
  31. sphinx/directives/other.py +92 -44
  32. sphinx/directives/patches.py +1 -1
  33. sphinx/domains/__init__.py +11 -8
  34. sphinx/domains/c.py +67 -57
  35. sphinx/domains/changeset.py +3 -2
  36. sphinx/domains/citation.py +2 -1
  37. sphinx/domains/cpp.py +136 -93
  38. sphinx/domains/index.py +9 -5
  39. sphinx/domains/javascript.py +32 -19
  40. sphinx/domains/math.py +5 -3
  41. sphinx/domains/python.py +69 -57
  42. sphinx/domains/rst.py +20 -11
  43. sphinx/domains/std.py +21 -15
  44. sphinx/environment/__init__.py +97 -65
  45. sphinx/environment/adapters/indexentries.py +13 -10
  46. sphinx/environment/adapters/toctree.py +485 -308
  47. sphinx/environment/collectors/__init__.py +3 -4
  48. sphinx/environment/collectors/asset.py +10 -4
  49. sphinx/environment/collectors/dependencies.py +7 -4
  50. sphinx/environment/collectors/metadata.py +7 -5
  51. sphinx/environment/collectors/title.py +5 -3
  52. sphinx/environment/collectors/toctree.py +13 -8
  53. sphinx/errors.py +1 -1
  54. sphinx/events.py +5 -5
  55. sphinx/ext/apidoc.py +49 -27
  56. sphinx/ext/autodoc/__init__.py +179 -161
  57. sphinx/ext/autodoc/directive.py +10 -6
  58. sphinx/ext/autodoc/importer.py +22 -13
  59. sphinx/ext/autodoc/mock.py +4 -1
  60. sphinx/ext/autodoc/preserve_defaults.py +80 -12
  61. sphinx/ext/autodoc/type_comment.py +14 -10
  62. sphinx/ext/autodoc/typehints.py +7 -3
  63. sphinx/ext/autosectionlabel.py +6 -3
  64. sphinx/ext/autosummary/__init__.py +21 -15
  65. sphinx/ext/autosummary/generate.py +176 -126
  66. sphinx/ext/coverage.py +93 -8
  67. sphinx/ext/doctest.py +28 -17
  68. sphinx/ext/duration.py +19 -17
  69. sphinx/ext/extlinks.py +11 -6
  70. sphinx/ext/githubpages.py +8 -7
  71. sphinx/ext/graphviz.py +61 -17
  72. sphinx/ext/ifconfig.py +7 -4
  73. sphinx/ext/imgconverter.py +4 -2
  74. sphinx/ext/imgmath.py +29 -23
  75. sphinx/ext/inheritance_diagram.py +41 -27
  76. sphinx/ext/intersphinx.py +45 -38
  77. sphinx/ext/linkcode.py +8 -5
  78. sphinx/ext/mathjax.py +13 -9
  79. sphinx/ext/napoleon/__init__.py +3 -3
  80. sphinx/ext/napoleon/docstring.py +40 -31
  81. sphinx/ext/todo.py +10 -7
  82. sphinx/ext/viewcode.py +46 -25
  83. sphinx/extension.py +1 -1
  84. sphinx/highlighting.py +20 -12
  85. sphinx/io.py +5 -4
  86. sphinx/jinja2glue.py +24 -19
  87. sphinx/locale/__init__.py +8 -2
  88. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  89. sphinx/locale/ar/LC_MESSAGES/sphinx.po +756 -740
  90. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  91. sphinx/locale/bg/LC_MESSAGES/sphinx.po +754 -738
  92. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  93. sphinx/locale/bn/LC_MESSAGES/sphinx.po +755 -739
  94. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  95. sphinx/locale/ca/LC_MESSAGES/sphinx.po +768 -752
  96. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  97. sphinx/locale/cak/LC_MESSAGES/sphinx.po +754 -738
  98. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/cs/LC_MESSAGES/sphinx.po +758 -742
  100. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/cy/LC_MESSAGES/sphinx.po +759 -743
  102. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/da/LC_MESSAGES/sphinx.po +760 -744
  104. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/de/LC_MESSAGES/sphinx.po +759 -743
  106. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +754 -738
  108. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/el/LC_MESSAGES/sphinx.po +763 -747
  110. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +754 -738
  112. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +754 -738
  114. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +768 -752
  116. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +754 -738
  118. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/eo/LC_MESSAGES/sphinx.po +754 -738
  120. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/es/LC_MESSAGES/sphinx.po +767 -751
  122. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +754 -738
  124. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/et/LC_MESSAGES/sphinx.po +762 -746
  126. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/eu/LC_MESSAGES/sphinx.po +755 -739
  128. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/fa/LC_MESSAGES/sphinx.po +766 -750
  130. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/fi/LC_MESSAGES/sphinx.po +754 -738
  132. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/fr/LC_MESSAGES/sphinx.po +768 -752
  134. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +754 -738
  136. sphinx/locale/gl/LC_MESSAGES/sphinx.js +60 -0
  137. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/gl/LC_MESSAGES/sphinx.po +3695 -0
  139. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/he/LC_MESSAGES/sphinx.po +755 -739
  141. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/hi/LC_MESSAGES/sphinx.po +763 -747
  143. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +754 -738
  145. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/hr/LC_MESSAGES/sphinx.po +760 -744
  147. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/hu/LC_MESSAGES/sphinx.po +759 -743
  149. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/id/LC_MESSAGES/sphinx.po +765 -749
  151. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/is/LC_MESSAGES/sphinx.po +760 -744
  153. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/it/LC_MESSAGES/sphinx.po +760 -744
  155. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/ja/LC_MESSAGES/sphinx.po +767 -751
  157. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/ka/LC_MESSAGES/sphinx.po +759 -743
  159. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/ko/LC_MESSAGES/sphinx.po +767 -751
  161. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/lt/LC_MESSAGES/sphinx.po +755 -739
  163. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/lv/LC_MESSAGES/sphinx.po +755 -739
  165. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/mk/LC_MESSAGES/sphinx.po +754 -738
  167. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +755 -739
  169. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ne/LC_MESSAGES/sphinx.po +755 -739
  171. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/nl/LC_MESSAGES/sphinx.po +760 -744
  173. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/pl/LC_MESSAGES/sphinx.po +762 -745
  175. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/pt/LC_MESSAGES/sphinx.po +754 -738
  177. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +768 -752
  179. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +755 -739
  181. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/ro/LC_MESSAGES/sphinx.po +759 -743
  183. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/ru/LC_MESSAGES/sphinx.po +760 -744
  185. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/si/LC_MESSAGES/sphinx.po +754 -738
  187. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/sk/LC_MESSAGES/sphinx.po +765 -749
  189. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/sl/LC_MESSAGES/sphinx.po +755 -739
  191. sphinx/locale/sphinx.pot +748 -740
  192. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/sq/LC_MESSAGES/sphinx.po +768 -752
  194. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/sr/LC_MESSAGES/sphinx.po +754 -738
  196. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +754 -738
  198. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +754 -738
  200. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sv/LC_MESSAGES/sphinx.po +755 -739
  202. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/ta/LC_MESSAGES/sphinx.po +754 -738
  204. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/te/LC_MESSAGES/sphinx.po +754 -738
  206. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/tr/LC_MESSAGES/sphinx.po +763 -747
  208. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +760 -749
  210. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/ur/LC_MESSAGES/sphinx.po +759 -748
  212. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/vi/LC_MESSAGES/sphinx.po +754 -738
  214. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  215. sphinx/locale/yue/LC_MESSAGES/sphinx.po +754 -738
  216. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  217. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +768 -752
  218. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  219. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +754 -738
  220. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  221. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +767 -751
  222. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  223. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +754 -738
  224. sphinx/parsers.py +5 -4
  225. sphinx/project.py +52 -34
  226. sphinx/pycode/__init__.py +2 -1
  227. sphinx/pycode/ast.py +7 -13
  228. sphinx/pycode/parser.py +42 -38
  229. sphinx/registry.py +35 -29
  230. sphinx/roles.py +9 -4
  231. sphinx/search/__init__.py +5 -17
  232. sphinx/search/da.py +1 -1
  233. sphinx/search/de.py +1 -1
  234. sphinx/search/en.py +1 -1
  235. sphinx/search/es.py +1 -1
  236. sphinx/search/fi.py +1 -1
  237. sphinx/search/fr.py +1 -1
  238. sphinx/search/hu.py +1 -1
  239. sphinx/search/it.py +1 -1
  240. sphinx/search/ja.py +1 -1
  241. sphinx/search/nl.py +1 -1
  242. sphinx/search/no.py +1 -1
  243. sphinx/search/pt.py +1 -1
  244. sphinx/search/ro.py +1 -1
  245. sphinx/search/ru.py +1 -1
  246. sphinx/search/sv.py +1 -1
  247. sphinx/search/tr.py +1 -1
  248. sphinx/search/zh.py +1 -1
  249. sphinx/testing/fixtures.py +23 -30
  250. sphinx/testing/path.py +9 -0
  251. sphinx/testing/restructuredtext.py +13 -5
  252. sphinx/testing/util.py +20 -63
  253. sphinx/texinputs/sphinxlatexobjects.sty +15 -15
  254. sphinx/themes/agogo/static/agogo.css_t +10 -4
  255. sphinx/themes/basic/layout.html +1 -1
  256. sphinx/themes/basic/static/basic.css_t +4 -0
  257. sphinx/themes/basic/static/documentation_options.js_t +1 -2
  258. sphinx/themes/basic/static/searchtools.js +17 -9
  259. sphinx/themes/basic/static/sphinx_highlight.js +13 -3
  260. sphinx/themes/bizstyle/static/bizstyle.css_t +4 -0
  261. sphinx/themes/classic/theme.conf +1 -1
  262. sphinx/themes/epub/static/epub.css_t +6 -1
  263. sphinx/themes/haiku/theme.conf +1 -1
  264. sphinx/themes/nature/static/nature.css_t +4 -0
  265. sphinx/themes/nonav/static/nonav.css_t +6 -1
  266. sphinx/themes/pyramid/static/pyramid.css_t +4 -0
  267. sphinx/themes/scrolls/static/scrolls.css_t +4 -0
  268. sphinx/themes/scrolls/theme.conf +1 -1
  269. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +4 -0
  270. sphinx/theming.py +9 -7
  271. sphinx/transforms/__init__.py +79 -3
  272. sphinx/transforms/compact_bullet_list.py +6 -3
  273. sphinx/transforms/i18n.py +26 -10
  274. sphinx/transforms/post_transforms/__init__.py +21 -8
  275. sphinx/transforms/post_transforms/code.py +6 -3
  276. sphinx/transforms/post_transforms/images.py +13 -9
  277. sphinx/util/__init__.py +21 -92
  278. sphinx/util/cfamily.py +7 -4
  279. sphinx/util/display.py +3 -2
  280. sphinx/util/docfields.py +7 -6
  281. sphinx/util/docstrings.py +1 -1
  282. sphinx/util/docutils.py +41 -31
  283. sphinx/util/fileutil.py +9 -6
  284. sphinx/util/i18n.py +21 -18
  285. sphinx/util/images.py +2 -1
  286. sphinx/util/index_entries.py +27 -0
  287. sphinx/util/inspect.py +83 -67
  288. sphinx/util/inventory.py +4 -2
  289. sphinx/util/logging.py +9 -6
  290. sphinx/util/matching.py +5 -2
  291. sphinx/util/math.py +6 -3
  292. sphinx/util/nodes.py +70 -31
  293. sphinx/util/osutil.py +22 -40
  294. sphinx/util/parallel.py +4 -1
  295. sphinx/util/rst.py +7 -3
  296. sphinx/util/tags.py +11 -4
  297. sphinx/util/template.py +17 -14
  298. sphinx/util/typing.py +61 -20
  299. sphinx/versioning.py +6 -4
  300. sphinx/writers/html.py +1 -1
  301. sphinx/writers/html5.py +32 -24
  302. sphinx/writers/latex.py +67 -53
  303. sphinx/writers/manpage.py +9 -5
  304. sphinx/writers/texinfo.py +11 -9
  305. sphinx/writers/text.py +14 -9
  306. sphinx/writers/xml.py +3 -2
  307. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/METADATA +7 -5
  308. sphinx-7.2.0.dist-info/RECORD +568 -0
  309. sphinx/testing/comparer.py +0 -97
  310. sphinx-7.1.1.dist-info/RECORD +0 -564
  311. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/LICENSE +0 -0
  312. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/WHEEL +0 -0
  313. {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/entry_points.txt +0 -0
@@ -4,12 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- from docutils import nodes
8
-
9
- from sphinx.environment import BuildEnvironment
10
-
11
7
  if TYPE_CHECKING:
8
+ from docutils import nodes
9
+
12
10
  from sphinx.application import Sphinx
11
+ from sphinx.environment import BuildEnvironment
13
12
 
14
13
 
15
14
  class EnvironmentCollector:
@@ -5,21 +5,24 @@ from __future__ import annotations
5
5
  import os
6
6
  from glob import glob
7
7
  from os import path
8
- from typing import Any
8
+ from typing import TYPE_CHECKING, Any
9
9
 
10
10
  from docutils import nodes
11
- from docutils.nodes import Node
12
11
  from docutils.utils import relative_path
13
12
 
14
13
  from sphinx import addnodes
15
- from sphinx.application import Sphinx
16
- from sphinx.environment import BuildEnvironment
17
14
  from sphinx.environment.collectors import EnvironmentCollector
18
15
  from sphinx.locale import __
19
16
  from sphinx.util import logging
20
17
  from sphinx.util.i18n import get_image_filename_for_language, search_image_for_language
21
18
  from sphinx.util.images import guess_mimetype
22
19
 
20
+ if TYPE_CHECKING:
21
+ from docutils.nodes import Node
22
+
23
+ from sphinx.application import Sphinx
24
+ from sphinx.environment import BuildEnvironment
25
+
23
26
  logger = logging.getLogger(__name__)
24
27
 
25
28
 
@@ -71,8 +74,11 @@ class ImageCollector(EnvironmentCollector):
71
74
 
72
75
  # Update `node['uri']` to a relative path from srcdir
73
76
  # from a relative path from current document.
77
+ original_uri = node['uri']
74
78
  node['uri'], _ = app.env.relfn2path(imguri, docname)
75
79
  candidates['*'] = node['uri']
80
+ if node['uri'] != original_uri:
81
+ node['original_uri'] = original_uri
76
82
 
77
83
  # map image paths to unique image names (so that they can be put
78
84
  # into a single directory)
@@ -4,16 +4,19 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  from os import path
7
- from typing import Any
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
- from docutils import nodes
10
9
  from docutils.utils import relative_path
11
10
 
12
- from sphinx.application import Sphinx
13
- from sphinx.environment import BuildEnvironment
14
11
  from sphinx.environment.collectors import EnvironmentCollector
15
12
  from sphinx.util.osutil import fs_encoding
16
13
 
14
+ if TYPE_CHECKING:
15
+ from docutils import nodes
16
+
17
+ from sphinx.application import Sphinx
18
+ from sphinx.environment import BuildEnvironment
19
+
17
20
 
18
21
  class DependenciesCollector(EnvironmentCollector):
19
22
  """dependencies collector for sphinx.environment."""
@@ -2,14 +2,16 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, List, cast
5
+ from typing import TYPE_CHECKING, Any, cast
6
6
 
7
7
  from docutils import nodes
8
8
 
9
- from sphinx.application import Sphinx
10
- from sphinx.environment import BuildEnvironment
11
9
  from sphinx.environment.collectors import EnvironmentCollector
12
10
 
11
+ if TYPE_CHECKING:
12
+ from sphinx.application import Sphinx
13
+ from sphinx.environment import BuildEnvironment
14
+
13
15
 
14
16
  class MetadataCollector(EnvironmentCollector):
15
17
  """metadata collector for sphinx.environment."""
@@ -32,10 +34,10 @@ class MetadataCollector(EnvironmentCollector):
32
34
  return
33
35
  elif isinstance(doctree[index], nodes.docinfo):
34
36
  md = app.env.metadata[app.env.docname]
35
- for node in doctree[index]: # type: ignore
37
+ for node in doctree[index]: # type: ignore[attr-defined]
36
38
  # nodes are multiply inherited...
37
39
  if isinstance(node, nodes.authors):
38
- authors = cast(List[nodes.author], node)
40
+ authors = cast(list[nodes.author], node)
39
41
  md['authors'] = [author.astext() for author in authors]
40
42
  elif isinstance(node, nodes.field):
41
43
  assert len(node) == 2
@@ -2,15 +2,17 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from docutils import nodes
8
8
 
9
- from sphinx.application import Sphinx
10
- from sphinx.environment import BuildEnvironment
11
9
  from sphinx.environment.collectors import EnvironmentCollector
12
10
  from sphinx.transforms import SphinxContentsFilter
13
11
 
12
+ if TYPE_CHECKING:
13
+ from sphinx.application import Sphinx
14
+ from sphinx.environment import BuildEnvironment
15
+
14
16
 
15
17
  class TitleCollector(EnvironmentCollector):
16
18
  """title collector for sphinx.environment."""
@@ -2,20 +2,25 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Sequence, TypeVar, cast
5
+ from typing import TYPE_CHECKING, Any, TypeVar, cast
6
6
 
7
7
  from docutils import nodes
8
- from docutils.nodes import Element, Node
9
8
 
10
9
  from sphinx import addnodes
11
- from sphinx.application import Sphinx
12
- from sphinx.environment import BuildEnvironment
13
- from sphinx.environment.adapters.toctree import TocTree
10
+ from sphinx.environment.adapters.toctree import note_toctree
14
11
  from sphinx.environment.collectors import EnvironmentCollector
15
12
  from sphinx.locale import __
16
13
  from sphinx.transforms import SphinxContentsFilter
17
14
  from sphinx.util import logging, url_re
18
15
 
16
+ if TYPE_CHECKING:
17
+ from collections.abc import Sequence
18
+
19
+ from docutils.nodes import Element, Node
20
+
21
+ from sphinx.application import Sphinx
22
+ from sphinx.environment import BuildEnvironment
23
+
19
24
  N = TypeVar('N')
20
25
 
21
26
  logger = logging.getLogger(__name__)
@@ -105,7 +110,7 @@ class TocTreeCollector(EnvironmentCollector):
105
110
  item = toctreenode.copy()
106
111
  entries.append(item)
107
112
  # important: do the inventory stuff
108
- TocTree(app.env).note(docname, toctreenode)
113
+ note_toctree(app.env, docname, toctreenode)
109
114
  # add object signatures within a section to the ToC
110
115
  elif isinstance(toctreenode, addnodes.desc):
111
116
  for sig_node in toctreenode:
@@ -115,9 +120,9 @@ class TocTreeCollector(EnvironmentCollector):
115
120
  if not sig_node.get('_toc_name', ''):
116
121
  continue
117
122
  # Skip if explicitly disabled
118
- if sig_node.parent.get('nocontentsentry'):
123
+ if sig_node.parent.get('no-contents-entry'):
119
124
  continue
120
- # Skip entries with no ID (e.g. with :noindex: set)
125
+ # Skip entries with no ID (e.g. with :no-index: set)
121
126
  ids = sig_node['ids']
122
127
  if not ids:
123
128
  continue
sphinx/errors.py CHANGED
@@ -50,7 +50,7 @@ class ExtensionError(SphinxError):
50
50
  self.modname = modname
51
51
 
52
52
  @property
53
- def category(self) -> str: # type: ignore
53
+ def category(self) -> str: # type: ignore[override]
54
54
  if self.modname:
55
55
  return 'Extension error (%s)' % self.modname
56
56
  else:
sphinx/events.py CHANGED
@@ -5,6 +5,7 @@ Gracefully adapted from the TextPress system by Armin.
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ import contextlib
8
9
  from collections import defaultdict
9
10
  from operator import attrgetter
10
11
  from typing import TYPE_CHECKING, Any, Callable, NamedTuple
@@ -82,12 +83,11 @@ class EventManager:
82
83
  def emit(self, name: str, *args: Any,
83
84
  allowed_exceptions: tuple[type[Exception], ...] = ()) -> list:
84
85
  """Emit a Sphinx event."""
85
- try:
86
+
87
+ # not every object likes to be repr()'d (think
88
+ # random stuff coming via autodoc)
89
+ with contextlib.suppress(Exception):
86
90
  logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
87
- except Exception:
88
- # not every object likes to be repr()'d (think
89
- # random stuff coming via autodoc)
90
- pass
91
91
 
92
92
  results = []
93
93
  listeners = sorted(self.listeners[name], key=attrgetter("priority"))
sphinx/ext/apidoc.py CHANGED
@@ -12,23 +12,30 @@ https://sat.qc.ca/
12
12
  from __future__ import annotations
13
13
 
14
14
  import argparse
15
+ import fnmatch
15
16
  import glob
16
17
  import locale
17
18
  import os
19
+ import re
18
20
  import sys
19
21
  from copy import copy
20
- from fnmatch import fnmatch
21
22
  from importlib.machinery import EXTENSION_SUFFIXES
22
23
  from os import path
23
- from typing import Any, Generator
24
+ from typing import TYPE_CHECKING, Any
24
25
 
25
26
  import sphinx.locale
26
27
  from sphinx import __display_version__, package_dir
27
28
  from sphinx.cmd.quickstart import EXTENSIONS
28
29
  from sphinx.locale import __
30
+ from sphinx.util import logging
29
31
  from sphinx.util.osutil import FileAvoidWrite, ensuredir
30
32
  from sphinx.util.template import ReSTRenderer
31
33
 
34
+ if TYPE_CHECKING:
35
+ from collections.abc import Generator, Sequence
36
+
37
+ logger = logging.getLogger(__name__)
38
+
32
39
  # automodule options
33
40
  if 'SPHINX_APIDOC_OPTIONS' in os.environ:
34
41
  OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',')
@@ -54,7 +61,7 @@ def is_initpy(filename: str) -> bool:
54
61
  )
55
62
 
56
63
 
57
- def module_join(*modnames: str) -> str:
64
+ def module_join(*modnames: str | None) -> str:
58
65
  """Join module names with dots."""
59
66
  return '.'.join(filter(None, modnames))
60
67
 
@@ -76,19 +83,19 @@ def write_file(name: str, text: str, opts: Any) -> None:
76
83
  fname = path.join(opts.destdir, f'{name}.{opts.suffix}')
77
84
  if opts.dryrun:
78
85
  if not quiet:
79
- print(__('Would create file %s.') % fname)
86
+ logger.info(__('Would create file %s.'), fname)
80
87
  return
81
88
  if not opts.force and path.isfile(fname):
82
89
  if not quiet:
83
- print(__('File %s already exists, skipping.') % fname)
90
+ logger.info(__('File %s already exists, skipping.'), fname)
84
91
  else:
85
92
  if not quiet:
86
- print(__('Creating file %s.') % fname)
93
+ logger.info(__('Creating file %s.'), fname)
87
94
  with FileAvoidWrite(fname) as f:
88
95
  f.write(text)
89
96
 
90
97
 
91
- def create_module_file(package: str, basename: str, opts: Any,
98
+ def create_module_file(package: str | None, basename: str, opts: Any,
92
99
  user_template_dir: str | None = None) -> None:
93
100
  """Build the text of the file and write the file."""
94
101
  options = copy(OPTIONS)
@@ -102,13 +109,19 @@ def create_module_file(package: str, basename: str, opts: Any,
102
109
  'qualname': qualname,
103
110
  'automodule_options': options,
104
111
  }
105
- text = ReSTRenderer([user_template_dir, template_dir]).render('module.rst_t', context)
112
+ if user_template_dir is not None:
113
+ template_path = [user_template_dir, template_dir]
114
+ else:
115
+ template_path = [template_dir]
116
+ text = ReSTRenderer(template_path).render('module.rst_t', context)
106
117
  write_file(qualname, text, opts)
107
118
 
108
119
 
109
- def create_package_file(root: str, master_package: str, subroot: str, py_files: list[str],
120
+ def create_package_file(root: str, master_package: str | None, subroot: str,
121
+ py_files: list[str],
110
122
  opts: Any, subs: list[str], is_namespace: bool,
111
- excludes: list[str] = [], user_template_dir: str | None = None,
123
+ excludes: Sequence[re.Pattern[str]] = (),
124
+ user_template_dir: str | None = None,
112
125
  ) -> None:
113
126
  """Build the text of the file and write the file."""
114
127
  # build a list of sub packages (directories containing an __init__ file)
@@ -138,7 +151,11 @@ def create_package_file(root: str, master_package: str, subroot: str, py_files:
138
151
  'show_headings': not opts.noheadings,
139
152
  'maxdepth': opts.maxdepth,
140
153
  }
141
- text = ReSTRenderer([user_template_dir, template_dir]).render('package.rst_t', context)
154
+ if user_template_dir is not None:
155
+ template_path = [user_template_dir, template_dir]
156
+ else:
157
+ template_path = [template_dir]
158
+ text = ReSTRenderer(template_path).render('package.rst_t', context)
142
159
  write_file(pkgname, text, opts)
143
160
 
144
161
  if submodules and opts.separatemodules:
@@ -163,11 +180,16 @@ def create_modules_toc_file(modules: list[str], opts: Any, name: str = 'modules'
163
180
  'maxdepth': opts.maxdepth,
164
181
  'docnames': modules,
165
182
  }
166
- text = ReSTRenderer([user_template_dir, template_dir]).render('toc.rst_t', context)
183
+ if user_template_dir is not None:
184
+ template_path = [user_template_dir, template_dir]
185
+ else:
186
+ template_path = [template_dir]
187
+ text = ReSTRenderer(template_path).render('toc.rst_t', context)
167
188
  write_file(name, text, opts)
168
189
 
169
190
 
170
- def is_skipped_package(dirname: str, opts: Any, excludes: list[str] = []) -> bool:
191
+ def is_skipped_package(dirname: str, opts: Any,
192
+ excludes: Sequence[re.Pattern[str]] = ()) -> bool:
171
193
  """Check if we want to skip this module."""
172
194
  if not path.isdir(dirname):
173
195
  return False
@@ -182,7 +204,7 @@ def is_skipped_package(dirname: str, opts: Any, excludes: list[str] = []) -> boo
182
204
  return all(is_excluded(path.join(dirname, f), excludes) for f in files)
183
205
 
184
206
 
185
- def is_skipped_module(filename: str, opts: Any, excludes: list[str]) -> bool:
207
+ def is_skipped_module(filename: str, opts: Any, _excludes: Sequence[re.Pattern[str]]) -> bool:
186
208
  """Check if we want to skip this module."""
187
209
  if not path.exists(filename):
188
210
  # skip if the file doesn't exist
@@ -193,7 +215,7 @@ def is_skipped_module(filename: str, opts: Any, excludes: list[str]) -> bool:
193
215
  return False
194
216
 
195
217
 
196
- def walk(rootpath: str, excludes: list[str], opts: Any,
218
+ def walk(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
197
219
  ) -> Generator[tuple[str, list[str], list[str]], None, None]:
198
220
  """Walk through the directory and list files and subdirectories up."""
199
221
  followlinks = getattr(opts, 'followlinks', False)
@@ -218,7 +240,7 @@ def walk(rootpath: str, excludes: list[str], opts: Any,
218
240
  yield root, subs, files
219
241
 
220
242
 
221
- def has_child_module(rootpath: str, excludes: list[str], opts: Any) -> bool:
243
+ def has_child_module(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any) -> bool:
222
244
  """Check the given directory contains child module/s (at least one)."""
223
245
  return any(
224
246
  files
@@ -226,7 +248,7 @@ def has_child_module(rootpath: str, excludes: list[str], opts: Any) -> bool:
226
248
  )
227
249
 
228
250
 
229
- def recurse_tree(rootpath: str, excludes: list[str], opts: Any,
251
+ def recurse_tree(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
230
252
  user_template_dir: str | None = None) -> list[str]:
231
253
  """
232
254
  Look for every file in the directory tree and create the corresponding
@@ -281,16 +303,13 @@ def recurse_tree(rootpath: str, excludes: list[str], opts: Any,
281
303
  return toplevels
282
304
 
283
305
 
284
- def is_excluded(root: str, excludes: list[str]) -> bool:
306
+ def is_excluded(root: str, excludes: Sequence[re.Pattern[str]]) -> bool:
285
307
  """Check if the directory is in the exclude list.
286
308
 
287
309
  Note: by having trailing slashes, we avoid common prefix issues, like
288
310
  e.g. an exclude "foo" also accidentally excluding "foobar".
289
311
  """
290
- return any(
291
- fnmatch(root, exclude)
292
- for exclude in excludes
293
- )
312
+ return any(exclude.match(root) for exclude in excludes)
294
313
 
295
314
 
296
315
  def get_parser() -> argparse.ArgumentParser:
@@ -390,13 +409,13 @@ Note: By default this script will not overwrite already created files."""))
390
409
  return parser
391
410
 
392
411
 
393
- def main(argv: list[str] = sys.argv[1:]) -> int:
412
+ def main(argv: Sequence[str] = (), /) -> int:
394
413
  """Parse and check the command line arguments."""
395
414
  locale.setlocale(locale.LC_ALL, '')
396
415
  sphinx.locale.init_console()
397
416
 
398
417
  parser = get_parser()
399
- args = parser.parse_args(argv)
418
+ args = parser.parse_args(argv or sys.argv[1:])
400
419
 
401
420
  rootpath = path.abspath(args.module_path)
402
421
 
@@ -407,11 +426,14 @@ def main(argv: list[str] = sys.argv[1:]) -> int:
407
426
  if args.suffix.startswith('.'):
408
427
  args.suffix = args.suffix[1:]
409
428
  if not path.isdir(rootpath):
410
- print(__('%s is not a directory.') % rootpath, file=sys.stderr)
429
+ logger.error(__('%s is not a directory.'), rootpath)
411
430
  raise SystemExit(1)
412
431
  if not args.dryrun:
413
432
  ensuredir(args.destdir)
414
- excludes = [path.abspath(exclude) for exclude in args.exclude_pattern]
433
+ excludes = tuple(
434
+ re.compile(fnmatch.translate(path.abspath(exclude)))
435
+ for exclude in dict.fromkeys(args.exclude_pattern)
436
+ )
415
437
  modules = recurse_tree(rootpath, excludes, args, args.templatedir)
416
438
 
417
439
  if args.full:
@@ -467,4 +489,4 @@ def main(argv: list[str] = sys.argv[1:]) -> int:
467
489
 
468
490
  # So program can be started with "python -m sphinx.apidoc ..."
469
491
  if __name__ == "__main__":
470
- main()
492
+ raise SystemExit(main(sys.argv[1:]))