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
@@ -4,10 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  import html
6
6
  import os
7
+ import os.path
7
8
  import re
8
9
  import time
9
- from os import path
10
- from typing import TYPE_CHECKING, Any, NamedTuple
10
+ from pathlib import Path
11
+ from typing import TYPE_CHECKING, NamedTuple
11
12
  from urllib.parse import quote
12
13
  from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
13
14
 
@@ -19,11 +20,14 @@ from sphinx.builders.html import StandaloneHTMLBuilder
19
20
  from sphinx.builders.html._build_info import BuildInfo
20
21
  from sphinx.locale import __
21
22
  from sphinx.util import logging
23
+ from sphinx.util._pathlib import _StrPath
22
24
  from sphinx.util.display import status_iterator
23
25
  from sphinx.util.fileutil import copy_asset_file
24
26
  from sphinx.util.osutil import copyfile, ensuredir, relpath
25
27
 
26
28
  if TYPE_CHECKING:
29
+ from typing import Any
30
+
27
31
  from docutils.nodes import Element, Node
28
32
 
29
33
  try:
@@ -123,8 +127,7 @@ ssp = sphinx_smarty_pants
123
127
 
124
128
 
125
129
  class EpubBuilder(StandaloneHTMLBuilder):
126
- """
127
- Builder that outputs epub files.
130
+ """Builder that outputs epub files.
128
131
 
129
132
  It creates the metainfo files container.opf, toc.ncx, mimetype, and
130
133
  META-INF/container.xml. Afterwards, all necessary files are zipped to an
@@ -156,7 +159,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
156
159
  guide_titles = GUIDE_TITLES
157
160
  media_types = MEDIA_TYPES
158
161
  refuri_re = REFURI_RE
159
- template_dir = ''
162
+ template_dir: _StrPath = _StrPath()
160
163
  doctype = ''
161
164
 
162
165
  def init(self) -> None:
@@ -226,18 +229,16 @@ class EpubBuilder(StandaloneHTMLBuilder):
226
229
  appeared.add(node['refuri'])
227
230
 
228
231
  def get_toc(self) -> None:
229
- """Get the total table of contents, containing the root_doc
230
- and pre and post files not managed by sphinx.
232
+ """Get the total table of contents, containing the master_doc
233
+ and pre and post files not managed by Sphinx.
231
234
  """
232
235
  doctree = self.env.get_and_resolve_doctree(
233
- self.config.root_doc, self, prune_toctrees=False, includehidden=True
236
+ self.config.master_doc, self, prune_toctrees=False, includehidden=True
234
237
  )
235
238
  self.refnodes = self.get_refnodes(doctree, [])
236
- master_dir = path.dirname(self.config.root_doc)
237
- if master_dir:
238
- master_dir += '/' # XXX or os.sep?
239
- for item in self.refnodes:
240
- item['refuri'] = master_dir + item['refuri']
239
+ master_dir = Path(self.config.master_doc).parent
240
+ for item in self.refnodes:
241
+ item['refuri'] = str(master_dir / item['refuri'])
241
242
  self.toc_add_files(self.refnodes)
242
243
 
243
244
  def toc_add_files(self, refnodes: list[dict[str, Any]]) -> None:
@@ -407,7 +408,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
407
408
 
408
409
  def is_vector_graphics(self, filename: str) -> bool:
409
410
  """Does the filename extension indicate a vector graphic format?"""
410
- ext = path.splitext(filename)[-1]
411
+ ext = os.path.splitext(filename)[-1]
411
412
  return ext in VECTOR_GRAPHICS_EXTENSIONS
412
413
 
413
414
  def copy_image_files_pil(self) -> None:
@@ -415,7 +416,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
415
416
  The method tries to read and write the files with Pillow, converting
416
417
  the format and resizing the image if necessary/possible.
417
418
  """
418
- ensuredir(path.join(self.outdir, self.imagedir))
419
+ ensuredir(self.outdir / self.imagedir)
419
420
  for src in status_iterator(
420
421
  self.images,
421
422
  __('copying images... '),
@@ -425,12 +426,12 @@ class EpubBuilder(StandaloneHTMLBuilder):
425
426
  ):
426
427
  dest = self.images[src]
427
428
  try:
428
- img = Image.open(path.join(self.srcdir, src))
429
+ img = Image.open(self.srcdir / src)
429
430
  except OSError:
430
431
  if not self.is_vector_graphics(src):
431
432
  logger.warning(
432
433
  __('cannot read image file %r: copying it instead'),
433
- path.join(self.srcdir, src),
434
+ self.srcdir / src,
434
435
  )
435
436
  try:
436
437
  copyfile(
@@ -441,7 +442,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
441
442
  except OSError as err:
442
443
  logger.warning(
443
444
  __('cannot copy image file %r: %s'),
444
- path.join(self.srcdir, src),
445
+ self.srcdir / src,
445
446
  err,
446
447
  )
447
448
  continue
@@ -457,11 +458,11 @@ class EpubBuilder(StandaloneHTMLBuilder):
457
458
  nh = round((height * nw) / width)
458
459
  img = img.resize((nw, nh), Image.BICUBIC)
459
460
  try:
460
- img.save(path.join(self.outdir, self.imagedir, dest))
461
+ img.save(self.outdir / self.imagedir / dest)
461
462
  except OSError as err:
462
463
  logger.warning(
463
464
  __('cannot write image file %r: %s'),
464
- path.join(self.srcdir, src),
465
+ self.srcdir / src,
465
466
  err,
466
467
  )
467
468
 
@@ -487,7 +488,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
487
488
  pagename: str,
488
489
  addctx: dict[str, Any],
489
490
  templatename: str = 'page.html',
490
- outfilename: str | None = None,
491
+ *,
492
+ outfilename: Path | None = None,
491
493
  event_arg: Any = None,
492
494
  ) -> None:
493
495
  """Create a rendered page.
@@ -500,13 +502,15 @@ class EpubBuilder(StandaloneHTMLBuilder):
500
502
  return
501
503
  self.fix_genindex(addctx['genindexentries'])
502
504
  addctx['doctype'] = self.doctype
503
- super().handle_page(pagename, addctx, templatename, outfilename, event_arg)
505
+ super().handle_page(
506
+ pagename, addctx, templatename, outfilename=outfilename, event_arg=event_arg
507
+ )
504
508
 
505
509
  def build_mimetype(self) -> None:
506
510
  """Write the metainfo file mimetype."""
507
511
  logger.info(__('writing mimetype file...'))
508
512
  copyfile(
509
- path.join(self.template_dir, 'mimetype'),
513
+ self.template_dir / 'mimetype',
510
514
  self.outdir / 'mimetype',
511
515
  force=True,
512
516
  )
@@ -517,7 +521,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
517
521
  outdir = self.outdir / 'META-INF'
518
522
  ensuredir(outdir)
519
523
  copyfile(
520
- path.join(self.template_dir, 'container.xml'),
524
+ self.template_dir / 'container.xml',
521
525
  outdir / 'container.xml',
522
526
  force=True,
523
527
  )
@@ -531,19 +535,20 @@ class EpubBuilder(StandaloneHTMLBuilder):
531
535
  else:
532
536
  time_tuple = time.gmtime()
533
537
 
534
- metadata: dict[str, Any] = {}
535
- metadata['title'] = html.escape(self.config.epub_title)
536
- metadata['author'] = html.escape(self.config.epub_author)
537
- metadata['uid'] = html.escape(self.config.epub_uid)
538
- metadata['lang'] = html.escape(self.config.epub_language)
539
- metadata['publisher'] = html.escape(self.config.epub_publisher)
540
- metadata['copyright'] = html.escape(self.config.epub_copyright)
541
- metadata['scheme'] = html.escape(self.config.epub_scheme)
542
- metadata['id'] = html.escape(self.config.epub_identifier)
543
- metadata['date'] = html.escape(time.strftime('%Y-%m-%d', time_tuple))
544
- metadata['manifest_items'] = []
545
- metadata['spines'] = []
546
- metadata['guides'] = []
538
+ metadata: dict[str, Any] = {
539
+ 'title': html.escape(self.config.epub_title),
540
+ 'author': html.escape(self.config.epub_author),
541
+ 'uid': html.escape(self.config.epub_uid),
542
+ 'lang': html.escape(self.config.epub_language),
543
+ 'publisher': html.escape(self.config.epub_publisher),
544
+ 'copyright': html.escape(self.config.epub_copyright),
545
+ 'scheme': html.escape(self.config.epub_scheme),
546
+ 'id': html.escape(self.config.epub_identifier),
547
+ 'date': html.escape(time.strftime('%Y-%m-%d', time_tuple)),
548
+ 'manifest_items': [],
549
+ 'spines': [],
550
+ 'guides': [],
551
+ }
547
552
  return metadata
548
553
 
549
554
  def build_content(self) -> None:
@@ -571,16 +576,17 @@ class EpubBuilder(StandaloneHTMLBuilder):
571
576
  if not self.use_index:
572
577
  self.ignored_files.append('genindex' + self.out_suffix)
573
578
  for root, dirs, files in os.walk(self.outdir):
579
+ root_path = Path(root)
574
580
  dirs.sort()
575
581
  for fn in sorted(files):
576
- filename = relpath(path.join(root, fn), self.outdir)
582
+ filename = relpath(root_path / fn, self.outdir)
577
583
  if filename in self.ignored_files:
578
584
  continue
579
- ext = path.splitext(filename)[-1]
585
+ ext = os.path.splitext(filename)[-1]
580
586
  if ext not in self.media_types:
581
587
  # we always have JS and potentially OpenSearch files, don't
582
588
  # always warn about them
583
- if ext not in ('.js', '.xml'):
589
+ if ext not in {'.js', '.xml'}:
584
590
  logger.warning(
585
591
  __('unknown mimetype for %s, ignoring'),
586
592
  filename,
@@ -631,7 +637,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
631
637
  spine = Spine(html.escape(self.make_id(self.coverpage_name)), True)
632
638
  metadata['spines'].insert(0, spine)
633
639
  if self.coverpage_name not in self.files:
634
- ext = path.splitext(self.coverpage_name)[-1]
640
+ ext = os.path.splitext(self.coverpage_name)[-1]
635
641
  self.files.append(self.coverpage_name)
636
642
  item = ManifestItem(
637
643
  html.escape(self.coverpage_name),
@@ -640,7 +646,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
640
646
  )
641
647
  metadata['manifest_items'].append(item)
642
648
  ctx = {'image': html.escape(image), 'title': self.config.project}
643
- self.handle_page(path.splitext(self.coverpage_name)[0], ctx, html_tmpl)
649
+ self.handle_page(
650
+ os.path.splitext(self.coverpage_name)[0], ctx, html_tmpl
651
+ )
644
652
  spinefiles.add(self.coverpage_name)
645
653
 
646
654
  auto_add_cover = True
@@ -676,7 +684,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
676
684
 
677
685
  # write the project file
678
686
  copy_asset_file(
679
- path.join(self.template_dir, 'content.opf.jinja'),
687
+ self.template_dir / 'content.opf.jinja',
680
688
  self.outdir,
681
689
  context=metadata,
682
690
  force=True,
@@ -700,8 +708,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
700
708
  Subelements of a node are nested inside the navpoint. For nested nodes
701
709
  the parent node is reinserted in the subnav.
702
710
  """
703
- navstack: list[NavPoint] = []
704
- navstack.append(NavPoint('dummy', 0, '', '', []))
711
+ navstack: list[NavPoint] = [NavPoint('dummy', 0, '', '', [])]
705
712
  level = 0
706
713
  lastnode = None
707
714
  for node in nodes:
@@ -735,7 +742,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
735
742
  navstack[-1].children.append(navpoint)
736
743
  navstack.append(navpoint)
737
744
  else:
738
- raise
745
+ msg = __('node has an invalid level')
746
+ raise ValueError(msg)
739
747
  lastnode = node
740
748
 
741
749
  return navstack[0].children
@@ -744,11 +752,12 @@ class EpubBuilder(StandaloneHTMLBuilder):
744
752
  """Create a dictionary with all metadata for the toc.ncx file
745
753
  properly escaped.
746
754
  """
747
- metadata: dict[str, Any] = {}
748
- metadata['uid'] = self.config.epub_uid
749
- metadata['title'] = html.escape(self.config.epub_title)
750
- metadata['level'] = level
751
- metadata['navpoints'] = navpoints
755
+ metadata: dict[str, Any] = {
756
+ 'uid': self.config.epub_uid,
757
+ 'title': html.escape(self.config.epub_title),
758
+ 'level': level,
759
+ 'navpoints': navpoints,
760
+ }
752
761
  return metadata
753
762
 
754
763
  def build_toc(self) -> None:
@@ -769,7 +778,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
769
778
  level = max(item['level'] for item in self.refnodes)
770
779
  level = min(level, self.config.epub_tocdepth)
771
780
  copy_asset_file(
772
- path.join(self.template_dir, 'toc.ncx.jinja'),
781
+ self.template_dir / 'toc.ncx.jinja',
773
782
  self.outdir,
774
783
  context=self.toc_metadata(level, navpoints),
775
784
  force=True,
@@ -783,10 +792,10 @@ class EpubBuilder(StandaloneHTMLBuilder):
783
792
  """
784
793
  outname = self.config.epub_basename + '.epub'
785
794
  logger.info(__('writing %s file...'), outname)
786
- epub_filename = path.join(self.outdir, outname)
795
+ epub_filename = self.outdir / outname
787
796
  with ZipFile(epub_filename, 'w', ZIP_DEFLATED) as epub:
788
- epub.write(path.join(self.outdir, 'mimetype'), 'mimetype', ZIP_STORED)
797
+ epub.write(self.outdir / 'mimetype', 'mimetype', ZIP_STORED)
789
798
  for filename in ('META-INF/container.xml', 'content.opf', 'toc.ncx'):
790
- epub.write(path.join(self.outdir, filename), filename, ZIP_DEFLATED)
799
+ epub.write(self.outdir / filename, filename, ZIP_DEFLATED)
791
800
  for filename in self.files:
792
- epub.write(path.join(self.outdir, filename), filename, ZIP_DEFLATED)
801
+ epub.write(self.outdir / filename, filename, ZIP_DEFLATED)
@@ -3,17 +3,15 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import html
6
- from os import path
7
6
  from typing import TYPE_CHECKING
8
7
 
9
8
  from sphinx import package_dir
9
+ from sphinx._cli.util.colour import bold
10
10
  from sphinx.builders import Builder
11
11
  from sphinx.locale import _, __
12
12
  from sphinx.theming import HTMLThemeFactory
13
13
  from sphinx.util import logging
14
- from sphinx.util.console import bold
15
14
  from sphinx.util.fileutil import copy_asset_file
16
- from sphinx.util.osutil import ensuredir, os_path
17
15
 
18
16
  if TYPE_CHECKING:
19
17
  from collections.abc import Set
@@ -25,9 +23,7 @@ logger = logging.getLogger(__name__)
25
23
 
26
24
 
27
25
  class ChangesBuilder(Builder):
28
- """
29
- Write a summary with all versionadded/changed/deprecated/removed directives.
30
- """
26
+ """Write a summary with all versionadded/changed/deprecated/removed directives."""
31
27
 
32
28
  name = 'changes'
33
29
  epilog = __('The overview file is in %(outdir)s.')
@@ -61,10 +57,7 @@ class ChangesBuilder(Builder):
61
57
  return
62
58
  logger.info(bold(__('writing summary file...')))
63
59
  for changeset in changesets:
64
- if isinstance(changeset.descname, tuple):
65
- descname = changeset.descname[0]
66
- else:
67
- descname = changeset.descname
60
+ descname = changeset.descname
68
61
  ttext = self.typemap[changeset.type]
69
62
  context = changeset.content.replace('\n', ' ')
70
63
  if descname and changeset.docname.startswith('c-api'):
@@ -108,9 +101,9 @@ class ChangesBuilder(Builder):
108
101
  'show_copyright': self.config.html_show_copyright,
109
102
  'show_sphinx': self.config.html_show_sphinx,
110
103
  }
111
- with open(path.join(self.outdir, 'index.html'), 'w', encoding='utf8') as f:
104
+ with open(self.outdir / 'index.html', 'w', encoding='utf8') as f:
112
105
  f.write(self.templates.render('changes/frameset.html', ctx))
113
- with open(path.join(self.outdir, 'changes.html'), 'w', encoding='utf8') as f:
106
+ with open(self.outdir / 'changes.html', 'w', encoding='utf8') as f:
114
107
  f.write(self.templates.render('changes/versionchanges.html', ctx))
115
108
 
116
109
  hltext = [
@@ -131,7 +124,7 @@ class ChangesBuilder(Builder):
131
124
  logger.info(bold(__('copying source files...')))
132
125
  for docname in self.env.all_docs:
133
126
  with open(
134
- self.env.doc2path(docname), encoding=self.env.config.source_encoding
127
+ self.env.doc2path(docname), encoding=self.config.source_encoding
135
128
  ) as f:
136
129
  try:
137
130
  lines = f.readlines()
@@ -140,27 +133,28 @@ class ChangesBuilder(Builder):
140
133
  __('could not read %r for changelog creation'), docname
141
134
  )
142
135
  continue
143
- targetfn = path.join(self.outdir, 'rst', os_path(docname)) + '.html'
144
- ensuredir(path.dirname(targetfn))
136
+ text = ''.join(hl(i + 1, line) for (i, line) in enumerate(lines))
137
+ ctx = {
138
+ 'filename': str(self.env.doc2path(docname, False)),
139
+ 'text': text,
140
+ }
141
+ rendered = self.templates.render('changes/rstsource.html', ctx)
142
+ targetfn = self.outdir / 'rst' / f'{docname}.html'
143
+ targetfn.parent.mkdir(parents=True, exist_ok=True)
145
144
  with open(targetfn, 'w', encoding='utf-8') as f:
146
- text = ''.join(hl(i + 1, line) for (i, line) in enumerate(lines))
147
- ctx = {
148
- 'filename': str(self.env.doc2path(docname, False)),
149
- 'text': text,
150
- }
151
- f.write(self.templates.render('changes/rstsource.html', ctx))
145
+ f.write(rendered)
152
146
  themectx = {
153
147
  'theme_' + key: val for (key, val) in self.theme.get_options({}).items()
154
148
  }
155
149
  copy_asset_file(
156
- path.join(package_dir, 'themes', 'default', 'static', 'default.css.jinja'),
150
+ package_dir.joinpath('themes', 'default', 'static', 'default.css.jinja'),
157
151
  self.outdir,
158
152
  context=themectx,
159
153
  renderer=self.templates,
160
154
  force=True,
161
155
  )
162
156
  copy_asset_file(
163
- path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'),
157
+ package_dir.joinpath('themes', 'basic', 'static', 'basic.css'),
164
158
  self.outdir / 'basic.css',
165
159
  force=True,
166
160
  )
@@ -2,12 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from os import path
5
+ from pathlib import Path
6
6
  from typing import TYPE_CHECKING
7
7
 
8
8
  from sphinx.builders.html import StandaloneHTMLBuilder
9
9
  from sphinx.util import logging
10
- from sphinx.util.osutil import SEP, os_path
10
+ from sphinx.util.osutil import SEP
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from sphinx.application import Sphinx
@@ -17,8 +17,7 @@ logger = logging.getLogger(__name__)
17
17
 
18
18
 
19
19
  class DirectoryHTMLBuilder(StandaloneHTMLBuilder):
20
- """
21
- A StandaloneHTMLBuilder that creates all HTML pages as "index.html" in
20
+ """A StandaloneHTMLBuilder that creates all HTML pages as "index.html" in
22
21
  a directory given by their pagename, so that generated URLs don't have
23
22
  ``.html`` in them.
24
23
  """
@@ -32,15 +31,11 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder):
32
31
  return docname[:-5] # up to sep
33
32
  return docname + SEP
34
33
 
35
- def get_outfilename(self, pagename: str) -> str:
36
- if pagename == 'index' or pagename.endswith(SEP + 'index'):
37
- outfilename = path.join(self.outdir, os_path(pagename) + self.out_suffix)
38
- else:
39
- outfilename = path.join(
40
- self.outdir, os_path(pagename), 'index' + self.out_suffix
41
- )
42
-
43
- return outfilename
34
+ def get_output_path(self, page_name: str, /) -> Path:
35
+ page_parts = page_name.split(SEP)
36
+ if page_parts[-1] == 'index':
37
+ page_parts.pop()
38
+ return Path(self.outdir, *page_parts, f'index{self.out_suffix}')
44
39
 
45
40
 
46
41
  def setup(app: Sphinx) -> ExtensionMetadata:
sphinx/builders/epub3.py CHANGED
@@ -7,14 +7,14 @@ from __future__ import annotations
7
7
 
8
8
  import html
9
9
  import os
10
+ import os.path
10
11
  import re
11
12
  import time
12
- from os import path
13
- from typing import TYPE_CHECKING, Any, NamedTuple
13
+ from typing import TYPE_CHECKING, NamedTuple
14
14
 
15
15
  from sphinx import package_dir
16
16
  from sphinx.builders import _epub_base
17
- from sphinx.config import ENUM, Config
17
+ from sphinx.config import ENUM
18
18
  from sphinx.locale import __
19
19
  from sphinx.util import logging
20
20
  from sphinx.util.fileutil import copy_asset_file
@@ -22,8 +22,10 @@ from sphinx.util.osutil import make_filename
22
22
 
23
23
  if TYPE_CHECKING:
24
24
  from collections.abc import Set
25
+ from typing import Any
25
26
 
26
27
  from sphinx.application import Sphinx
28
+ from sphinx.config import Config
27
29
  from sphinx.util.typing import ExtensionMetadata
28
30
 
29
31
  logger = logging.getLogger(__name__)
@@ -65,14 +67,13 @@ _xml_name_start_char = (
65
67
  '|[\ufdf0-\ufffd]|[\U00010000-\U000effff]'
66
68
  )
67
69
  _xml_name_char = (
68
- _xml_name_start_char + r'\-|\.' '|[0-9]|\u00b7|[\u0300-\u036f]|[\u203f-\u2040]'
70
+ _xml_name_start_char + r'\-|\.|[0-9]|\u00b7|[\u0300-\u036f]|[\u203f-\u2040]'
69
71
  )
70
72
  _XML_NAME_PATTERN = re.compile(f'({_xml_name_start_char})({_xml_name_char})*')
71
73
 
72
74
 
73
75
  class Epub3Builder(_epub_base.EpubBuilder):
74
- """
75
- Builder that outputs epub3 files.
76
+ """Builder that outputs epub3 files.
76
77
 
77
78
  It creates the metainfo files content.opf, nav.xhtml, toc.ncx, mimetype,
78
79
  and META-INF/container.xml. Afterwards, all necessary files are zipped to
@@ -83,7 +84,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
83
84
  epilog = __('The ePub file is in %(outdir)s.')
84
85
 
85
86
  supported_remote_images = False
86
- template_dir = path.join(package_dir, 'templates', 'epub3')
87
+ template_dir = package_dir.joinpath('templates', 'epub3')
87
88
  doctype = DOCTYPE
88
89
  html_tag = HTML_TAG
89
90
  use_meta_charset = True
@@ -141,8 +142,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
141
142
  The difference from build_navpoints method is templates which are used
142
143
  when generating navigation documents.
143
144
  """
144
- navstack: list[NavPoint] = []
145
- navstack.append(NavPoint('', '', []))
145
+ navstack: list[NavPoint] = [NavPoint('', '', [])]
146
146
  level = 0
147
147
  for node in navnodes:
148
148
  if not node['text']:
@@ -199,7 +199,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
199
199
  refnodes = self.refnodes
200
200
  navlist = self.build_navlist(refnodes)
201
201
  copy_asset_file(
202
- path.join(self.template_dir, 'nav.xhtml.jinja'),
202
+ self.template_dir / 'nav.xhtml.jinja',
203
203
  self.outdir,
204
204
  context=self.navigation_doc_metadata(navlist),
205
205
  force=True,
@@ -286,35 +286,67 @@ def setup(app: Sphinx) -> ExtensionMetadata:
286
286
  app.add_builder(Epub3Builder)
287
287
 
288
288
  # config values
289
- app.add_config_value('epub_basename', lambda self: make_filename(self.project), '')
290
- app.add_config_value('epub_version', 3.0, 'epub') # experimental
291
- app.add_config_value('epub_theme', 'epub', 'epub')
292
- app.add_config_value('epub_theme_options', {}, 'epub')
293
- app.add_config_value('epub_title', lambda self: self.project, 'epub')
294
- app.add_config_value('epub_author', lambda self: self.author, 'epub')
295
- app.add_config_value('epub_language', lambda self: self.language or 'en', 'epub')
296
- app.add_config_value('epub_publisher', lambda self: self.author, 'epub')
297
- app.add_config_value('epub_copyright', lambda self: self.copyright, 'epub')
298
- app.add_config_value('epub_identifier', 'unknown', 'epub')
299
- app.add_config_value('epub_scheme', 'unknown', 'epub')
300
- app.add_config_value('epub_uid', 'unknown', 'env')
301
- app.add_config_value('epub_cover', (), 'env')
302
- app.add_config_value('epub_guide', (), 'env')
303
- app.add_config_value('epub_pre_files', [], 'env')
304
- app.add_config_value('epub_post_files', [], 'env')
305
- app.add_config_value('epub_css_files', lambda config: config.html_css_files, 'epub')
306
- app.add_config_value('epub_exclude_files', [], 'env')
307
- app.add_config_value('epub_tocdepth', 3, 'env')
308
- app.add_config_value('epub_tocdup', True, 'env')
309
- app.add_config_value('epub_tocscope', 'default', 'env')
310
- app.add_config_value('epub_fix_images', False, 'env')
311
- app.add_config_value('epub_max_image_width', 0, 'env')
312
- app.add_config_value('epub_show_urls', 'inline', 'epub')
313
- app.add_config_value('epub_use_index', lambda self: self.html_use_index, 'epub')
314
- app.add_config_value('epub_description', 'unknown', 'epub')
315
- app.add_config_value('epub_contributor', 'unknown', 'epub')
316
289
  app.add_config_value(
317
- 'epub_writing_mode', 'horizontal', 'epub', ENUM('horizontal', 'vertical')
290
+ 'epub_basename',
291
+ lambda self: make_filename(self.project),
292
+ '',
293
+ types=frozenset({str}),
294
+ )
295
+ app.add_config_value(
296
+ 'epub_version', 3.0, 'epub', types=frozenset({float})
297
+ ) # experimental
298
+ app.add_config_value('epub_theme', 'epub', 'epub', types=frozenset({str}))
299
+ app.add_config_value('epub_theme_options', {}, 'epub', types=frozenset({dict}))
300
+ app.add_config_value(
301
+ 'epub_title', lambda self: self.project, 'epub', types=frozenset({str})
302
+ )
303
+ app.add_config_value(
304
+ 'epub_author', lambda self: self.author, 'epub', types=frozenset({str})
305
+ )
306
+ app.add_config_value(
307
+ 'epub_language',
308
+ lambda self: self.language or 'en',
309
+ 'epub',
310
+ types=frozenset({str}),
311
+ )
312
+ app.add_config_value(
313
+ 'epub_publisher', lambda self: self.author, 'epub', types=frozenset({str})
314
+ )
315
+ app.add_config_value(
316
+ 'epub_copyright', lambda self: self.copyright, 'epub', types=frozenset({str})
317
+ )
318
+ app.add_config_value('epub_identifier', 'unknown', 'epub', types=frozenset({str}))
319
+ app.add_config_value('epub_scheme', 'unknown', 'epub', types=frozenset({str}))
320
+ app.add_config_value('epub_uid', 'unknown', 'env', types=frozenset({str}))
321
+ app.add_config_value('epub_cover', (), 'env', types=frozenset({list, tuple}))
322
+ app.add_config_value('epub_guide', (), 'env', types=frozenset({list, tuple}))
323
+ app.add_config_value('epub_pre_files', [], 'env', types=frozenset({list, tuple}))
324
+ app.add_config_value('epub_post_files', [], 'env', types=frozenset({list, tuple}))
325
+ app.add_config_value(
326
+ 'epub_css_files',
327
+ lambda config: config.html_css_files,
328
+ 'epub',
329
+ types=frozenset({list, tuple}),
330
+ )
331
+ app.add_config_value(
332
+ 'epub_exclude_files', [], 'env', types=frozenset({list, tuple})
333
+ )
334
+ app.add_config_value('epub_tocdepth', 3, 'env', types=frozenset({int}))
335
+ app.add_config_value('epub_tocdup', True, 'env', types=frozenset({bool}))
336
+ app.add_config_value('epub_tocscope', 'default', 'env', types=frozenset({str}))
337
+ app.add_config_value('epub_fix_images', False, 'env', types=frozenset({bool}))
338
+ app.add_config_value('epub_max_image_width', 0, 'env', types=frozenset({int}))
339
+ app.add_config_value('epub_show_urls', 'inline', 'epub', types=frozenset({str}))
340
+ app.add_config_value(
341
+ 'epub_use_index',
342
+ lambda self: self.html_use_index,
343
+ 'epub',
344
+ types=frozenset({bool}),
345
+ )
346
+ app.add_config_value('epub_description', 'unknown', 'epub', types=frozenset({str}))
347
+ app.add_config_value('epub_contributor', 'unknown', 'epub', types=frozenset({str}))
348
+ app.add_config_value(
349
+ 'epub_writing_mode', 'horizontal', 'epub', types=ENUM('horizontal', 'vertical')
318
350
  )
319
351
 
320
352
  # event handlers