Sphinx 8.0.1__py3-none-any.whl → 8.1.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.
- sphinx/__init__.py +6 -3
- sphinx/_cli/__init__.py +40 -20
- sphinx/_cli/util/colour.py +5 -4
- sphinx/_cli/util/errors.py +28 -11
- sphinx/application.py +361 -38
- sphinx/builders/__init__.py +229 -83
- sphinx/builders/_epub_base.py +118 -71
- sphinx/builders/changes.py +39 -21
- sphinx/builders/dirhtml.py +4 -4
- sphinx/builders/dummy.py +2 -5
- sphinx/builders/epub3.py +43 -22
- sphinx/builders/gettext.py +43 -25
- sphinx/builders/html/__init__.py +284 -218
- sphinx/builders/html/_assets.py +62 -26
- sphinx/builders/html/_build_info.py +76 -0
- sphinx/builders/html/transforms.py +11 -9
- sphinx/builders/latex/__init__.py +139 -81
- sphinx/builders/latex/constants.py +7 -7
- sphinx/builders/latex/nodes.py +3 -2
- sphinx/builders/latex/theming.py +7 -5
- sphinx/builders/latex/transforms.py +27 -19
- sphinx/builders/linkcheck.py +146 -72
- sphinx/builders/manpage.py +30 -13
- sphinx/builders/singlehtml.py +22 -14
- sphinx/builders/texinfo.py +67 -37
- sphinx/builders/text.py +5 -5
- sphinx/builders/xml.py +6 -9
- sphinx/cmd/build.py +282 -103
- sphinx/cmd/make_mode.py +106 -63
- sphinx/cmd/quickstart.py +341 -145
- sphinx/config.py +45 -12
- sphinx/deprecation.py +8 -2
- sphinx/directives/__init__.py +28 -19
- sphinx/directives/code.py +86 -56
- sphinx/directives/other.py +50 -36
- sphinx/directives/patches.py +29 -19
- sphinx/domains/__init__.py +20 -120
- sphinx/domains/_domains_container.py +281 -0
- sphinx/domains/_index.py +110 -0
- sphinx/domains/c/__init__.py +3 -3
- sphinx/domains/c/_parser.py +10 -6
- sphinx/domains/changeset.py +5 -3
- sphinx/domains/citation.py +5 -3
- sphinx/domains/cpp/__init__.py +9 -11
- sphinx/domains/cpp/_parser.py +8 -7
- sphinx/domains/index.py +3 -3
- sphinx/domains/javascript.py +12 -7
- sphinx/domains/math.py +2 -2
- sphinx/domains/python/__init__.py +10 -5
- sphinx/domains/python/_object.py +1 -1
- sphinx/domains/rst.py +5 -5
- sphinx/domains/std/__init__.py +16 -11
- sphinx/environment/__init__.py +206 -146
- sphinx/environment/adapters/asset.py +3 -2
- sphinx/environment/adapters/indexentries.py +74 -33
- sphinx/environment/adapters/toctree.py +100 -43
- sphinx/environment/collectors/__init__.py +19 -8
- sphinx/environment/collectors/asset.py +47 -15
- sphinx/environment/collectors/dependencies.py +8 -4
- sphinx/environment/collectors/metadata.py +7 -2
- sphinx/environment/collectors/title.py +7 -2
- sphinx/environment/collectors/toctree.py +54 -22
- sphinx/errors.py +4 -1
- sphinx/events.py +314 -7
- sphinx/ext/apidoc.py +42 -18
- sphinx/ext/autodoc/__init__.py +52 -24
- sphinx/ext/autodoc/importer.py +6 -9
- sphinx/ext/autosectionlabel.py +1 -2
- sphinx/ext/autosummary/__init__.py +3 -1
- sphinx/ext/autosummary/generate.py +28 -14
- sphinx/ext/coverage.py +7 -7
- sphinx/ext/doctest.py +4 -8
- sphinx/ext/duration.py +6 -5
- sphinx/ext/inheritance_diagram.py +1 -1
- sphinx/ext/intersphinx/_cli.py +6 -4
- sphinx/ext/intersphinx/_load.py +77 -32
- sphinx/ext/intersphinx/_resolve.py +173 -79
- sphinx/ext/intersphinx/_shared.py +7 -5
- sphinx/ext/linkcode.py +7 -1
- sphinx/ext/mathjax.py +1 -2
- sphinx/ext/napoleon/__init__.py +37 -24
- sphinx/ext/napoleon/docstring.py +202 -134
- sphinx/ext/todo.py +5 -3
- sphinx/highlighting.py +10 -3
- sphinx/io.py +1 -1
- sphinx/jinja2glue.py +27 -6
- sphinx/locale/__init__.py +6 -2
- sphinx/locale/ar/LC_MESSAGES/sphinx.js +8 -1
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2246 -2288
- sphinx/locale/bg/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/bn/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2349 -2395
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2846 -2892
- sphinx/locale/cak/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2213 -2259
- sphinx/locale/cs/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2225 -2269
- sphinx/locale/cy/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2403 -2447
- sphinx/locale/da/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2214 -2260
- sphinx/locale/de/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2230 -2276
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/el/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2619 -2665
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2519 -2565
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/eo/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2232 -2278
- sphinx/locale/es/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2516 -2561
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2114 -2159
- sphinx/locale/et/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2317 -2363
- sphinx/locale/eu/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2218 -2264
- sphinx/locale/fa/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +2505 -2551
- sphinx/locale/fi/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +2303 -2349
- sphinx/locale/fr/LC_MESSAGES/sphinx.js +6 -2
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +2863 -2908
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +2114 -2159
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2571 -2617
- sphinx/locale/he/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +2307 -2352
- sphinx/locale/hi/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +2580 -2626
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/hr/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +2238 -2283
- sphinx/locale/hu/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +2228 -2274
- sphinx/locale/id/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2787 -2834
- sphinx/locale/is/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +2224 -2270
- sphinx/locale/it/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2231 -2276
- sphinx/locale/ja/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2507 -2554
- sphinx/locale/ka/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2428 -2474
- sphinx/locale/ko/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2516 -2563
- sphinx/locale/lt/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2425 -2469
- sphinx/locale/lv/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2362 -2407
- sphinx/locale/mk/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2121 -2167
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2220 -2266
- sphinx/locale/ne/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2221 -2267
- sphinx/locale/nl/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2240 -2286
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2319 -2363
- sphinx/locale/pt/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2114 -2159
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2854 -2899
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2224 -2269
- sphinx/locale/ro/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2226 -2271
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +8 -3
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +2841 -2885
- sphinx/locale/si/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2294 -2340
- sphinx/locale/sk/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2497 -2541
- sphinx/locale/sl/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2331 -2375
- sphinx/locale/sphinx.pot +2121 -2167
- sphinx/locale/sq/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2855 -2901
- sphinx/locale/sr/LC_MESSAGES/sphinx.js +5 -1
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2203 -2248
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2423 -2469
- sphinx/locale/te/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/tr/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2443 -2489
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js +6 -1
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2329 -2373
- sphinx/locale/ur/LC_MESSAGES/sphinx.js +4 -1
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2113 -2159
- sphinx/locale/vi/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2199 -2246
- sphinx/locale/yue/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2112 -2159
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2112 -2159
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2845 -2892
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.js +3 -1
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2112 -2159
- sphinx/parsers.py +3 -1
- sphinx/project.py +6 -2
- sphinx/pycode/__init__.py +11 -4
- sphinx/pycode/ast.py +58 -58
- sphinx/pycode/parser.py +49 -28
- sphinx/pygments_styles.py +49 -49
- sphinx/registry.py +8 -3
- sphinx/roles.py +133 -13
- sphinx/search/__init__.py +146 -87
- sphinx/search/da.py +2 -4
- sphinx/search/de.py +2 -4
- sphinx/search/en.py +4 -4
- sphinx/search/es.py +2 -4
- sphinx/search/fi.py +2 -4
- sphinx/search/fr.py +2 -4
- sphinx/search/hu.py +2 -4
- sphinx/search/it.py +2 -4
- sphinx/search/ja.py +55 -32
- sphinx/search/nl.py +2 -4
- sphinx/search/no.py +2 -4
- sphinx/search/pt.py +2 -4
- sphinx/search/ro.py +0 -2
- sphinx/search/ru.py +2 -4
- sphinx/search/sv.py +2 -4
- sphinx/search/tr.py +0 -2
- sphinx/search/zh.py +18 -13
- sphinx/templates/graphviz/graphviz.css +0 -7
- sphinx/testing/fixtures.py +6 -5
- sphinx/testing/path.py +7 -5
- sphinx/testing/util.py +63 -29
- sphinx/texinputs/sphinx.sty +107 -39
- sphinx/texinputs/sphinxlatexadmonitions.sty +51 -35
- sphinx/texinputs/sphinxlatexcontainers.sty +1 -1
- sphinx/texinputs/sphinxlatexgraphics.sty +3 -2
- sphinx/texinputs/sphinxlatexindbibtoc.sty +1 -1
- sphinx/texinputs/sphinxlatexlists.sty +1 -1
- sphinx/texinputs/sphinxlatexliterals.sty +4 -1
- sphinx/texinputs/sphinxlatexnumfig.sty +22 -9
- sphinx/texinputs/sphinxlatexobjects.sty +1 -1
- sphinx/texinputs/sphinxlatexshadowbox.sty +72 -10
- sphinx/texinputs/sphinxlatexstyleheadings.sty +7 -2
- sphinx/texinputs/sphinxlatexstylepage.sty +2 -8
- sphinx/texinputs/sphinxlatexstyletext.sty +2 -4
- sphinx/texinputs/sphinxlatextables.sty +1 -1
- sphinx/texinputs/sphinxoptionsgeometry.sty +1 -1
- sphinx/texinputs/sphinxoptionshyperref.sty +1 -1
- sphinx/themes/agogo/layout.html +1 -10
- sphinx/themes/agogo/static/agogo.css.jinja +0 -7
- sphinx/themes/basic/defindex.html +1 -8
- sphinx/themes/basic/domainindex.html +1 -9
- sphinx/themes/basic/genindex-single.html +1 -9
- sphinx/themes/basic/genindex-split.html +1 -9
- sphinx/themes/basic/genindex.html +1 -9
- sphinx/themes/basic/globaltoc.html +1 -9
- sphinx/themes/basic/layout.html +1 -9
- sphinx/themes/basic/localtoc.html +1 -9
- sphinx/themes/basic/page.html +1 -9
- sphinx/themes/basic/relations.html +1 -9
- sphinx/themes/basic/search.html +1 -9
- sphinx/themes/basic/searchbox.html +1 -9
- sphinx/themes/basic/searchfield.html +4 -10
- sphinx/themes/basic/sourcelink.html +1 -9
- sphinx/themes/basic/static/basic.css.jinja +2 -13
- sphinx/themes/basic/static/doctools.js +0 -7
- sphinx/themes/basic/static/language_data.js.jinja +0 -7
- sphinx/themes/basic/static/searchtools.js +25 -13
- sphinx/themes/bizstyle/layout.html +1 -9
- sphinx/themes/bizstyle/static/bizstyle.css.jinja +0 -7
- sphinx/themes/bizstyle/static/bizstyle.js.jinja +5 -11
- sphinx/themes/classic/layout.html +1 -9
- sphinx/themes/classic/static/classic.css.jinja +0 -7
- sphinx/themes/classic/static/sidebar.js.jinja +0 -6
- sphinx/themes/epub/epub-cover.html +1 -9
- sphinx/themes/epub/layout.html +1 -9
- sphinx/themes/epub/static/epub.css.jinja +0 -7
- sphinx/themes/haiku/layout.html +1 -9
- sphinx/themes/haiku/static/haiku.css.jinja +0 -6
- sphinx/themes/nature/static/nature.css.jinja +0 -7
- sphinx/themes/nonav/layout.html +1 -9
- sphinx/themes/nonav/static/nonav.css.jinja +0 -7
- sphinx/themes/pyramid/static/epub.css.jinja +0 -7
- sphinx/themes/pyramid/static/pyramid.css.jinja +0 -7
- sphinx/themes/scrolls/layout.html +1 -10
- sphinx/themes/scrolls/static/scrolls.css.jinja +0 -7
- sphinx/themes/sphinxdoc/static/sphinxdoc.css.jinja +2 -7
- sphinx/themes/traditional/static/traditional.css.jinja +0 -7
- sphinx/theming.py +18 -6
- sphinx/transforms/__init__.py +56 -35
- sphinx/transforms/compact_bullet_list.py +3 -2
- sphinx/transforms/i18n.py +132 -50
- sphinx/transforms/post_transforms/__init__.py +94 -43
- sphinx/transforms/post_transforms/code.py +7 -6
- sphinx/transforms/post_transforms/images.py +71 -54
- sphinx/transforms/references.py +1 -2
- sphinx/util/__init__.py +23 -194
- sphinx/util/_files.py +80 -0
- sphinx/util/_importer.py +27 -0
- sphinx/util/_io.py +1 -2
- sphinx/util/_lines.py +26 -0
- sphinx/util/_pathlib.py +5 -2
- sphinx/util/_serialise.py +53 -0
- sphinx/util/_timestamps.py +2 -1
- sphinx/util/_uri.py +16 -0
- sphinx/util/cfamily.py +48 -25
- sphinx/util/console.py +1 -0
- sphinx/util/display.py +1 -1
- sphinx/util/docfields.py +125 -45
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -44
- sphinx/util/exceptions.py +11 -5
- sphinx/util/fileutil.py +53 -32
- sphinx/util/http_date.py +9 -7
- sphinx/util/i18n.py +49 -16
- sphinx/util/images.py +7 -6
- sphinx/util/inspect.py +29 -12
- sphinx/util/inventory.py +47 -29
- sphinx/util/logging.py +58 -85
- sphinx/util/matching.py +3 -3
- sphinx/util/math.py +1 -1
- sphinx/util/nodes.py +176 -108
- sphinx/util/osutil.py +13 -10
- sphinx/util/parallel.py +5 -4
- sphinx/util/parsing.py +5 -3
- sphinx/util/png.py +3 -3
- sphinx/util/requests.py +8 -4
- sphinx/util/rst.py +5 -3
- sphinx/util/tags.py +5 -2
- sphinx/util/template.py +26 -11
- sphinx/util/texescape.py +2 -2
- sphinx/util/typing.py +89 -38
- sphinx/versioning.py +3 -1
- sphinx/writers/html.py +22 -7
- sphinx/writers/html5.py +113 -64
- sphinx/writers/latex.py +408 -221
- sphinx/writers/manpage.py +25 -15
- sphinx/writers/texinfo.py +94 -82
- sphinx/writers/text.py +87 -53
- sphinx/writers/xml.py +5 -4
- sphinx-8.1.0.dist-info/LICENSE.rst +31 -0
- {sphinx-8.0.1.dist-info → sphinx-8.1.0.dist-info}/METADATA +13 -11
- sphinx-8.1.0.dist-info/RECORD +598 -0
- sphinx-8.0.1.dist-info/LICENSE.rst +0 -67
- sphinx-8.0.1.dist-info/RECORD +0 -590
- {sphinx-8.0.1.dist-info → sphinx-8.1.0.dist-info}/WHEEL +0 -0
- {sphinx-8.0.1.dist-info → sphinx-8.1.0.dist-info}/entry_points.txt +0 -0
sphinx/builders/html/__init__.py
CHANGED
|
@@ -3,17 +3,16 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import contextlib
|
|
6
|
-
import hashlib
|
|
7
6
|
import html
|
|
8
7
|
import os
|
|
9
8
|
import posixpath
|
|
10
9
|
import re
|
|
10
|
+
import shutil
|
|
11
11
|
import sys
|
|
12
|
-
import types
|
|
13
12
|
import warnings
|
|
14
13
|
from os import path
|
|
15
14
|
from pathlib import Path
|
|
16
|
-
from typing import
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
17
16
|
from urllib.parse import quote
|
|
18
17
|
|
|
19
18
|
import docutils.readers.doctree
|
|
@@ -26,10 +25,15 @@ from docutils.utils import relative_path
|
|
|
26
25
|
from sphinx import __display_version__, package_dir
|
|
27
26
|
from sphinx import version_info as sphinx_version
|
|
28
27
|
from sphinx.builders import Builder
|
|
29
|
-
from sphinx.builders.html._assets import
|
|
28
|
+
from sphinx.builders.html._assets import (
|
|
29
|
+
_CascadingStyleSheet,
|
|
30
|
+
_file_checksum,
|
|
31
|
+
_JavaScript,
|
|
32
|
+
)
|
|
33
|
+
from sphinx.builders.html._build_info import BuildInfo
|
|
30
34
|
from sphinx.config import ENUM, Config
|
|
31
35
|
from sphinx.deprecation import _deprecation_warning
|
|
32
|
-
from sphinx.domains import
|
|
36
|
+
from sphinx.domains import Index, IndexEntry
|
|
33
37
|
from sphinx.environment.adapters.asset import ImageAdapter
|
|
34
38
|
from sphinx.environment.adapters.indexentries import IndexEntries
|
|
35
39
|
from sphinx.environment.adapters.toctree import document_toc, global_toctree_for_doc
|
|
@@ -38,8 +42,10 @@ from sphinx.highlighting import PygmentsBridge
|
|
|
38
42
|
from sphinx.locale import _, __
|
|
39
43
|
from sphinx.search import js_index
|
|
40
44
|
from sphinx.theming import HTMLThemeFactory
|
|
41
|
-
from sphinx.util import
|
|
45
|
+
from sphinx.util import logging
|
|
42
46
|
from sphinx.util._timestamps import _format_rfc3339_microseconds
|
|
47
|
+
from sphinx.util._uri import is_url
|
|
48
|
+
from sphinx.util.console import bold
|
|
43
49
|
from sphinx.util.display import progress_message, status_iterator
|
|
44
50
|
from sphinx.util.docutils import new_document
|
|
45
51
|
from sphinx.util.fileutil import copy_asset
|
|
@@ -58,16 +64,14 @@ from sphinx.writers.html import HTMLWriter
|
|
|
58
64
|
from sphinx.writers.html5 import HTML5Translator
|
|
59
65
|
|
|
60
66
|
if TYPE_CHECKING:
|
|
61
|
-
from collections.abc import
|
|
67
|
+
from collections.abc import Iterator, Set
|
|
62
68
|
from typing import TypeAlias
|
|
63
69
|
|
|
64
70
|
from docutils.nodes import Node
|
|
65
71
|
from docutils.readers import Reader
|
|
66
72
|
|
|
67
73
|
from sphinx.application import Sphinx
|
|
68
|
-
from sphinx.config import _ConfigRebuild
|
|
69
74
|
from sphinx.environment import BuildEnvironment
|
|
70
|
-
from sphinx.util.tags import Tags
|
|
71
75
|
from sphinx.util.typing import ExtensionMetadata
|
|
72
76
|
|
|
73
77
|
#: the filename for the inventory of objects
|
|
@@ -88,23 +92,6 @@ DOMAIN_INDEX_TYPE: TypeAlias = tuple[
|
|
|
88
92
|
]
|
|
89
93
|
|
|
90
94
|
|
|
91
|
-
def _stable_hash(obj: Any) -> str:
|
|
92
|
-
"""Return a stable hash for a Python data structure.
|
|
93
|
-
|
|
94
|
-
We can't just use the md5 of str(obj) as the order of collections
|
|
95
|
-
may be random.
|
|
96
|
-
"""
|
|
97
|
-
if isinstance(obj, dict):
|
|
98
|
-
obj = sorted(map(_stable_hash, obj.items()))
|
|
99
|
-
if isinstance(obj, list | tuple | set | frozenset):
|
|
100
|
-
obj = sorted(map(_stable_hash, obj))
|
|
101
|
-
elif isinstance(obj, type | types.FunctionType):
|
|
102
|
-
# The default repr() of functions includes the ID, which is not ideal.
|
|
103
|
-
# We use the fully qualified name instead.
|
|
104
|
-
obj = f'{obj.__module__}.{obj.__qualname__}'
|
|
105
|
-
return hashlib.md5(str(obj).encode(), usedforsecurity=False).hexdigest()
|
|
106
|
-
|
|
107
|
-
|
|
108
95
|
def convert_locale_to_language_tag(locale: str | None) -> str | None:
|
|
109
96
|
"""Convert a locale string to a language tag (ex. en_US -> en-US).
|
|
110
97
|
|
|
@@ -116,57 +103,6 @@ def convert_locale_to_language_tag(locale: str | None) -> str | None:
|
|
|
116
103
|
return None
|
|
117
104
|
|
|
118
105
|
|
|
119
|
-
class BuildInfo:
|
|
120
|
-
"""buildinfo file manipulator.
|
|
121
|
-
|
|
122
|
-
HTMLBuilder and its family are storing their own envdata to ``.buildinfo``.
|
|
123
|
-
This class is a manipulator for the file.
|
|
124
|
-
"""
|
|
125
|
-
|
|
126
|
-
@classmethod
|
|
127
|
-
def load(cls: type[BuildInfo], f: IO[str]) -> BuildInfo:
|
|
128
|
-
try:
|
|
129
|
-
lines = f.readlines()
|
|
130
|
-
assert lines[0].rstrip() == '# Sphinx build info version 1'
|
|
131
|
-
assert lines[2].startswith('config: ')
|
|
132
|
-
assert lines[3].startswith('tags: ')
|
|
133
|
-
|
|
134
|
-
build_info = BuildInfo()
|
|
135
|
-
build_info.config_hash = lines[2].split()[1].strip()
|
|
136
|
-
build_info.tags_hash = lines[3].split()[1].strip()
|
|
137
|
-
return build_info
|
|
138
|
-
except Exception as exc:
|
|
139
|
-
raise ValueError(__('build info file is broken: %r') % exc) from exc
|
|
140
|
-
|
|
141
|
-
def __init__(
|
|
142
|
-
self,
|
|
143
|
-
config: Config | None = None,
|
|
144
|
-
tags: Tags | None = None,
|
|
145
|
-
config_categories: Set[_ConfigRebuild] = frozenset(),
|
|
146
|
-
) -> None:
|
|
147
|
-
self.config_hash = ''
|
|
148
|
-
self.tags_hash = ''
|
|
149
|
-
|
|
150
|
-
if config:
|
|
151
|
-
values = {c.name: c.value for c in config.filter(config_categories)}
|
|
152
|
-
self.config_hash = _stable_hash(values)
|
|
153
|
-
|
|
154
|
-
if tags:
|
|
155
|
-
self.tags_hash = _stable_hash(sorted(tags))
|
|
156
|
-
|
|
157
|
-
def __eq__(self, other: BuildInfo) -> bool: # type: ignore[override]
|
|
158
|
-
return (self.config_hash == other.config_hash and
|
|
159
|
-
self.tags_hash == other.tags_hash)
|
|
160
|
-
|
|
161
|
-
def dump(self, f: IO[str]) -> None:
|
|
162
|
-
f.write('# Sphinx build info version 1\n'
|
|
163
|
-
'# This file hashes the configuration used when building these files.'
|
|
164
|
-
' When it is not found, a full rebuild will be done.\n'
|
|
165
|
-
'config: %s\n'
|
|
166
|
-
'tags: %s\n' %
|
|
167
|
-
(self.config_hash, self.tags_hash))
|
|
168
|
-
|
|
169
|
-
|
|
170
106
|
class StandaloneHTMLBuilder(Builder):
|
|
171
107
|
"""
|
|
172
108
|
Builds standalone HTML docs.
|
|
@@ -185,8 +121,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
185
121
|
indexer_dumps_unicode = True
|
|
186
122
|
# create links to original images from images [True/False]
|
|
187
123
|
html_scaled_image_link = True
|
|
188
|
-
supported_image_types = ['image/svg+xml', 'image/png',
|
|
189
|
-
'image/gif', 'image/jpeg']
|
|
124
|
+
supported_image_types = ['image/svg+xml', 'image/png', 'image/gif', 'image/jpeg']
|
|
190
125
|
supported_remote_images = True
|
|
191
126
|
supported_data_uri_images = True
|
|
192
127
|
searchindex_filename = 'searchindex.js'
|
|
@@ -253,13 +188,17 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
253
188
|
return BuildInfo(self.config, self.tags, frozenset({'html'}))
|
|
254
189
|
|
|
255
190
|
def _get_translations_js(self) -> str:
|
|
256
|
-
candidates = [
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
191
|
+
candidates = [
|
|
192
|
+
path.join(dir, self.config.language, 'LC_MESSAGES', 'sphinx.js')
|
|
193
|
+
for dir in self.config.locale_dirs
|
|
194
|
+
] + [
|
|
195
|
+
path.join(
|
|
196
|
+
package_dir, 'locale', self.config.language, 'LC_MESSAGES', 'sphinx.js'
|
|
197
|
+
),
|
|
198
|
+
path.join(
|
|
199
|
+
sys.prefix, 'share/sphinx/locale', self.config.language, 'sphinx.js'
|
|
200
|
+
),
|
|
201
|
+
]
|
|
263
202
|
|
|
264
203
|
for jsfile in candidates:
|
|
265
204
|
if path.isfile(jsfile):
|
|
@@ -307,15 +246,19 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
307
246
|
self.dark_highlighter: PygmentsBridge | None
|
|
308
247
|
if dark_style is not None:
|
|
309
248
|
self.dark_highlighter = PygmentsBridge('html', dark_style)
|
|
310
|
-
self.app.add_css_file(
|
|
311
|
-
|
|
312
|
-
|
|
249
|
+
self.app.add_css_file(
|
|
250
|
+
'pygments_dark.css',
|
|
251
|
+
media='(prefers-color-scheme: dark)',
|
|
252
|
+
id='pygments_dark_css',
|
|
253
|
+
)
|
|
313
254
|
else:
|
|
314
255
|
self.dark_highlighter = None
|
|
315
256
|
|
|
316
257
|
@property
|
|
317
258
|
def css_files(self) -> list[_CascadingStyleSheet]:
|
|
318
|
-
_deprecation_warning(
|
|
259
|
+
_deprecation_warning(
|
|
260
|
+
__name__, f'{self.__class__.__name__}.css_files', remove=(9, 0)
|
|
261
|
+
)
|
|
319
262
|
return self._css_files
|
|
320
263
|
|
|
321
264
|
def init_css_files(self) -> None:
|
|
@@ -329,7 +272,8 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
329
272
|
self.add_css_file(filename, **attrs)
|
|
330
273
|
|
|
331
274
|
for filename, attrs in self.get_builder_config('css_files', 'html'):
|
|
332
|
-
|
|
275
|
+
# User's CSSs are loaded after extensions'
|
|
276
|
+
attrs.setdefault('priority', 800)
|
|
333
277
|
self.add_css_file(filename, **attrs)
|
|
334
278
|
|
|
335
279
|
def add_css_file(self, filename: str, **kwargs: Any) -> None:
|
|
@@ -389,22 +333,50 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
389
333
|
return None
|
|
390
334
|
|
|
391
335
|
def get_outdated_docs(self) -> Iterator[str]:
|
|
336
|
+
build_info_fname = self.outdir / '.buildinfo'
|
|
392
337
|
try:
|
|
393
|
-
|
|
394
|
-
buildinfo = BuildInfo.load(fp)
|
|
395
|
-
|
|
396
|
-
if self.build_info != buildinfo:
|
|
397
|
-
logger.debug('[build target] did not match: build_info ')
|
|
398
|
-
yield from self.env.found_docs
|
|
399
|
-
return
|
|
338
|
+
build_info = BuildInfo.load(build_info_fname)
|
|
400
339
|
except ValueError as exc:
|
|
401
340
|
logger.warning(__('Failed to read build info file: %r'), exc)
|
|
402
341
|
except OSError:
|
|
403
342
|
# ignore errors on reading
|
|
404
343
|
pass
|
|
344
|
+
else:
|
|
345
|
+
if self.build_info != build_info:
|
|
346
|
+
# log the mismatch and backup the old build info
|
|
347
|
+
build_info_backup = build_info_fname.with_name('.buildinfo.bak')
|
|
348
|
+
try:
|
|
349
|
+
shutil.move(build_info_fname, build_info_backup)
|
|
350
|
+
self.build_info.dump(build_info_fname)
|
|
351
|
+
except OSError:
|
|
352
|
+
pass # ignore errors
|
|
353
|
+
else:
|
|
354
|
+
# only log on success
|
|
355
|
+
msg = __(
|
|
356
|
+
'build_info mismatch, copying .buildinfo to .buildinfo.bak'
|
|
357
|
+
)
|
|
358
|
+
logger.info(bold(__('building [html]: ')) + msg)
|
|
359
|
+
|
|
360
|
+
yield from self.env.found_docs
|
|
361
|
+
return
|
|
405
362
|
|
|
406
363
|
if self.templates:
|
|
407
364
|
template_mtime = int(self.templates.newest_template_mtime() * 10**6)
|
|
365
|
+
try:
|
|
366
|
+
old_mtime = _last_modified_time(build_info_fname)
|
|
367
|
+
except Exception:
|
|
368
|
+
pass
|
|
369
|
+
else:
|
|
370
|
+
# Let users know they have a newer template
|
|
371
|
+
if template_mtime > old_mtime:
|
|
372
|
+
logger.info(
|
|
373
|
+
bold('building [html]: ')
|
|
374
|
+
+ __(
|
|
375
|
+
'template %s has been changed since the previous build, '
|
|
376
|
+
'all docs will be rebuilt'
|
|
377
|
+
),
|
|
378
|
+
self.templates.newest_template_name(),
|
|
379
|
+
)
|
|
408
380
|
else:
|
|
409
381
|
template_mtime = 0
|
|
410
382
|
for docname in self.env.found_docs:
|
|
@@ -418,7 +390,8 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
418
390
|
except Exception:
|
|
419
391
|
targetmtime = 0
|
|
420
392
|
try:
|
|
421
|
-
|
|
393
|
+
doc_mtime = _last_modified_time(self.env.doc2path(docname))
|
|
394
|
+
srcmtime = max(doc_mtime, template_mtime)
|
|
422
395
|
if srcmtime > targetmtime:
|
|
423
396
|
logger.debug(
|
|
424
397
|
'[build target] targetname %r(%s), template(%s), docname %r(%s)',
|
|
@@ -426,7 +399,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
426
399
|
_format_rfc3339_microseconds(targetmtime),
|
|
427
400
|
_format_rfc3339_microseconds(template_mtime),
|
|
428
401
|
docname,
|
|
429
|
-
_format_rfc3339_microseconds(
|
|
402
|
+
_format_rfc3339_microseconds(doc_mtime),
|
|
430
403
|
)
|
|
431
404
|
yield docname
|
|
432
405
|
except OSError:
|
|
@@ -447,15 +420,19 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
447
420
|
self._publisher.publish()
|
|
448
421
|
return self._publisher.writer.parts
|
|
449
422
|
|
|
450
|
-
def prepare_writing(self, docnames:
|
|
423
|
+
def prepare_writing(self, docnames: Set[str]) -> None:
|
|
451
424
|
# create the search indexer
|
|
452
425
|
self.indexer = None
|
|
453
426
|
if self.search:
|
|
454
427
|
from sphinx.search import IndexBuilder
|
|
428
|
+
|
|
455
429
|
lang = self.config.html_search_language or self.config.language
|
|
456
|
-
self.indexer = IndexBuilder(
|
|
457
|
-
|
|
458
|
-
|
|
430
|
+
self.indexer = IndexBuilder(
|
|
431
|
+
self.env,
|
|
432
|
+
lang,
|
|
433
|
+
self.config.html_search_options,
|
|
434
|
+
self.config.html_search_scorer,
|
|
435
|
+
)
|
|
459
436
|
self.load_indexer(docnames)
|
|
460
437
|
|
|
461
438
|
self.docwriter = HTMLWriter(self)
|
|
@@ -466,7 +443,8 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
466
443
|
self.docsettings: Any = OptionParser(
|
|
467
444
|
defaults=self.env.settings,
|
|
468
445
|
components=(self.docwriter,),
|
|
469
|
-
read_config_files=True
|
|
446
|
+
read_config_files=True,
|
|
447
|
+
).get_default_values()
|
|
470
448
|
self.docsettings.compact_lists = bool(self.config.html_compact_lists)
|
|
471
449
|
|
|
472
450
|
# determine the additional indices to include
|
|
@@ -478,23 +456,29 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
478
456
|
indices_config = frozenset(indices_config)
|
|
479
457
|
else:
|
|
480
458
|
check_names = False
|
|
481
|
-
for
|
|
482
|
-
domain: Domain = self.env.domains[domain_name]
|
|
459
|
+
for domain in self.env.domains.sorted():
|
|
483
460
|
for index_cls in domain.indices:
|
|
484
461
|
index_name = f'{domain.name}-{index_cls.name}'
|
|
485
462
|
if check_names and index_name not in indices_config:
|
|
486
463
|
continue
|
|
487
464
|
content, collapse = index_cls(domain).generate()
|
|
488
465
|
if content:
|
|
489
|
-
self.domain_indices.append(
|
|
490
|
-
|
|
466
|
+
self.domain_indices.append((
|
|
467
|
+
index_name,
|
|
468
|
+
index_cls,
|
|
469
|
+
content,
|
|
470
|
+
collapse,
|
|
471
|
+
))
|
|
491
472
|
|
|
492
473
|
# format the "last updated on" string, only once is enough since it
|
|
493
474
|
# typically doesn't include the time of day
|
|
494
475
|
last_updated: str | None
|
|
495
476
|
if (lu_fmt := self.config.html_last_updated_fmt) is not None:
|
|
496
|
-
|
|
497
|
-
|
|
477
|
+
last_updated = format_date(
|
|
478
|
+
lu_fmt or _('%b %d, %Y'),
|
|
479
|
+
language=self.config.language,
|
|
480
|
+
local_time=not self.config.html_last_updated_use_utc,
|
|
481
|
+
)
|
|
498
482
|
else:
|
|
499
483
|
last_updated = None
|
|
500
484
|
|
|
@@ -503,9 +487,9 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
503
487
|
logo = self.config.html_logo or ''
|
|
504
488
|
favicon = self.config.html_favicon or ''
|
|
505
489
|
|
|
506
|
-
if not
|
|
490
|
+
if not is_url(logo):
|
|
507
491
|
logo = path.basename(logo)
|
|
508
|
-
if not
|
|
492
|
+
if not is_url(favicon):
|
|
509
493
|
favicon = path.basename(favicon)
|
|
510
494
|
|
|
511
495
|
self.relations = self.env.collect_relations()
|
|
@@ -516,8 +500,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
516
500
|
for indexname, indexcls, _content, _collapse in self.domain_indices:
|
|
517
501
|
# if it has a short name
|
|
518
502
|
if indexcls.shortname:
|
|
519
|
-
rellinks.append((indexname, indexcls.localname,
|
|
520
|
-
'', indexcls.shortname))
|
|
503
|
+
rellinks.append((indexname, indexcls.localname, '', indexcls.shortname))
|
|
521
504
|
|
|
522
505
|
# add assets registered after ``Builder.init()``.
|
|
523
506
|
for css_filename, attrs in self.app.registry.css_files:
|
|
@@ -567,8 +550,8 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
567
550
|
}
|
|
568
551
|
if self.theme:
|
|
569
552
|
self.globalcontext |= {
|
|
570
|
-
f'theme_{key}': val
|
|
571
|
-
self.theme.get_options(self.theme_options).items()
|
|
553
|
+
f'theme_{key}': val
|
|
554
|
+
for key, val in self.theme.get_options(self.theme_options).items()
|
|
572
555
|
}
|
|
573
556
|
self.globalcontext |= self.config.html_context
|
|
574
557
|
|
|
@@ -602,9 +585,10 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
602
585
|
prev = None
|
|
603
586
|
while related and related[0]:
|
|
604
587
|
with contextlib.suppress(KeyError):
|
|
605
|
-
parents.append(
|
|
606
|
-
|
|
607
|
-
|
|
588
|
+
parents.append({
|
|
589
|
+
'link': self.get_relative_uri(docname, related[0]),
|
|
590
|
+
'title': self.render_partial(titles[related[0]])['title'],
|
|
591
|
+
})
|
|
608
592
|
|
|
609
593
|
related = self.relations.get(related[0])
|
|
610
594
|
if parents:
|
|
@@ -618,7 +602,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
618
602
|
title = self.render_partial(title_node)['title'] if title_node else ''
|
|
619
603
|
|
|
620
604
|
# Suffix for the document
|
|
621
|
-
source_suffix = str(self.env.doc2path(docname, False))[len(docname):]
|
|
605
|
+
source_suffix = str(self.env.doc2path(docname, False))[len(docname) :]
|
|
622
606
|
|
|
623
607
|
# the name for the copied source
|
|
624
608
|
if self.config.html_copy_source:
|
|
@@ -728,8 +712,10 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
728
712
|
# the total count of lines for each index letter, used to distribute
|
|
729
713
|
# the entries into two columns
|
|
730
714
|
genindex = IndexEntries(self.env).create_index(self)
|
|
731
|
-
indexcounts = [
|
|
732
|
-
|
|
715
|
+
indexcounts = [
|
|
716
|
+
sum(1 + len(subitems) for _, (_, subitems, _) in entries)
|
|
717
|
+
for _k, entries in genindex
|
|
718
|
+
]
|
|
733
719
|
|
|
734
720
|
genindexcontext = {
|
|
735
721
|
'genindexentries': genindex,
|
|
@@ -739,15 +725,16 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
739
725
|
logger.info('genindex ', nonl=True)
|
|
740
726
|
|
|
741
727
|
if self.config.html_split_index:
|
|
742
|
-
self.handle_page('genindex', genindexcontext,
|
|
743
|
-
|
|
744
|
-
self.handle_page('genindex-all', genindexcontext,
|
|
745
|
-
'genindex.html')
|
|
728
|
+
self.handle_page('genindex', genindexcontext, 'genindex-split.html')
|
|
729
|
+
self.handle_page('genindex-all', genindexcontext, 'genindex.html')
|
|
746
730
|
for (key, entries), count in zip(genindex, indexcounts, strict=True):
|
|
747
|
-
ctx = {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
731
|
+
ctx = {
|
|
732
|
+
'key': key,
|
|
733
|
+
'entries': entries,
|
|
734
|
+
'count': count,
|
|
735
|
+
'genindexentries': genindex,
|
|
736
|
+
}
|
|
737
|
+
self.handle_page('genindex-' + key, ctx, 'genindex-single.html')
|
|
751
738
|
else:
|
|
752
739
|
self.handle_page('genindex', genindexcontext, 'genindex.html')
|
|
753
740
|
|
|
@@ -765,9 +752,14 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
765
752
|
if self.images:
|
|
766
753
|
stringify_func = ImageAdapter(self.app.env).get_original_image_uri
|
|
767
754
|
ensuredir(self.outdir / self.imagedir)
|
|
768
|
-
for src in status_iterator(
|
|
769
|
-
|
|
770
|
-
|
|
755
|
+
for src in status_iterator(
|
|
756
|
+
self.images,
|
|
757
|
+
__('copying images... '),
|
|
758
|
+
'brown',
|
|
759
|
+
len(self.images),
|
|
760
|
+
self.app.verbosity,
|
|
761
|
+
stringify_func=stringify_func,
|
|
762
|
+
):
|
|
771
763
|
dest = self.images[src]
|
|
772
764
|
try:
|
|
773
765
|
copyfile(
|
|
@@ -776,8 +768,9 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
776
768
|
force=True,
|
|
777
769
|
)
|
|
778
770
|
except Exception as err:
|
|
779
|
-
logger.warning(
|
|
780
|
-
|
|
771
|
+
logger.warning(
|
|
772
|
+
__("cannot copy image file '%s': %s"), self.srcdir / src, err
|
|
773
|
+
)
|
|
781
774
|
|
|
782
775
|
def copy_download_files(self) -> None:
|
|
783
776
|
def to_relpath(f: str) -> str:
|
|
@@ -786,26 +779,34 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
786
779
|
# copy downloadable files
|
|
787
780
|
if self.env.dlfiles:
|
|
788
781
|
ensuredir(self.outdir / '_downloads')
|
|
789
|
-
for src in status_iterator(
|
|
790
|
-
|
|
791
|
-
|
|
782
|
+
for src in status_iterator(
|
|
783
|
+
self.env.dlfiles,
|
|
784
|
+
__('copying downloadable files... '),
|
|
785
|
+
'brown',
|
|
786
|
+
len(self.env.dlfiles),
|
|
787
|
+
self.app.verbosity,
|
|
788
|
+
stringify_func=to_relpath,
|
|
789
|
+
):
|
|
792
790
|
try:
|
|
793
791
|
dest = self.outdir / '_downloads' / self.env.dlfiles[src][1]
|
|
794
792
|
ensuredir(dest.parent)
|
|
795
793
|
copyfile(self.srcdir / src, dest, force=True)
|
|
796
794
|
except OSError as err:
|
|
797
|
-
logger.warning(
|
|
798
|
-
|
|
795
|
+
logger.warning(
|
|
796
|
+
__('cannot copy downloadable file %r: %s'),
|
|
797
|
+
self.srcdir / src,
|
|
798
|
+
err,
|
|
799
|
+
)
|
|
799
800
|
|
|
800
801
|
def create_pygments_style_file(self) -> None:
|
|
801
802
|
"""Create a style file for pygments."""
|
|
802
|
-
|
|
803
|
-
|
|
803
|
+
pyg_path = path.join(self.outdir, '_static', 'pygments.css')
|
|
804
|
+
with open(pyg_path, 'w', encoding='utf-8') as f:
|
|
804
805
|
f.write(self.highlighter.get_stylesheet())
|
|
805
806
|
|
|
806
807
|
if self.dark_highlighter:
|
|
807
|
-
|
|
808
|
-
|
|
808
|
+
dark_path = path.join(self.outdir, '_static', 'pygments_dark.css')
|
|
809
|
+
with open(dark_path, 'w', encoding='utf-8') as f:
|
|
809
810
|
f.write(self.dark_highlighter.get_stylesheet())
|
|
810
811
|
|
|
811
812
|
def copy_translation_js(self) -> None:
|
|
@@ -847,28 +848,33 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
847
848
|
copy_asset(
|
|
848
849
|
Path(entry) / 'static',
|
|
849
850
|
self.outdir / '_static',
|
|
850
|
-
excluded=DOTFILES,
|
|
851
|
-
|
|
851
|
+
excluded=DOTFILES,
|
|
852
|
+
context=context,
|
|
853
|
+
renderer=self.templates,
|
|
854
|
+
onerror=onerror,
|
|
852
855
|
force=True,
|
|
853
856
|
)
|
|
854
857
|
|
|
855
858
|
def copy_html_static_files(self, context: dict[str, Any]) -> None:
|
|
856
859
|
def onerror(filename: str, error: Exception) -> None:
|
|
857
|
-
logger.warning(
|
|
858
|
-
|
|
860
|
+
logger.warning(
|
|
861
|
+
__('Failed to copy a file in html_static_file: %s: %r'), filename, error
|
|
862
|
+
)
|
|
859
863
|
|
|
860
864
|
excluded = Matcher([*self.config.exclude_patterns, '**/.*'])
|
|
861
865
|
for entry in self.config.html_static_path:
|
|
862
866
|
copy_asset(
|
|
863
867
|
self.confdir / entry,
|
|
864
868
|
self.outdir / '_static',
|
|
865
|
-
excluded=excluded,
|
|
866
|
-
|
|
869
|
+
excluded=excluded,
|
|
870
|
+
context=context,
|
|
871
|
+
renderer=self.templates,
|
|
872
|
+
onerror=onerror,
|
|
867
873
|
force=True,
|
|
868
874
|
)
|
|
869
875
|
|
|
870
876
|
def copy_html_logo(self) -> None:
|
|
871
|
-
if self.config.html_logo and not
|
|
877
|
+
if self.config.html_logo and not is_url(self.config.html_logo):
|
|
872
878
|
source_path = self.confdir / self.config.html_logo
|
|
873
879
|
copyfile(
|
|
874
880
|
source_path,
|
|
@@ -877,7 +883,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
877
883
|
)
|
|
878
884
|
|
|
879
885
|
def copy_html_favicon(self) -> None:
|
|
880
|
-
if self.config.html_favicon and not
|
|
886
|
+
if self.config.html_favicon and not is_url(self.config.html_favicon):
|
|
881
887
|
source_path = self.confdir / self.config.html_favicon
|
|
882
888
|
copyfile(
|
|
883
889
|
source_path,
|
|
@@ -887,7 +893,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
887
893
|
|
|
888
894
|
def copy_static_files(self) -> None:
|
|
889
895
|
try:
|
|
890
|
-
with progress_message(__('copying static files')):
|
|
896
|
+
with progress_message(__('copying static files'), nonl=False):
|
|
891
897
|
ensuredir(self.outdir / '_static')
|
|
892
898
|
|
|
893
899
|
# prepare context for templates
|
|
@@ -908,7 +914,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
908
914
|
def copy_extra_files(self) -> None:
|
|
909
915
|
"""Copy html_extra_path files."""
|
|
910
916
|
try:
|
|
911
|
-
with progress_message(__('copying extra files')):
|
|
917
|
+
with progress_message(__('copying extra files'), nonl=False):
|
|
912
918
|
excluded = Matcher(self.config.exclude_patterns)
|
|
913
919
|
for extra_path in self.config.html_extra_path:
|
|
914
920
|
copy_asset(
|
|
@@ -922,8 +928,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
922
928
|
|
|
923
929
|
def write_buildinfo(self) -> None:
|
|
924
930
|
try:
|
|
925
|
-
|
|
926
|
-
self.build_info.dump(fp)
|
|
931
|
+
self.build_info.dump(self.outdir / '.buildinfo')
|
|
927
932
|
except OSError as exc:
|
|
928
933
|
logger.warning(__('Failed to write build info file: %r'), exc)
|
|
929
934
|
|
|
@@ -954,16 +959,15 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
954
959
|
uri = node['uri']
|
|
955
960
|
reference = nodes.reference('', '', internal=True)
|
|
956
961
|
if uri in self.images:
|
|
957
|
-
reference['refuri'] = posixpath.join(self.imgpath,
|
|
958
|
-
self.images[uri])
|
|
962
|
+
reference['refuri'] = posixpath.join(self.imgpath, self.images[uri])
|
|
959
963
|
else:
|
|
960
964
|
reference['refuri'] = uri
|
|
961
965
|
node.replace_self(reference)
|
|
962
966
|
reference.append(node)
|
|
963
967
|
|
|
964
|
-
def load_indexer(self, docnames:
|
|
968
|
+
def load_indexer(self, docnames: Set[str]) -> None:
|
|
965
969
|
assert self.indexer is not None
|
|
966
|
-
keep = set(self.env.all_docs)
|
|
970
|
+
keep = set(self.env.all_docs).difference(docnames)
|
|
967
971
|
try:
|
|
968
972
|
searchindexfn = path.join(self.outdir, self.searchindex_filename)
|
|
969
973
|
if self.indexer_dumps_unicode:
|
|
@@ -974,9 +978,13 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
974
978
|
self.indexer.load(fb, self.indexer_format)
|
|
975
979
|
except (OSError, ValueError):
|
|
976
980
|
if keep:
|
|
977
|
-
logger.warning(
|
|
978
|
-
|
|
979
|
-
|
|
981
|
+
logger.warning(
|
|
982
|
+
__(
|
|
983
|
+
"search index couldn't be loaded, but not all "
|
|
984
|
+
'documents will be built: the index will be '
|
|
985
|
+
'incomplete.'
|
|
986
|
+
)
|
|
987
|
+
)
|
|
980
988
|
# delete all entries for files that will be rebuilt
|
|
981
989
|
self.indexer.prune(keep)
|
|
982
990
|
|
|
@@ -990,12 +998,16 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
990
998
|
else:
|
|
991
999
|
self.indexer.feed(pagename, filename, title, doctree)
|
|
992
1000
|
|
|
993
|
-
def _get_local_toctree(
|
|
1001
|
+
def _get_local_toctree(
|
|
1002
|
+
self, docname: str, collapse: bool = True, **kwargs: Any
|
|
1003
|
+
) -> str:
|
|
994
1004
|
if 'includehidden' not in kwargs:
|
|
995
1005
|
kwargs['includehidden'] = False
|
|
996
1006
|
if kwargs.get('maxdepth') == '':
|
|
997
1007
|
kwargs.pop('maxdepth')
|
|
998
|
-
toctree = global_toctree_for_doc(
|
|
1008
|
+
toctree = global_toctree_for_doc(
|
|
1009
|
+
self.env, docname, self, collapse=collapse, **kwargs
|
|
1010
|
+
)
|
|
999
1011
|
return self.render_partial(toctree)['fragment']
|
|
1000
1012
|
|
|
1001
1013
|
def get_outfilename(self, pagename: str) -> str:
|
|
@@ -1033,7 +1045,8 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1033
1045
|
return quote(docname) + self.link_suffix
|
|
1034
1046
|
|
|
1035
1047
|
def handle_page(
|
|
1036
|
-
self,
|
|
1048
|
+
self,
|
|
1049
|
+
pagename: str,
|
|
1037
1050
|
addctx: dict[str, Any],
|
|
1038
1051
|
templatename: str = 'page.html',
|
|
1039
1052
|
outfilename: str | None = None,
|
|
@@ -1049,13 +1062,16 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1049
1062
|
default_baseuri = default_baseuri.rsplit('#', 1)[0]
|
|
1050
1063
|
|
|
1051
1064
|
if self.config.html_baseurl:
|
|
1052
|
-
ctx['pageurl'] = posixpath.join(
|
|
1053
|
-
|
|
1065
|
+
ctx['pageurl'] = posixpath.join(
|
|
1066
|
+
self.config.html_baseurl, self.get_target_uri(pagename)
|
|
1067
|
+
)
|
|
1054
1068
|
else:
|
|
1055
1069
|
ctx['pageurl'] = None
|
|
1056
1070
|
|
|
1057
1071
|
def pathto(
|
|
1058
|
-
otheruri: str,
|
|
1072
|
+
otheruri: str,
|
|
1073
|
+
resource: bool = False,
|
|
1074
|
+
baseuri: str = default_baseuri,
|
|
1059
1075
|
) -> str:
|
|
1060
1076
|
if resource and '://' in otheruri:
|
|
1061
1077
|
# allow non-local resources given by scheme
|
|
@@ -1066,6 +1082,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1066
1082
|
if uri == '#' and not self.allow_sharp_as_current_path:
|
|
1067
1083
|
uri = baseuri
|
|
1068
1084
|
return uri
|
|
1085
|
+
|
|
1069
1086
|
ctx['pathto'] = pathto
|
|
1070
1087
|
|
|
1071
1088
|
def hasdoc(name: str) -> bool:
|
|
@@ -1074,6 +1091,7 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1074
1091
|
if name == 'search' and self.search:
|
|
1075
1092
|
return True
|
|
1076
1093
|
return name == 'genindex' and self.get_builder_config('use_index', 'html')
|
|
1094
|
+
|
|
1077
1095
|
ctx['hasdoc'] = hasdoc
|
|
1078
1096
|
|
|
1079
1097
|
ctx['toctree'] = lambda **kwargs: self._get_local_toctree(pagename, **kwargs)
|
|
@@ -1086,9 +1104,11 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1086
1104
|
outdir = self.app.outdir
|
|
1087
1105
|
|
|
1088
1106
|
def css_tag(css: _CascadingStyleSheet) -> str:
|
|
1089
|
-
attrs = [
|
|
1090
|
-
|
|
1091
|
-
|
|
1107
|
+
attrs = [
|
|
1108
|
+
f'{key}="{html.escape(value, quote=True)}"'
|
|
1109
|
+
for key, value in css.attributes.items()
|
|
1110
|
+
if value is not None
|
|
1111
|
+
]
|
|
1092
1112
|
uri = pathto(os.fspath(css.filename), resource=True)
|
|
1093
1113
|
# the EPUB format does not allow the use of query components
|
|
1094
1114
|
# the Windows help compiler requires that css links
|
|
@@ -1106,9 +1126,11 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1106
1126
|
return f'<script src="{pathto(js, resource=True)}"></script>'
|
|
1107
1127
|
|
|
1108
1128
|
body = js.attributes.get('body', '')
|
|
1109
|
-
attrs = [
|
|
1110
|
-
|
|
1111
|
-
|
|
1129
|
+
attrs = [
|
|
1130
|
+
f'{key}="{html.escape(value, quote=True)}"'
|
|
1131
|
+
for key, value in js.attributes.items()
|
|
1132
|
+
if key != 'body' and value is not None
|
|
1133
|
+
]
|
|
1112
1134
|
|
|
1113
1135
|
if not js.filename:
|
|
1114
1136
|
if attrs:
|
|
@@ -1137,15 +1159,18 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1137
1159
|
self._js_files[:] = self._orig_js_files
|
|
1138
1160
|
|
|
1139
1161
|
self.update_page_context(pagename, templatename, ctx, event_arg)
|
|
1140
|
-
newtmpl = self.app.emit_firstresult(
|
|
1141
|
-
|
|
1162
|
+
newtmpl = self.app.emit_firstresult(
|
|
1163
|
+
'html-page-context', pagename, templatename, ctx, event_arg
|
|
1164
|
+
)
|
|
1142
1165
|
if newtmpl:
|
|
1143
1166
|
templatename = newtmpl
|
|
1144
1167
|
|
|
1145
1168
|
# sort JS/CSS before rendering HTML
|
|
1146
1169
|
try: # NoQA: SIM105
|
|
1147
1170
|
# Convert script_files to list to support non-list script_files (refs: #8889)
|
|
1148
|
-
ctx['script_files'] = sorted(
|
|
1171
|
+
ctx['script_files'] = sorted(
|
|
1172
|
+
ctx['script_files'], key=lambda js: js.priority
|
|
1173
|
+
)
|
|
1149
1174
|
except AttributeError:
|
|
1150
1175
|
# Skip sorting if users modifies script_files directly (maybe via `html_context`).
|
|
1151
1176
|
# refs: #8885
|
|
@@ -1159,33 +1184,42 @@ class StandaloneHTMLBuilder(Builder):
|
|
|
1159
1184
|
try:
|
|
1160
1185
|
output = self.templates.render(templatename, ctx)
|
|
1161
1186
|
except UnicodeError:
|
|
1162
|
-
logger.warning(
|
|
1163
|
-
|
|
1164
|
-
|
|
1187
|
+
logger.warning(
|
|
1188
|
+
__(
|
|
1189
|
+
'a Unicode error occurred when rendering the page %s. '
|
|
1190
|
+
'Please make sure all config values that contain '
|
|
1191
|
+
'non-ASCII content are Unicode strings.'
|
|
1192
|
+
),
|
|
1193
|
+
pagename,
|
|
1194
|
+
)
|
|
1165
1195
|
return
|
|
1166
1196
|
except Exception as exc:
|
|
1167
|
-
|
|
1168
|
-
|
|
1197
|
+
msg = __('An error happened in rendering the page %s.\nReason: %r') % (
|
|
1198
|
+
pagename,
|
|
1199
|
+
exc,
|
|
1200
|
+
)
|
|
1201
|
+
raise ThemeError(msg) from exc
|
|
1169
1202
|
|
|
1170
1203
|
if not outfilename:
|
|
1171
1204
|
outfilename = self.get_outfilename(pagename)
|
|
1172
1205
|
# outfilename's path is in general different from self.outdir
|
|
1173
1206
|
ensuredir(path.dirname(outfilename))
|
|
1174
1207
|
try:
|
|
1175
|
-
with open(
|
|
1176
|
-
|
|
1208
|
+
with open(
|
|
1209
|
+
outfilename, 'w', encoding=ctx['encoding'], errors='xmlcharrefreplace'
|
|
1210
|
+
) as f:
|
|
1177
1211
|
f.write(output)
|
|
1178
1212
|
except OSError as err:
|
|
1179
|
-
logger.warning(__(
|
|
1213
|
+
logger.warning(__('error writing file %s: %s'), outfilename, err)
|
|
1180
1214
|
if self.copysource and ctx.get('sourcename'):
|
|
1181
1215
|
# copy the source file for the "show source" link
|
|
1182
|
-
source_name = path.join(self.outdir, '_sources',
|
|
1183
|
-
os_path(ctx['sourcename']))
|
|
1216
|
+
source_name = path.join(self.outdir, '_sources', os_path(ctx['sourcename']))
|
|
1184
1217
|
ensuredir(path.dirname(source_name))
|
|
1185
1218
|
copyfile(self.env.doc2path(pagename), source_name, force=True)
|
|
1186
1219
|
|
|
1187
|
-
def update_page_context(
|
|
1188
|
-
|
|
1220
|
+
def update_page_context(
|
|
1221
|
+
self, pagename: str, templatename: str, ctx: dict[str, Any], event_arg: Any
|
|
1222
|
+
) -> None:
|
|
1189
1223
|
pass
|
|
1190
1224
|
|
|
1191
1225
|
def handle_finish(self) -> None:
|
|
@@ -1248,19 +1282,24 @@ def convert_html_js_files(app: Sphinx, config: Config) -> None:
|
|
|
1248
1282
|
config.html_js_files = html_js_files
|
|
1249
1283
|
|
|
1250
1284
|
|
|
1251
|
-
def setup_resource_paths(
|
|
1252
|
-
|
|
1285
|
+
def setup_resource_paths(
|
|
1286
|
+
app: Sphinx,
|
|
1287
|
+
pagename: str,
|
|
1288
|
+
templatename: str,
|
|
1289
|
+
context: dict[str, Any],
|
|
1290
|
+
doctree: Node,
|
|
1291
|
+
) -> None:
|
|
1253
1292
|
"""Set up relative resource paths."""
|
|
1254
1293
|
pathto = context['pathto']
|
|
1255
1294
|
|
|
1256
1295
|
# favicon_url
|
|
1257
1296
|
favicon_url = context.get('favicon_url')
|
|
1258
|
-
if favicon_url and not
|
|
1297
|
+
if favicon_url and not is_url(favicon_url):
|
|
1259
1298
|
context['favicon_url'] = pathto('_static/' + favicon_url, resource=True)
|
|
1260
1299
|
|
|
1261
1300
|
# logo_url
|
|
1262
1301
|
logo_url = context.get('logo_url')
|
|
1263
|
-
if logo_url and not
|
|
1302
|
+
if logo_url and not is_url(logo_url):
|
|
1264
1303
|
context['logo_url'] = pathto('_static/' + logo_url, resource=True)
|
|
1265
1304
|
|
|
1266
1305
|
|
|
@@ -1270,8 +1309,10 @@ def validate_math_renderer(app: Sphinx) -> None:
|
|
|
1270
1309
|
|
|
1271
1310
|
name = app.builder.math_renderer_name # type: ignore[attr-defined]
|
|
1272
1311
|
if name is None:
|
|
1273
|
-
|
|
1274
|
-
|
|
1312
|
+
msg = __(
|
|
1313
|
+
'Many math_renderers are registered. But no math_renderer is selected.'
|
|
1314
|
+
)
|
|
1315
|
+
raise ConfigError(msg)
|
|
1275
1316
|
if name not in app.registry.html_inline_math_renderers:
|
|
1276
1317
|
raise ConfigError(__('Unknown math_renderer %r is given.') % name)
|
|
1277
1318
|
|
|
@@ -1283,9 +1324,13 @@ def validate_html_extra_path(app: Sphinx, config: Config) -> None:
|
|
|
1283
1324
|
if not path.exists(extra_path):
|
|
1284
1325
|
logger.warning(__('html_extra_path entry %r does not exist'), entry)
|
|
1285
1326
|
config.html_extra_path.remove(entry)
|
|
1286
|
-
elif (
|
|
1287
|
-
|
|
1288
|
-
|
|
1327
|
+
elif (
|
|
1328
|
+
path.splitdrive(app.outdir)[0] == path.splitdrive(extra_path)[0]
|
|
1329
|
+
and path.commonpath((app.outdir, extra_path)) == path.normpath(app.outdir)
|
|
1330
|
+
): # fmt: skip
|
|
1331
|
+
logger.warning(
|
|
1332
|
+
__('html_extra_path entry %r is placed inside outdir'), entry
|
|
1333
|
+
)
|
|
1289
1334
|
config.html_extra_path.remove(entry)
|
|
1290
1335
|
|
|
1291
1336
|
|
|
@@ -1296,26 +1341,34 @@ def validate_html_static_path(app: Sphinx, config: Config) -> None:
|
|
|
1296
1341
|
if not path.exists(static_path):
|
|
1297
1342
|
logger.warning(__('html_static_path entry %r does not exist'), entry)
|
|
1298
1343
|
config.html_static_path.remove(entry)
|
|
1299
|
-
elif (
|
|
1300
|
-
|
|
1301
|
-
|
|
1344
|
+
elif (
|
|
1345
|
+
path.splitdrive(app.outdir)[0] == path.splitdrive(static_path)[0]
|
|
1346
|
+
and path.commonpath((app.outdir, static_path)) == path.normpath(app.outdir)
|
|
1347
|
+
): # fmt: skip
|
|
1348
|
+
logger.warning(
|
|
1349
|
+
__('html_static_path entry %r is placed inside outdir'), entry
|
|
1350
|
+
)
|
|
1302
1351
|
config.html_static_path.remove(entry)
|
|
1303
1352
|
|
|
1304
1353
|
|
|
1305
1354
|
def validate_html_logo(app: Sphinx, config: Config) -> None:
|
|
1306
1355
|
"""Check html_logo setting."""
|
|
1307
|
-
if (
|
|
1308
|
-
|
|
1309
|
-
|
|
1356
|
+
if (
|
|
1357
|
+
config.html_logo
|
|
1358
|
+
and not path.isfile(path.join(app.confdir, config.html_logo))
|
|
1359
|
+
and not is_url(config.html_logo)
|
|
1360
|
+
):
|
|
1310
1361
|
logger.warning(__('logo file %r does not exist'), config.html_logo)
|
|
1311
1362
|
config.html_logo = None
|
|
1312
1363
|
|
|
1313
1364
|
|
|
1314
1365
|
def validate_html_favicon(app: Sphinx, config: Config) -> None:
|
|
1315
1366
|
"""Check html_favicon setting."""
|
|
1316
|
-
if (
|
|
1317
|
-
|
|
1318
|
-
|
|
1367
|
+
if (
|
|
1368
|
+
config.html_favicon
|
|
1369
|
+
and not path.isfile(path.join(app.confdir, config.html_favicon))
|
|
1370
|
+
and not is_url(config.html_favicon)
|
|
1371
|
+
):
|
|
1319
1372
|
logger.warning(__('favicon file %r does not exist'), config.html_favicon)
|
|
1320
1373
|
config.html_favicon = None
|
|
1321
1374
|
|
|
@@ -1328,9 +1381,11 @@ def error_on_html_sidebars_string_values(app: Sphinx, config: Config) -> None:
|
|
|
1328
1381
|
errors[pattern] = [pat_sidebars]
|
|
1329
1382
|
if not errors:
|
|
1330
1383
|
return
|
|
1331
|
-
msg = __(
|
|
1332
|
-
|
|
1333
|
-
|
|
1384
|
+
msg = __(
|
|
1385
|
+
"Values in 'html_sidebars' must be a list of strings. "
|
|
1386
|
+
'At least one pattern has a string value: %s. '
|
|
1387
|
+
'Change to `html_sidebars = %r`.'
|
|
1388
|
+
)
|
|
1334
1389
|
bad_patterns = ', '.join(map(repr, errors))
|
|
1335
1390
|
fixed = config.html_sidebars | errors
|
|
1336
1391
|
raise ConfigError(msg % (bad_patterns, fixed))
|
|
@@ -1339,10 +1394,11 @@ def error_on_html_sidebars_string_values(app: Sphinx, config: Config) -> None:
|
|
|
1339
1394
|
def error_on_html_4(_app: Sphinx, config: Config) -> None:
|
|
1340
1395
|
"""Error on HTML 4."""
|
|
1341
1396
|
if config.html4_writer:
|
|
1342
|
-
|
|
1397
|
+
msg = __(
|
|
1343
1398
|
'HTML 4 is no longer supported by Sphinx. '
|
|
1344
1399
|
'("html4_writer=True" detected in configuration options)',
|
|
1345
|
-
)
|
|
1400
|
+
)
|
|
1401
|
+
raise ConfigError(msg)
|
|
1346
1402
|
|
|
1347
1403
|
|
|
1348
1404
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
|
@@ -1354,7 +1410,11 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
1354
1410
|
app.add_config_value('html_theme_path', [], 'html')
|
|
1355
1411
|
app.add_config_value('html_theme_options', {}, 'html')
|
|
1356
1412
|
app.add_config_value(
|
|
1357
|
-
'html_title',
|
|
1413
|
+
'html_title',
|
|
1414
|
+
lambda c: _('%s %s documentation') % (c.project, c.release),
|
|
1415
|
+
'html',
|
|
1416
|
+
str,
|
|
1417
|
+
)
|
|
1358
1418
|
app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
|
|
1359
1419
|
app.add_config_value('html_style', None, 'html', {list, str})
|
|
1360
1420
|
app.add_config_value('html_logo', None, 'html', str)
|
|
@@ -1364,6 +1424,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
1364
1424
|
app.add_config_value('html_static_path', [], 'html')
|
|
1365
1425
|
app.add_config_value('html_extra_path', [], 'html')
|
|
1366
1426
|
app.add_config_value('html_last_updated_fmt', None, 'html', str)
|
|
1427
|
+
app.add_config_value('html_last_updated_use_utc', False, 'html', types={bool})
|
|
1367
1428
|
app.add_config_value('html_sidebars', {}, 'html')
|
|
1368
1429
|
app.add_config_value('html_additional_pages', {}, 'html')
|
|
1369
1430
|
app.add_config_value('html_domain_indices', True, 'html', types={set, list})
|
|
@@ -1390,8 +1451,9 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
1390
1451
|
app.add_config_value('html_scaled_image_link', True, 'html')
|
|
1391
1452
|
app.add_config_value('html_baseurl', '', 'html')
|
|
1392
1453
|
# removal is indefinitely on hold (ref: https://github.com/sphinx-doc/sphinx/issues/10265)
|
|
1393
|
-
app.add_config_value(
|
|
1394
|
-
|
|
1454
|
+
app.add_config_value(
|
|
1455
|
+
'html_codeblock_linenos_style', 'inline', 'html', ENUM('table', 'inline')
|
|
1456
|
+
)
|
|
1395
1457
|
app.add_config_value('html_math_renderer', None, 'env')
|
|
1396
1458
|
app.add_config_value('html4_writer', False, 'html')
|
|
1397
1459
|
|
|
@@ -1426,7 +1488,11 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
1426
1488
|
|
|
1427
1489
|
# deprecated name -> (object to return, canonical path or empty string, removal version)
|
|
1428
1490
|
_DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
|
|
1429
|
-
'Stylesheet': (
|
|
1491
|
+
'Stylesheet': (
|
|
1492
|
+
_CascadingStyleSheet,
|
|
1493
|
+
'sphinx.builders.html._assets._CascadingStyleSheet',
|
|
1494
|
+
(9, 0),
|
|
1495
|
+
),
|
|
1430
1496
|
'JavaScript': (_JavaScript, 'sphinx.builders.html._assets._JavaScript', (9, 0)),
|
|
1431
1497
|
}
|
|
1432
1498
|
|