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/util/docutils.py
CHANGED
|
@@ -24,7 +24,9 @@ from sphinx.util import logging
|
|
|
24
24
|
from sphinx.util.parsing import nested_parse_to_nodes
|
|
25
25
|
|
|
26
26
|
logger = logging.getLogger(__name__)
|
|
27
|
-
report_re = re.compile(
|
|
27
|
+
report_re = re.compile(
|
|
28
|
+
'^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) '
|
|
29
|
+
)
|
|
28
30
|
|
|
29
31
|
if TYPE_CHECKING:
|
|
30
32
|
from collections.abc import Callable, Iterator # NoQA: TCH003
|
|
@@ -114,8 +116,8 @@ def unregister_node(node: type[Element]) -> None:
|
|
|
114
116
|
This is inverse of ``nodes._add_nodes_class_names()``.
|
|
115
117
|
"""
|
|
116
118
|
if hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
|
|
117
|
-
delattr(nodes.GenericNodeVisitor,
|
|
118
|
-
delattr(nodes.GenericNodeVisitor,
|
|
119
|
+
delattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__)
|
|
120
|
+
delattr(nodes.GenericNodeVisitor, 'depart_' + node.__name__)
|
|
119
121
|
delattr(nodes.SparseNodeVisitor, 'visit_' + node.__name__)
|
|
120
122
|
delattr(nodes.SparseNodeVisitor, 'depart_' + node.__name__)
|
|
121
123
|
|
|
@@ -129,7 +131,9 @@ def patched_get_language() -> Iterator[None]:
|
|
|
129
131
|
"""
|
|
130
132
|
from docutils.languages import get_language
|
|
131
133
|
|
|
132
|
-
def patched_get_language(
|
|
134
|
+
def patched_get_language(
|
|
135
|
+
language_code: str, reporter: Reporter | None = None
|
|
136
|
+
) -> Any:
|
|
133
137
|
return get_language(language_code)
|
|
134
138
|
|
|
135
139
|
try:
|
|
@@ -153,7 +157,9 @@ def patched_rst_get_language() -> Iterator[None]:
|
|
|
153
157
|
"""
|
|
154
158
|
from docutils.parsers.rst.languages import get_language
|
|
155
159
|
|
|
156
|
-
def patched_get_language(
|
|
160
|
+
def patched_get_language(
|
|
161
|
+
language_code: str, reporter: Reporter | None = None
|
|
162
|
+
) -> Any:
|
|
157
163
|
return get_language(language_code)
|
|
158
164
|
|
|
159
165
|
try:
|
|
@@ -170,7 +176,9 @@ def using_user_docutils_conf(confdir: str | None) -> Iterator[None]:
|
|
|
170
176
|
try:
|
|
171
177
|
docutilsconfig = os.environ.get('DOCUTILSCONFIG', None)
|
|
172
178
|
if confdir:
|
|
173
|
-
os.environ['DOCUTILSCONFIG'] = path.join(
|
|
179
|
+
os.environ['DOCUTILSCONFIG'] = path.join(
|
|
180
|
+
path.abspath(confdir), 'docutils.conf'
|
|
181
|
+
)
|
|
174
182
|
|
|
175
183
|
yield
|
|
176
184
|
finally:
|
|
@@ -183,9 +191,11 @@ def using_user_docutils_conf(confdir: str | None) -> Iterator[None]:
|
|
|
183
191
|
@contextmanager
|
|
184
192
|
def patch_docutils(confdir: str | None = None) -> Iterator[None]:
|
|
185
193
|
"""Patch to docutils temporarily."""
|
|
186
|
-
with
|
|
187
|
-
|
|
188
|
-
|
|
194
|
+
with (
|
|
195
|
+
patched_get_language(),
|
|
196
|
+
patched_rst_get_language(),
|
|
197
|
+
using_user_docutils_conf(confdir),
|
|
198
|
+
):
|
|
189
199
|
yield
|
|
190
200
|
|
|
191
201
|
|
|
@@ -204,7 +214,7 @@ class CustomReSTDispatcher:
|
|
|
204
214
|
self.enable()
|
|
205
215
|
|
|
206
216
|
def __exit__(
|
|
207
|
-
self, exc_type: type[Exception], exc_value: Exception, traceback: Any
|
|
217
|
+
self, exc_type: type[Exception], exc_value: Exception, traceback: Any
|
|
208
218
|
) -> None:
|
|
209
219
|
self.disable()
|
|
210
220
|
|
|
@@ -219,16 +229,27 @@ class CustomReSTDispatcher:
|
|
|
219
229
|
directives.directive = self.directive_func
|
|
220
230
|
roles.role = self.role_func
|
|
221
231
|
|
|
222
|
-
def directive(
|
|
223
|
-
|
|
224
|
-
|
|
232
|
+
def directive(
|
|
233
|
+
self,
|
|
234
|
+
directive_name: str,
|
|
235
|
+
language_module: ModuleType,
|
|
236
|
+
document: nodes.document,
|
|
237
|
+
) -> tuple[type[Directive] | None, list[system_message]]:
|
|
225
238
|
return self.directive_func(directive_name, language_module, document)
|
|
226
239
|
|
|
227
240
|
def role(
|
|
228
|
-
self,
|
|
241
|
+
self,
|
|
242
|
+
role_name: str,
|
|
243
|
+
language_module: ModuleType,
|
|
244
|
+
lineno: int,
|
|
245
|
+
reporter: Reporter,
|
|
229
246
|
) -> tuple[RoleFunction, list[system_message]]:
|
|
230
|
-
return self.role_func(
|
|
231
|
-
|
|
247
|
+
return self.role_func(
|
|
248
|
+
role_name,
|
|
249
|
+
language_module, # type: ignore[return-value]
|
|
250
|
+
lineno,
|
|
251
|
+
reporter,
|
|
252
|
+
)
|
|
232
253
|
|
|
233
254
|
|
|
234
255
|
class ElementLookupError(Exception):
|
|
@@ -258,7 +279,9 @@ class sphinx_domains(CustomReSTDispatcher):
|
|
|
258
279
|
if element is not None:
|
|
259
280
|
return element, []
|
|
260
281
|
else:
|
|
261
|
-
logger.warning(
|
|
282
|
+
logger.warning(
|
|
283
|
+
_('unknown directive or role name: %s:%s'), domain_name, name
|
|
284
|
+
)
|
|
262
285
|
# else look in the default domain
|
|
263
286
|
else:
|
|
264
287
|
def_domain = self.env.temp_data.get('default_domain')
|
|
@@ -268,22 +291,29 @@ class sphinx_domains(CustomReSTDispatcher):
|
|
|
268
291
|
return element, []
|
|
269
292
|
|
|
270
293
|
# always look in the std domain
|
|
271
|
-
element = getattr(self.env.
|
|
294
|
+
element = getattr(self.env.domains.standard_domain, type)(name)
|
|
272
295
|
if element is not None:
|
|
273
296
|
return element, []
|
|
274
297
|
|
|
275
298
|
raise ElementLookupError
|
|
276
299
|
|
|
277
|
-
def directive(
|
|
278
|
-
|
|
279
|
-
|
|
300
|
+
def directive(
|
|
301
|
+
self,
|
|
302
|
+
directive_name: str,
|
|
303
|
+
language_module: ModuleType,
|
|
304
|
+
document: nodes.document,
|
|
305
|
+
) -> tuple[type[Directive] | None, list[system_message]]:
|
|
280
306
|
try:
|
|
281
307
|
return self.lookup_domain_element('directive', directive_name)
|
|
282
308
|
except ElementLookupError:
|
|
283
309
|
return super().directive(directive_name, language_module, document)
|
|
284
310
|
|
|
285
311
|
def role(
|
|
286
|
-
self,
|
|
312
|
+
self,
|
|
313
|
+
role_name: str,
|
|
314
|
+
language_module: ModuleType,
|
|
315
|
+
lineno: int,
|
|
316
|
+
reporter: Reporter,
|
|
287
317
|
) -> tuple[RoleFunction, list[system_message]]:
|
|
288
318
|
try:
|
|
289
319
|
return self.lookup_domain_element('role', role_name)
|
|
@@ -295,26 +325,39 @@ class WarningStream:
|
|
|
295
325
|
def write(self, text: str) -> None:
|
|
296
326
|
matched = report_re.search(text)
|
|
297
327
|
if not matched:
|
|
298
|
-
logger.warning(text.rstrip(
|
|
328
|
+
logger.warning(text.rstrip('\r\n'), type='docutils')
|
|
299
329
|
else:
|
|
300
330
|
location, type, level = matched.groups()
|
|
301
331
|
message = report_re.sub('', text).rstrip()
|
|
302
|
-
logger.log(type, message, location=location, type=
|
|
332
|
+
logger.log(type, message, location=location, type='docutils')
|
|
303
333
|
|
|
304
334
|
|
|
305
335
|
class LoggingReporter(Reporter):
|
|
306
336
|
@classmethod
|
|
307
|
-
def from_reporter(
|
|
337
|
+
def from_reporter(
|
|
338
|
+
cls: type[LoggingReporter], reporter: Reporter
|
|
339
|
+
) -> LoggingReporter:
|
|
308
340
|
"""Create an instance of LoggingReporter from other reporter object."""
|
|
309
|
-
return cls(
|
|
310
|
-
|
|
341
|
+
return cls(
|
|
342
|
+
reporter.source,
|
|
343
|
+
reporter.report_level,
|
|
344
|
+
reporter.halt_level,
|
|
345
|
+
reporter.debug_flag,
|
|
346
|
+
reporter.error_handler,
|
|
347
|
+
)
|
|
311
348
|
|
|
312
|
-
def __init__(
|
|
313
|
-
|
|
314
|
-
|
|
349
|
+
def __init__(
|
|
350
|
+
self,
|
|
351
|
+
source: str,
|
|
352
|
+
report_level: int = Reporter.WARNING_LEVEL,
|
|
353
|
+
halt_level: int = Reporter.SEVERE_LEVEL,
|
|
354
|
+
debug: bool = False,
|
|
355
|
+
error_handler: str = 'backslashreplace',
|
|
356
|
+
) -> None:
|
|
315
357
|
stream = cast(IO, WarningStream())
|
|
316
|
-
super().__init__(
|
|
317
|
-
|
|
358
|
+
super().__init__(
|
|
359
|
+
source, report_level, halt_level, stream, debug, error_handler=error_handler
|
|
360
|
+
)
|
|
318
361
|
|
|
319
362
|
|
|
320
363
|
class NullReporter(Reporter):
|
|
@@ -351,8 +394,13 @@ class SphinxFileOutput(FileOutput):
|
|
|
351
394
|
super().__init__(**kwargs)
|
|
352
395
|
|
|
353
396
|
def write(self, data: str) -> str:
|
|
354
|
-
if (
|
|
355
|
-
|
|
397
|
+
if (
|
|
398
|
+
self.destination_path
|
|
399
|
+
and self.autoclose
|
|
400
|
+
and 'b' not in self.mode
|
|
401
|
+
and self.overwrite_if_changed
|
|
402
|
+
and os.path.exists(self.destination_path)
|
|
403
|
+
):
|
|
356
404
|
with open(self.destination_path, encoding=self.encoding) as f:
|
|
357
405
|
# skip writing: content not changed
|
|
358
406
|
if f.read() == data:
|
|
@@ -416,7 +464,9 @@ class SphinxDirective(Directive):
|
|
|
416
464
|
return f'<unknown>:{line}'
|
|
417
465
|
return ''
|
|
418
466
|
|
|
419
|
-
def parse_content_to_nodes(
|
|
467
|
+
def parse_content_to_nodes(
|
|
468
|
+
self, allow_section_headings: bool = False
|
|
469
|
+
) -> list[Node]:
|
|
420
470
|
"""Parse the directive's content into nodes.
|
|
421
471
|
|
|
422
472
|
:param allow_section_headings:
|
|
@@ -437,7 +487,12 @@ class SphinxDirective(Directive):
|
|
|
437
487
|
)
|
|
438
488
|
|
|
439
489
|
def parse_text_to_nodes(
|
|
440
|
-
self,
|
|
490
|
+
self,
|
|
491
|
+
text: str = '',
|
|
492
|
+
/,
|
|
493
|
+
*,
|
|
494
|
+
offset: int = -1,
|
|
495
|
+
allow_section_headings: bool = False,
|
|
441
496
|
) -> list[Node]:
|
|
442
497
|
"""Parse *text* into nodes.
|
|
443
498
|
|
|
@@ -465,7 +520,7 @@ class SphinxDirective(Directive):
|
|
|
465
520
|
)
|
|
466
521
|
|
|
467
522
|
def parse_inline(
|
|
468
|
-
self, text: str, *, lineno: int = -1
|
|
523
|
+
self, text: str, *, lineno: int = -1
|
|
469
524
|
) -> tuple[list[Node], list[system_message]]:
|
|
470
525
|
"""Parse *text* as inline elements.
|
|
471
526
|
|
|
@@ -496,6 +551,7 @@ class SphinxRole:
|
|
|
496
551
|
This class is strongly coupled with Sphinx.
|
|
497
552
|
"""
|
|
498
553
|
|
|
554
|
+
# fmt: off
|
|
499
555
|
name: str #: The role name actually used in the document.
|
|
500
556
|
rawtext: str #: A string containing the entire interpreted text input.
|
|
501
557
|
text: str #: The interpreted text content.
|
|
@@ -507,10 +563,18 @@ class SphinxRole:
|
|
|
507
563
|
#: A list of strings, the directive content for customisation
|
|
508
564
|
#: (from the "role" directive).
|
|
509
565
|
content: Sequence[str]
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
566
|
+
# fmt: on
|
|
567
|
+
|
|
568
|
+
def __call__(
|
|
569
|
+
self,
|
|
570
|
+
name: str,
|
|
571
|
+
rawtext: str,
|
|
572
|
+
text: str,
|
|
573
|
+
lineno: int,
|
|
574
|
+
inliner: Inliner,
|
|
575
|
+
options: dict | None = None,
|
|
576
|
+
content: Sequence[str] = (),
|
|
577
|
+
) -> tuple[list[Node], list[system_message]]:
|
|
514
578
|
self.rawtext = rawtext
|
|
515
579
|
self.text = unescape(text)
|
|
516
580
|
self.lineno = lineno
|
|
@@ -585,17 +649,26 @@ class ReferenceRole(SphinxRole):
|
|
|
585
649
|
.. versionadded:: 2.0
|
|
586
650
|
"""
|
|
587
651
|
|
|
652
|
+
# fmt: off
|
|
588
653
|
has_explicit_title: bool #: A boolean indicates the role has explicit title or not.
|
|
589
654
|
disabled: bool #: A boolean indicates the reference is disabled.
|
|
590
655
|
title: str #: The link title for the interpreted text.
|
|
591
656
|
target: str #: The link target for the interpreted text.
|
|
657
|
+
# fmt: on
|
|
592
658
|
|
|
593
659
|
# \x00 means the "<" was backslash-escaped
|
|
594
660
|
explicit_title_re = re.compile(r'^(.+?)\s*(?<!\x00)<(.*?)>$', re.DOTALL)
|
|
595
661
|
|
|
596
|
-
def __call__(
|
|
597
|
-
|
|
598
|
-
|
|
662
|
+
def __call__(
|
|
663
|
+
self,
|
|
664
|
+
name: str,
|
|
665
|
+
rawtext: str,
|
|
666
|
+
text: str,
|
|
667
|
+
lineno: int,
|
|
668
|
+
inliner: Inliner,
|
|
669
|
+
options: dict | None = None,
|
|
670
|
+
content: Sequence[str] = (),
|
|
671
|
+
) -> tuple[list[Node], list[system_message]]:
|
|
599
672
|
if options is None:
|
|
600
673
|
options = {}
|
|
601
674
|
|
|
@@ -698,6 +771,7 @@ def new_document(source_path: str, settings: Any = None) -> nodes.document:
|
|
|
698
771
|
|
|
699
772
|
# Create a new instance of nodes.document using cached reporter
|
|
700
773
|
from sphinx import addnodes
|
|
774
|
+
|
|
701
775
|
document = addnodes.document(settings, reporter, source=source_path)
|
|
702
776
|
document.note_source(source_path, -1)
|
|
703
777
|
return document
|
sphinx/util/exceptions.py
CHANGED
|
@@ -31,12 +31,18 @@ def save_traceback(app: Sphinx | None, exc: BaseException) -> str:
|
|
|
31
31
|
last_msgs = exts_list = ''
|
|
32
32
|
else:
|
|
33
33
|
extensions = app.extensions.values()
|
|
34
|
-
last_msgs = '\n'.join(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
last_msgs = '\n'.join(
|
|
35
|
+
f'# {strip_escape_sequences(s).strip()}' for s in app.messagelog
|
|
36
|
+
)
|
|
37
|
+
exts_list = '\n'.join(
|
|
38
|
+
f'# {ext.name} ({ext.version})'
|
|
39
|
+
for ext in extensions
|
|
40
|
+
if ext.version != 'builtin'
|
|
41
|
+
)
|
|
38
42
|
|
|
39
|
-
with NamedTemporaryFile(
|
|
43
|
+
with NamedTemporaryFile(
|
|
44
|
+
'w', suffix='.log', prefix='sphinx-err-', delete=False
|
|
45
|
+
) as f:
|
|
40
46
|
f.write(f"""\
|
|
41
47
|
# Platform: {sys.platform}; ({platform.platform()})
|
|
42
48
|
# Sphinx version: {sphinx.__display_version__}
|
sphinx/util/fileutil.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import posixpath
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
from typing import TYPE_CHECKING, Any
|
|
8
9
|
|
|
9
10
|
from docutils.utils import relative_path
|
|
@@ -34,11 +35,14 @@ def _template_basename(filename: str | os.PathLike[str]) -> str | None:
|
|
|
34
35
|
return None
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def copy_asset_file(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
def copy_asset_file(
|
|
39
|
+
source: str | os.PathLike[str],
|
|
40
|
+
destination: str | os.PathLike[str],
|
|
41
|
+
context: dict[str, Any] | None = None,
|
|
42
|
+
renderer: BaseRenderer | None = None,
|
|
43
|
+
*,
|
|
44
|
+
force: bool = False,
|
|
45
|
+
) -> None:
|
|
42
46
|
"""Copy an asset file to destination.
|
|
43
47
|
|
|
44
48
|
On copying, it expands the template variables if context argument is given and
|
|
@@ -53,44 +57,59 @@ def copy_asset_file(source: str | os.PathLike[str], destination: str | os.PathLi
|
|
|
53
57
|
if not os.path.exists(source):
|
|
54
58
|
return
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
destination = Path(destination)
|
|
61
|
+
if destination.is_dir():
|
|
57
62
|
# Use source filename if destination points a directory
|
|
58
|
-
destination
|
|
59
|
-
else:
|
|
60
|
-
destination = str(destination)
|
|
63
|
+
destination /= os.path.basename(source)
|
|
61
64
|
|
|
62
65
|
if _template_basename(source) and context is not None:
|
|
63
66
|
if renderer is None:
|
|
64
67
|
from sphinx.util.template import SphinxRenderer
|
|
68
|
+
|
|
65
69
|
renderer = SphinxRenderer()
|
|
66
70
|
|
|
67
71
|
with open(source, encoding='utf-8') as fsrc:
|
|
68
72
|
template_content = fsrc.read()
|
|
69
73
|
rendered_template = renderer.render_string(template_content, context)
|
|
70
74
|
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
if not force and destination.exists() and template_content != rendered_template:
|
|
76
|
+
msg = __(
|
|
77
|
+
'Aborted attempted copy from rendered template %s to %s '
|
|
78
|
+
'(the destination path has existing data).'
|
|
79
|
+
)
|
|
80
|
+
logger.warning(
|
|
81
|
+
msg,
|
|
82
|
+
os.fsdecode(source),
|
|
83
|
+
os.fsdecode(destination),
|
|
84
|
+
type='misc',
|
|
85
|
+
subtype='copy_overwrite',
|
|
86
|
+
)
|
|
80
87
|
return
|
|
81
88
|
|
|
82
89
|
destination = _template_basename(destination) or destination
|
|
83
90
|
with open(destination, 'w', encoding='utf-8') as fdst:
|
|
91
|
+
msg = __('Writing evaluated template result to %s')
|
|
92
|
+
logger.info(
|
|
93
|
+
msg,
|
|
94
|
+
os.fsdecode(destination),
|
|
95
|
+
type='misc',
|
|
96
|
+
subtype='template_evaluation',
|
|
97
|
+
)
|
|
84
98
|
fdst.write(rendered_template)
|
|
85
99
|
else:
|
|
86
100
|
copyfile(source, destination, force=force)
|
|
87
101
|
|
|
88
102
|
|
|
89
|
-
def copy_asset(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
def copy_asset(
|
|
104
|
+
source: str | os.PathLike[str],
|
|
105
|
+
destination: str | os.PathLike[str],
|
|
106
|
+
excluded: PathMatcher = lambda path: False,
|
|
107
|
+
context: dict[str, Any] | None = None,
|
|
108
|
+
renderer: BaseRenderer | None = None,
|
|
109
|
+
onerror: Callable[[str, Exception], None] | None = None,
|
|
110
|
+
*,
|
|
111
|
+
force: bool = False,
|
|
112
|
+
) -> None:
|
|
94
113
|
"""Copy asset files to destination recursively.
|
|
95
114
|
|
|
96
115
|
On copying, it expands the template variables if context argument is given and
|
|
@@ -111,14 +130,14 @@ def copy_asset(source: str | os.PathLike[str], destination: str | os.PathLike[st
|
|
|
111
130
|
|
|
112
131
|
if renderer is None:
|
|
113
132
|
from sphinx.util.template import SphinxRenderer
|
|
133
|
+
|
|
114
134
|
renderer = SphinxRenderer()
|
|
115
135
|
|
|
116
136
|
ensuredir(destination)
|
|
117
137
|
if os.path.isfile(source):
|
|
118
|
-
copy_asset_file(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
force=force)
|
|
138
|
+
copy_asset_file(
|
|
139
|
+
source, destination, context=context, renderer=renderer, force=force
|
|
140
|
+
)
|
|
122
141
|
return
|
|
123
142
|
|
|
124
143
|
for root, dirs, files in os.walk(source, followlinks=True):
|
|
@@ -132,11 +151,13 @@ def copy_asset(source: str | os.PathLike[str], destination: str | os.PathLike[st
|
|
|
132
151
|
for filename in files:
|
|
133
152
|
if not excluded(posixpath.join(reldir, filename)):
|
|
134
153
|
try:
|
|
135
|
-
copy_asset_file(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
154
|
+
copy_asset_file(
|
|
155
|
+
posixpath.join(root, filename),
|
|
156
|
+
posixpath.join(destination, reldir),
|
|
157
|
+
context=context,
|
|
158
|
+
renderer=renderer,
|
|
159
|
+
force=force,
|
|
160
|
+
)
|
|
140
161
|
except Exception as exc:
|
|
141
162
|
if onerror:
|
|
142
163
|
onerror(posixpath.join(root, filename), exc)
|
sphinx/util/http_date.py
CHANGED
|
@@ -12,7 +12,7 @@ from sphinx.deprecation import RemovedInSphinx90Warning
|
|
|
12
12
|
_WEEKDAY_NAME = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
|
|
13
13
|
_MONTH_NAME = ('', # Placeholder for indexing purposes
|
|
14
14
|
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
15
|
-
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
|
|
15
|
+
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') # fmt: skip
|
|
16
16
|
_GMT_OFFSET = float(time.localtime().tm_gmtoff)
|
|
17
17
|
|
|
18
18
|
|
|
@@ -29,18 +29,20 @@ def rfc1123_to_epoch(rfc1123: str) -> float:
|
|
|
29
29
|
t = parsedate_tz(rfc1123)
|
|
30
30
|
if t is None:
|
|
31
31
|
raise ValueError
|
|
32
|
-
if not rfc1123.endswith(
|
|
32
|
+
if not rfc1123.endswith(' GMT'):
|
|
33
33
|
warnings.warn(
|
|
34
|
-
|
|
34
|
+
'HTTP-date string does not meet RFC 7231 requirements '
|
|
35
35
|
f"(must end with 'GMT'): {rfc1123!r}",
|
|
36
|
-
RemovedInSphinx90Warning,
|
|
36
|
+
RemovedInSphinx90Warning,
|
|
37
|
+
stacklevel=3,
|
|
37
38
|
)
|
|
38
39
|
epoch_secs = time.mktime(time.struct_time(t[:9])) + _GMT_OFFSET
|
|
39
40
|
if (gmt_offset := t[9]) != 0:
|
|
40
41
|
warnings.warn(
|
|
41
|
-
|
|
42
|
-
f
|
|
43
|
-
RemovedInSphinx90Warning,
|
|
42
|
+
'HTTP-date string does not meet RFC 7231 requirements '
|
|
43
|
+
f'(must be GMT time): {rfc1123!r}',
|
|
44
|
+
RemovedInSphinx90Warning,
|
|
45
|
+
stacklevel=3,
|
|
44
46
|
)
|
|
45
47
|
return epoch_secs - (gmt_offset or 0)
|
|
46
48
|
return epoch_secs
|
sphinx/util/i18n.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
|
+
import sys
|
|
7
8
|
from datetime import datetime, timezone
|
|
8
9
|
from os import path
|
|
9
10
|
from typing import TYPE_CHECKING, NamedTuple
|
|
@@ -59,6 +60,11 @@ if TYPE_CHECKING:
|
|
|
59
60
|
|
|
60
61
|
Formatter: TypeAlias = DateFormatter | TimeFormatter | DatetimeFormatter
|
|
61
62
|
|
|
63
|
+
if sys.version_info[:2] >= (3, 11):
|
|
64
|
+
from datetime import UTC
|
|
65
|
+
else:
|
|
66
|
+
UTC = timezone.utc
|
|
67
|
+
|
|
62
68
|
logger = logging.getLogger(__name__)
|
|
63
69
|
|
|
64
70
|
|
|
@@ -69,7 +75,6 @@ class LocaleFileInfoBase(NamedTuple):
|
|
|
69
75
|
|
|
70
76
|
|
|
71
77
|
class CatalogInfo(LocaleFileInfoBase):
|
|
72
|
-
|
|
73
78
|
@property
|
|
74
79
|
def po_file(self) -> str:
|
|
75
80
|
return self.domain + '.po'
|
|
@@ -88,8 +93,9 @@ class CatalogInfo(LocaleFileInfoBase):
|
|
|
88
93
|
|
|
89
94
|
def is_outdated(self) -> bool:
|
|
90
95
|
return (
|
|
91
|
-
not path.exists(self.mo_path)
|
|
92
|
-
_last_modified_time(self.mo_path) < _last_modified_time(self.po_path)
|
|
96
|
+
not path.exists(self.mo_path)
|
|
97
|
+
or _last_modified_time(self.mo_path) < _last_modified_time(self.po_path)
|
|
98
|
+
) # fmt: skip
|
|
93
99
|
|
|
94
100
|
def write_mo(self, locale: str, use_fuzzy: bool = False) -> None:
|
|
95
101
|
with open(self.po_path, encoding=self.charset) as file_po:
|
|
@@ -109,8 +115,13 @@ class CatalogInfo(LocaleFileInfoBase):
|
|
|
109
115
|
class CatalogRepository:
|
|
110
116
|
"""A repository for message catalogs."""
|
|
111
117
|
|
|
112
|
-
def __init__(
|
|
113
|
-
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
basedir: str | os.PathLike[str],
|
|
121
|
+
locale_dirs: list[str],
|
|
122
|
+
language: str,
|
|
123
|
+
encoding: str,
|
|
124
|
+
) -> None:
|
|
114
125
|
self.basedir = basedir
|
|
115
126
|
self._locale_dirs = locale_dirs
|
|
116
127
|
self.language = language
|
|
@@ -199,13 +210,17 @@ date_format_mappings = {
|
|
|
199
210
|
'%z': 'ZZZ', # UTC offset in the form ±HHMM[SS[.ffffff]]
|
|
200
211
|
# (empty string if the object is naive).
|
|
201
212
|
'%%': '%',
|
|
202
|
-
}
|
|
213
|
+
} # fmt: skip
|
|
203
214
|
|
|
204
215
|
date_format_re = re.compile('(%s)' % '|'.join(date_format_mappings))
|
|
205
216
|
|
|
206
217
|
|
|
207
|
-
def babel_format_date(
|
|
208
|
-
|
|
218
|
+
def babel_format_date(
|
|
219
|
+
date: datetime,
|
|
220
|
+
format: str,
|
|
221
|
+
locale: str,
|
|
222
|
+
formatter: Formatter = babel.dates.format_date,
|
|
223
|
+
) -> str:
|
|
209
224
|
# Check if we have the tzinfo attribute. If not we cannot do any time
|
|
210
225
|
# related formats.
|
|
211
226
|
if not hasattr(date, 'tzinfo'):
|
|
@@ -217,22 +232,37 @@ def babel_format_date(date: datetime, format: str, locale: str,
|
|
|
217
232
|
# fallback to English
|
|
218
233
|
return formatter(date, format, locale='en')
|
|
219
234
|
except AttributeError:
|
|
220
|
-
logger.warning(
|
|
221
|
-
|
|
235
|
+
logger.warning(
|
|
236
|
+
__(
|
|
237
|
+
'Invalid date format. Quote the string by single quote '
|
|
238
|
+
'if you want to output it directly: %s'
|
|
239
|
+
),
|
|
240
|
+
format,
|
|
241
|
+
)
|
|
222
242
|
return format
|
|
223
243
|
|
|
224
244
|
|
|
225
245
|
def format_date(
|
|
226
|
-
format: str,
|
|
246
|
+
format: str,
|
|
247
|
+
*,
|
|
248
|
+
date: datetime | None = None,
|
|
249
|
+
language: str,
|
|
250
|
+
local_time: bool = False,
|
|
227
251
|
) -> str:
|
|
228
252
|
if date is None:
|
|
229
253
|
# If time is not specified, try to use $SOURCE_DATE_EPOCH variable
|
|
230
254
|
# See https://wiki.debian.org/ReproducibleBuilds/TimestampsProposal
|
|
231
255
|
source_date_epoch = os.getenv('SOURCE_DATE_EPOCH')
|
|
232
256
|
if source_date_epoch is not None:
|
|
233
|
-
date = datetime.fromtimestamp(float(source_date_epoch), tz=
|
|
257
|
+
date = datetime.fromtimestamp(float(source_date_epoch), tz=UTC)
|
|
234
258
|
else:
|
|
235
|
-
date = datetime.now(tz=
|
|
259
|
+
date = datetime.now(tz=UTC)
|
|
260
|
+
|
|
261
|
+
if local_time:
|
|
262
|
+
# > If called with tz=None, the system local time zone
|
|
263
|
+
# > is assumed for the target time zone.
|
|
264
|
+
# https://docs.python.org/dev/library/datetime.html#datetime.datetime.astimezone
|
|
265
|
+
date = date.astimezone(tz=None)
|
|
236
266
|
|
|
237
267
|
result = []
|
|
238
268
|
tokens = date_format_re.split(format)
|
|
@@ -251,12 +281,15 @@ def format_date(
|
|
|
251
281
|
else:
|
|
252
282
|
function = babel.dates.format_datetime
|
|
253
283
|
|
|
254
|
-
result.append(
|
|
255
|
-
|
|
284
|
+
result.append(
|
|
285
|
+
babel_format_date(
|
|
286
|
+
date, babel_format, locale=language, formatter=function
|
|
287
|
+
)
|
|
288
|
+
)
|
|
256
289
|
else:
|
|
257
290
|
result.append(token)
|
|
258
291
|
|
|
259
|
-
return
|
|
292
|
+
return ''.join(result)
|
|
260
293
|
|
|
261
294
|
|
|
262
295
|
def get_image_filename_for_language(
|