Sphinx 8.0.2__py3-none-any.whl → 8.1.1__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 +202 -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 +9 -2
- 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 +136 -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 +115 -50
- sphinx/texinputs/sphinxlatexadmonitions.sty +56 -38
- 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.1.dist-info/LICENSE.rst +31 -0
- {sphinx-8.0.2.dist-info → sphinx-8.1.1.dist-info}/METADATA +13 -11
- sphinx-8.1.1.dist-info/RECORD +598 -0
- sphinx-8.0.2.dist-info/LICENSE.rst +0 -67
- sphinx-8.0.2.dist-info/RECORD +0 -590
- {sphinx-8.0.2.dist-info → sphinx-8.1.1.dist-info}/WHEEL +0 -0
- {sphinx-8.0.2.dist-info → sphinx-8.1.1.dist-info}/entry_points.txt +0 -0
sphinx/builders/__init__.py
CHANGED
|
@@ -6,6 +6,7 @@ import codecs
|
|
|
6
6
|
import pickle
|
|
7
7
|
import re
|
|
8
8
|
import time
|
|
9
|
+
from contextlib import nullcontext
|
|
9
10
|
from os import path
|
|
10
11
|
from typing import TYPE_CHECKING, Any, Literal, final
|
|
11
12
|
|
|
@@ -16,21 +17,31 @@ from sphinx.environment import CONFIG_CHANGED_REASON, CONFIG_OK, BuildEnvironmen
|
|
|
16
17
|
from sphinx.environment.adapters.asset import ImageAdapter
|
|
17
18
|
from sphinx.errors import SphinxError
|
|
18
19
|
from sphinx.locale import __
|
|
19
|
-
from sphinx.util import
|
|
20
|
+
from sphinx.util import (
|
|
21
|
+
get_filetype,
|
|
22
|
+
logging,
|
|
23
|
+
rst,
|
|
24
|
+
)
|
|
25
|
+
from sphinx.util._importer import import_object
|
|
20
26
|
from sphinx.util.build_phase import BuildPhase
|
|
21
27
|
from sphinx.util.console import bold
|
|
22
28
|
from sphinx.util.display import progress_message, status_iterator
|
|
23
29
|
from sphinx.util.docutils import sphinx_domains
|
|
24
30
|
from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain
|
|
25
31
|
from sphinx.util.osutil import SEP, canon_path, ensuredir, relative_uri, relpath
|
|
26
|
-
from sphinx.util.parallel import
|
|
32
|
+
from sphinx.util.parallel import (
|
|
33
|
+
ParallelTasks,
|
|
34
|
+
SerialTasks,
|
|
35
|
+
make_chunks,
|
|
36
|
+
parallel_available,
|
|
37
|
+
)
|
|
27
38
|
|
|
28
39
|
# side effect: registers roles and directives
|
|
29
40
|
from sphinx import directives # NoQA: F401 isort:skip
|
|
30
41
|
from sphinx import roles # NoQA: F401 isort:skip
|
|
31
42
|
|
|
32
43
|
if TYPE_CHECKING:
|
|
33
|
-
from collections.abc import Iterable, Sequence
|
|
44
|
+
from collections.abc import Iterable, Sequence, Set
|
|
34
45
|
|
|
35
46
|
from docutils.nodes import Node
|
|
36
47
|
|
|
@@ -85,8 +96,7 @@ class Builder:
|
|
|
85
96
|
|
|
86
97
|
self.app: Sphinx = app
|
|
87
98
|
self.env: BuildEnvironment = env
|
|
88
|
-
self.env.set_versioning_method(self.versioning_method,
|
|
89
|
-
self.versioning_compare)
|
|
99
|
+
self.env.set_versioning_method(self.versioning_method, self.versioning_compare)
|
|
90
100
|
self.events: EventManager = app.events
|
|
91
101
|
self.config: Config = app.config
|
|
92
102
|
self.tags: Tags = app.tags
|
|
@@ -98,9 +108,9 @@ class Builder:
|
|
|
98
108
|
# images that need to be copied over (source -> dest)
|
|
99
109
|
self.images: dict[str, str] = {}
|
|
100
110
|
# basename of images directory
|
|
101
|
-
self.imagedir =
|
|
111
|
+
self.imagedir = ''
|
|
102
112
|
# relative path to image directory from current docname (used at writing docs)
|
|
103
|
-
self.imgpath =
|
|
113
|
+
self.imgpath = ''
|
|
104
114
|
|
|
105
115
|
# these get set later
|
|
106
116
|
self.parallel_ok = False
|
|
@@ -128,10 +138,14 @@ class Builder:
|
|
|
128
138
|
def create_template_bridge(self) -> None:
|
|
129
139
|
"""Return the template bridge configured."""
|
|
130
140
|
if self.config.template_bridge:
|
|
131
|
-
|
|
132
|
-
|
|
141
|
+
template_bridge_cls = import_object(
|
|
142
|
+
self.config.template_bridge,
|
|
143
|
+
source='template_bridge setting',
|
|
144
|
+
)
|
|
145
|
+
self.templates = template_bridge_cls()
|
|
133
146
|
else:
|
|
134
147
|
from sphinx.jinja2glue import BuiltinTemplateLoader
|
|
148
|
+
|
|
135
149
|
self.templates = BuiltinTemplateLoader()
|
|
136
150
|
|
|
137
151
|
def get_target_uri(self, docname: str, typ: str | None = None) -> str:
|
|
@@ -147,8 +161,10 @@ class Builder:
|
|
|
147
161
|
|
|
148
162
|
May raise environment.NoUri if there's no way to return a sensible URI.
|
|
149
163
|
"""
|
|
150
|
-
return relative_uri(
|
|
151
|
-
|
|
164
|
+
return relative_uri(
|
|
165
|
+
self.get_target_uri(from_),
|
|
166
|
+
self.get_target_uri(to, typ),
|
|
167
|
+
)
|
|
152
168
|
|
|
153
169
|
def get_outdated_docs(self) -> str | Iterable[str]:
|
|
154
170
|
"""Return an iterable of output files that are outdated, or a string
|
|
@@ -180,12 +196,20 @@ class Builder:
|
|
|
180
196
|
mimetypes = sorted(node['candidates'])
|
|
181
197
|
image_uri = images.get_original_image_uri(node['uri'])
|
|
182
198
|
if mimetypes:
|
|
183
|
-
logger.warning(
|
|
184
|
-
|
|
185
|
-
|
|
199
|
+
logger.warning(
|
|
200
|
+
__('a suitable image for %s builder not found: ' '%s (%s)'),
|
|
201
|
+
self.name,
|
|
202
|
+
mimetypes,
|
|
203
|
+
image_uri,
|
|
204
|
+
location=node,
|
|
205
|
+
)
|
|
186
206
|
else:
|
|
187
|
-
logger.warning(
|
|
188
|
-
|
|
207
|
+
logger.warning(
|
|
208
|
+
__('a suitable image for %s builder not found: %s'),
|
|
209
|
+
self.name,
|
|
210
|
+
image_uri,
|
|
211
|
+
location=node,
|
|
212
|
+
)
|
|
189
213
|
continue
|
|
190
214
|
node['uri'] = candidate
|
|
191
215
|
else:
|
|
@@ -205,15 +229,25 @@ class Builder:
|
|
|
205
229
|
return relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
|
|
206
230
|
|
|
207
231
|
logger.info(bold(__('building [mo]: ')) + message)
|
|
208
|
-
for catalog in status_iterator(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
232
|
+
for catalog in status_iterator(
|
|
233
|
+
catalogs,
|
|
234
|
+
__('writing output... '),
|
|
235
|
+
'darkgreen',
|
|
236
|
+
len(catalogs),
|
|
237
|
+
self.app.verbosity,
|
|
238
|
+
stringify_func=cat2relpath,
|
|
239
|
+
):
|
|
240
|
+
catalog.write_mo(
|
|
241
|
+
self.config.language, self.config.gettext_allow_fuzzy_translations
|
|
242
|
+
)
|
|
213
243
|
|
|
214
244
|
def compile_all_catalogs(self) -> None:
|
|
215
|
-
repo = CatalogRepository(
|
|
216
|
-
|
|
245
|
+
repo = CatalogRepository(
|
|
246
|
+
self.srcdir,
|
|
247
|
+
self.config.locale_dirs,
|
|
248
|
+
self.config.language,
|
|
249
|
+
self.config.source_encoding,
|
|
250
|
+
)
|
|
217
251
|
message = __('all of %d po files') % len(list(repo.catalogs))
|
|
218
252
|
self.compile_catalogs(set(repo.catalogs), message)
|
|
219
253
|
|
|
@@ -227,8 +261,12 @@ class Builder:
|
|
|
227
261
|
|
|
228
262
|
catalogs = set()
|
|
229
263
|
domains = set(map(to_domain, specified_files))
|
|
230
|
-
repo = CatalogRepository(
|
|
231
|
-
|
|
264
|
+
repo = CatalogRepository(
|
|
265
|
+
self.srcdir,
|
|
266
|
+
self.config.locale_dirs,
|
|
267
|
+
self.config.language,
|
|
268
|
+
self.config.source_encoding,
|
|
269
|
+
)
|
|
232
270
|
for catalog in repo.catalogs:
|
|
233
271
|
if catalog.domain in domains and catalog.is_outdated():
|
|
234
272
|
catalogs.add(catalog)
|
|
@@ -237,8 +275,12 @@ class Builder:
|
|
|
237
275
|
|
|
238
276
|
# TODO(stephenfin): This would make more sense as 'compile_outdated_catalogs'
|
|
239
277
|
def compile_update_catalogs(self) -> None:
|
|
240
|
-
repo = CatalogRepository(
|
|
241
|
-
|
|
278
|
+
repo = CatalogRepository(
|
|
279
|
+
self.srcdir,
|
|
280
|
+
self.config.locale_dirs,
|
|
281
|
+
self.config.language,
|
|
282
|
+
self.config.source_encoding,
|
|
283
|
+
)
|
|
242
284
|
catalogs = {c for c in repo.catalogs if c.is_outdated()}
|
|
243
285
|
message = __('targets for %d po files that are out of date') % len(catalogs)
|
|
244
286
|
self.compile_catalogs(catalogs, message)
|
|
@@ -261,27 +303,41 @@ class Builder:
|
|
|
261
303
|
filename = path.normpath(path.abspath(filename))
|
|
262
304
|
|
|
263
305
|
if not path.isfile(filename):
|
|
264
|
-
logger.warning(
|
|
265
|
-
|
|
306
|
+
logger.warning(
|
|
307
|
+
__('file %r given on command line does not exist, '), filename
|
|
308
|
+
)
|
|
266
309
|
continue
|
|
267
310
|
|
|
268
311
|
if not filename.startswith(str(self.srcdir)):
|
|
269
|
-
logger.warning(
|
|
270
|
-
|
|
312
|
+
logger.warning(
|
|
313
|
+
__(
|
|
314
|
+
'file %r given on command line is not under the '
|
|
315
|
+
'source directory, ignoring'
|
|
316
|
+
),
|
|
317
|
+
filename,
|
|
318
|
+
)
|
|
271
319
|
continue
|
|
272
320
|
|
|
273
321
|
docname = self.env.path2doc(filename)
|
|
274
322
|
if not docname:
|
|
275
|
-
logger.warning(
|
|
276
|
-
|
|
323
|
+
logger.warning(
|
|
324
|
+
__(
|
|
325
|
+
'file %r given on command line is not a valid '
|
|
326
|
+
'document, ignoring'
|
|
327
|
+
),
|
|
328
|
+
filename,
|
|
329
|
+
)
|
|
277
330
|
continue
|
|
278
331
|
|
|
279
332
|
docnames.append(docname)
|
|
280
333
|
|
|
281
334
|
self.compile_specific_catalogs(filenames)
|
|
282
335
|
|
|
283
|
-
self.build(
|
|
284
|
-
|
|
336
|
+
self.build(
|
|
337
|
+
docnames,
|
|
338
|
+
method='specific',
|
|
339
|
+
summary=__('%d source files given on command line') % len(docnames),
|
|
340
|
+
)
|
|
285
341
|
|
|
286
342
|
@final
|
|
287
343
|
def build_update(self) -> None:
|
|
@@ -293,9 +349,11 @@ class Builder:
|
|
|
293
349
|
self.build(['__all__'], to_build)
|
|
294
350
|
else:
|
|
295
351
|
to_build = list(to_build)
|
|
296
|
-
self.build(
|
|
297
|
-
|
|
298
|
-
|
|
352
|
+
self.build(
|
|
353
|
+
to_build,
|
|
354
|
+
summary=__('targets for %d source files that are out of date')
|
|
355
|
+
% len(to_build),
|
|
356
|
+
)
|
|
299
357
|
|
|
300
358
|
@final
|
|
301
359
|
def build(
|
|
@@ -313,7 +371,11 @@ class Builder:
|
|
|
313
371
|
logger.info(bold(__('building [%s]: ')) + summary, self.name)
|
|
314
372
|
|
|
315
373
|
# while reading, collect all warnings from docutils
|
|
316
|
-
with
|
|
374
|
+
with (
|
|
375
|
+
nullcontext()
|
|
376
|
+
if self.app._exception_on_warning
|
|
377
|
+
else logging.pending_warnings()
|
|
378
|
+
):
|
|
317
379
|
updated_docnames = set(self.read())
|
|
318
380
|
|
|
319
381
|
doccount = len(updated_docnames)
|
|
@@ -328,8 +390,11 @@ class Builder:
|
|
|
328
390
|
if updated_docnames:
|
|
329
391
|
# save the environment
|
|
330
392
|
from sphinx.application import ENV_PICKLE_FILENAME
|
|
331
|
-
|
|
332
|
-
|
|
393
|
+
|
|
394
|
+
with (
|
|
395
|
+
progress_message(__('pickling environment')),
|
|
396
|
+
open(path.join(self.doctreedir, ENV_PICKLE_FILENAME), 'wb') as f,
|
|
397
|
+
):
|
|
333
398
|
pickle.dump(self.env, f, pickle.HIGHEST_PROTOCOL)
|
|
334
399
|
|
|
335
400
|
# global actions
|
|
@@ -381,11 +446,13 @@ class Builder:
|
|
|
381
446
|
logger.info(bold(__('updating environment: ')), nonl=True)
|
|
382
447
|
|
|
383
448
|
self.env.find_files(self.config, self)
|
|
384
|
-
updated =
|
|
449
|
+
updated = self.env.config_status != CONFIG_OK
|
|
385
450
|
added, changed, removed = self.env.get_outdated_files(updated)
|
|
386
451
|
|
|
387
452
|
# allow user intervention as well
|
|
388
|
-
for docs in self.events.emit(
|
|
453
|
+
for docs in self.events.emit(
|
|
454
|
+
'env-get-outdated', self.env, added, changed, removed
|
|
455
|
+
):
|
|
389
456
|
changed.update(set(docs) & self.env.found_docs)
|
|
390
457
|
|
|
391
458
|
# if files were added or removed, all documents with globbed toctrees
|
|
@@ -395,12 +462,17 @@ class Builder:
|
|
|
395
462
|
changed.update(self.env.glob_toctrees & self.env.found_docs)
|
|
396
463
|
|
|
397
464
|
if updated: # explain the change iff build config status was not ok
|
|
398
|
-
reason =
|
|
399
|
-
|
|
465
|
+
reason = CONFIG_CHANGED_REASON.get(self.env.config_status, '') + (
|
|
466
|
+
self.env.config_status_extra or ''
|
|
467
|
+
)
|
|
400
468
|
logger.info('[%s] ', reason, nonl=True)
|
|
401
469
|
|
|
402
|
-
logger.info(
|
|
403
|
-
|
|
470
|
+
logger.info(
|
|
471
|
+
__('%s added, %s changed, %s removed'),
|
|
472
|
+
len(added),
|
|
473
|
+
len(changed),
|
|
474
|
+
len(removed),
|
|
475
|
+
)
|
|
404
476
|
|
|
405
477
|
# clear all files no longer present
|
|
406
478
|
for docname in removed:
|
|
@@ -413,7 +485,7 @@ class Builder:
|
|
|
413
485
|
self.events.emit('env-before-read-docs', self.env, docnames)
|
|
414
486
|
|
|
415
487
|
# check if we should do parallel or serial read
|
|
416
|
-
if parallel_available and
|
|
488
|
+
if parallel_available and self.app.parallel > 1:
|
|
417
489
|
par_ok = self.app.is_parallel_allowed('read')
|
|
418
490
|
else:
|
|
419
491
|
par_ok = False
|
|
@@ -432,30 +504,38 @@ class Builder:
|
|
|
432
504
|
for pat in EXCLUDE_PATHS:
|
|
433
505
|
if not re.match(_translate_pattern(pat), master_doc_canon):
|
|
434
506
|
continue
|
|
435
|
-
msg = __(
|
|
436
|
-
|
|
437
|
-
|
|
507
|
+
msg = __(
|
|
508
|
+
'Sphinx is unable to load the master document (%s) '
|
|
509
|
+
'because it matches a built-in exclude pattern %r. '
|
|
510
|
+
'Please move your master document to a different location.'
|
|
511
|
+
)
|
|
438
512
|
raise SphinxError(msg % (master_doc_path, pat))
|
|
439
513
|
for pat in self.config.exclude_patterns:
|
|
440
514
|
if not re.match(_translate_pattern(pat), master_doc_canon):
|
|
441
515
|
continue
|
|
442
|
-
msg = __(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
516
|
+
msg = __(
|
|
517
|
+
'Sphinx is unable to load the master document (%s) '
|
|
518
|
+
'because it matches an exclude pattern specified '
|
|
519
|
+
'in conf.py, %r. '
|
|
520
|
+
'Please remove this pattern from conf.py.'
|
|
521
|
+
)
|
|
446
522
|
raise SphinxError(msg % (master_doc_path, pat))
|
|
447
523
|
if set(self.config.include_patterns) != {'**'} and not any(
|
|
448
524
|
re.match(_translate_pattern(pat), master_doc_canon)
|
|
449
525
|
for pat in self.config.include_patterns
|
|
450
526
|
):
|
|
451
|
-
msg = __(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
527
|
+
msg = __(
|
|
528
|
+
'Sphinx is unable to load the master document (%s) '
|
|
529
|
+
'because it is not included in the custom include_patterns = %r. '
|
|
530
|
+
'Ensure that a pattern in include_patterns matches the '
|
|
531
|
+
'master document.'
|
|
532
|
+
)
|
|
455
533
|
raise SphinxError(msg % (master_doc_path, self.config.include_patterns))
|
|
456
|
-
msg = __(
|
|
457
|
-
|
|
458
|
-
|
|
534
|
+
msg = __(
|
|
535
|
+
'Sphinx is unable to load the master document (%s). '
|
|
536
|
+
'The master document must be within the source directory '
|
|
537
|
+
'or a subdirectory of it.'
|
|
538
|
+
)
|
|
459
539
|
raise SphinxError(msg % master_doc_path)
|
|
460
540
|
|
|
461
541
|
for retval in self.events.emit('env-updated', self.env):
|
|
@@ -468,8 +548,13 @@ class Builder:
|
|
|
468
548
|
return sorted(docnames)
|
|
469
549
|
|
|
470
550
|
def _read_serial(self, docnames: list[str]) -> None:
|
|
471
|
-
for docname in status_iterator(
|
|
472
|
-
|
|
551
|
+
for docname in status_iterator(
|
|
552
|
+
docnames,
|
|
553
|
+
__('reading sources... '),
|
|
554
|
+
'purple',
|
|
555
|
+
len(docnames),
|
|
556
|
+
self.app.verbosity,
|
|
557
|
+
):
|
|
473
558
|
# remove all inventory entries for that file
|
|
474
559
|
self.events.emit('env-purge-doc', self.env, docname)
|
|
475
560
|
self.env.clear_doc(docname)
|
|
@@ -480,8 +565,9 @@ class Builder:
|
|
|
480
565
|
|
|
481
566
|
# create a status_iterator to step progressbar after reading a document
|
|
482
567
|
# (see: ``merge()`` function)
|
|
483
|
-
progress = status_iterator(
|
|
484
|
-
|
|
568
|
+
progress = status_iterator(
|
|
569
|
+
chunks, __('reading sources... '), 'purple', len(chunks), self.app.verbosity
|
|
570
|
+
)
|
|
485
571
|
|
|
486
572
|
# clear all outdated docs at once
|
|
487
573
|
for docname in docnames:
|
|
@@ -526,10 +612,13 @@ class Builder:
|
|
|
526
612
|
# record_dependencies is mutable even though it is in settings,
|
|
527
613
|
# explicitly re-initialise for each document
|
|
528
614
|
publisher.settings.record_dependencies = DependencyList()
|
|
529
|
-
with
|
|
615
|
+
with (
|
|
616
|
+
sphinx_domains(self.env),
|
|
617
|
+
rst.default_role(docname, self.config.default_role),
|
|
618
|
+
):
|
|
530
619
|
# set up error_handler for the target document
|
|
531
|
-
|
|
532
|
-
|
|
620
|
+
error_handler = _UnicodeDecodeErrorHandler(docname)
|
|
621
|
+
codecs.register_error('sphinx', error_handler) # type: ignore[arg-type]
|
|
533
622
|
|
|
534
623
|
publisher.set_source(source_path=filename)
|
|
535
624
|
publisher.publish()
|
|
@@ -546,7 +635,11 @@ class Builder:
|
|
|
546
635
|
|
|
547
636
|
@final
|
|
548
637
|
def write_doctree(
|
|
549
|
-
self,
|
|
638
|
+
self,
|
|
639
|
+
docname: str,
|
|
640
|
+
doctree: nodes.document,
|
|
641
|
+
*,
|
|
642
|
+
_cache: bool = True,
|
|
550
643
|
) -> None:
|
|
551
644
|
"""Write the doctree to a file, to be used as a cache by re-builds."""
|
|
552
645
|
# make it picklable
|
|
@@ -571,6 +664,7 @@ class Builder:
|
|
|
571
664
|
if _cache:
|
|
572
665
|
self.env._write_doc_doctree_cache[docname] = doctree
|
|
573
666
|
|
|
667
|
+
@final
|
|
574
668
|
def write(
|
|
575
669
|
self,
|
|
576
670
|
build_docnames: Iterable[str] | None,
|
|
@@ -592,11 +686,15 @@ class Builder:
|
|
|
592
686
|
logger.debug(__('docnames to write: %s'), ', '.join(sorted(docnames)))
|
|
593
687
|
|
|
594
688
|
# add all toctree-containing files that may have changed
|
|
595
|
-
|
|
689
|
+
extra = {self.config.root_doc}
|
|
690
|
+
for docname in docnames:
|
|
596
691
|
for tocdocname in self.env.files_to_rebuild.get(docname, set()):
|
|
597
692
|
if tocdocname in self.env.found_docs:
|
|
598
|
-
|
|
599
|
-
docnames
|
|
693
|
+
extra.add(tocdocname)
|
|
694
|
+
docnames |= extra
|
|
695
|
+
|
|
696
|
+
# sort to ensure deterministic toctree generation
|
|
697
|
+
self.env.toctree_includes = dict(sorted(self.env.toctree_includes.items()))
|
|
600
698
|
|
|
601
699
|
with progress_message(__('preparing documents')):
|
|
602
700
|
self.prepare_writing(docnames)
|
|
@@ -604,18 +702,35 @@ class Builder:
|
|
|
604
702
|
with progress_message(__('copying assets'), nonl=False):
|
|
605
703
|
self.copy_assets()
|
|
606
704
|
|
|
705
|
+
self.write_documents(docnames)
|
|
706
|
+
|
|
707
|
+
def write_documents(self, docnames: Set[str]) -> None:
|
|
708
|
+
"""Write all documents in *docnames*.
|
|
709
|
+
|
|
710
|
+
This method can be overridden if a builder does not create
|
|
711
|
+
output files for each document.
|
|
712
|
+
"""
|
|
713
|
+
sorted_docnames = sorted(docnames)
|
|
607
714
|
if self.parallel_ok:
|
|
608
715
|
# number of subprocesses is parallel-1 because the main process
|
|
609
716
|
# is busy loading doctrees and doing write_doc_serialized()
|
|
610
|
-
self._write_parallel(
|
|
611
|
-
nproc=self.app.parallel - 1)
|
|
717
|
+
self._write_parallel(sorted_docnames, nproc=self.app.parallel - 1)
|
|
612
718
|
else:
|
|
613
|
-
self._write_serial(
|
|
719
|
+
self._write_serial(sorted_docnames)
|
|
614
720
|
|
|
615
721
|
def _write_serial(self, docnames: Sequence[str]) -> None:
|
|
616
|
-
with
|
|
617
|
-
|
|
618
|
-
|
|
722
|
+
with (
|
|
723
|
+
nullcontext()
|
|
724
|
+
if self.app._exception_on_warning
|
|
725
|
+
else logging.pending_warnings()
|
|
726
|
+
):
|
|
727
|
+
for docname in status_iterator(
|
|
728
|
+
docnames,
|
|
729
|
+
__('writing output... '),
|
|
730
|
+
'darkgreen',
|
|
731
|
+
len(docnames),
|
|
732
|
+
self.app.verbosity,
|
|
733
|
+
):
|
|
619
734
|
self.app.phase = BuildPhase.RESOLVING
|
|
620
735
|
doctree = self.env.get_and_resolve_doctree(docname, self)
|
|
621
736
|
self.app.phase = BuildPhase.WRITING
|
|
@@ -641,8 +756,13 @@ class Builder:
|
|
|
641
756
|
|
|
642
757
|
# create a status_iterator to step progressbar after writing a document
|
|
643
758
|
# (see: ``on_chunk_done()`` function)
|
|
644
|
-
progress = status_iterator(
|
|
645
|
-
|
|
759
|
+
progress = status_iterator(
|
|
760
|
+
chunks,
|
|
761
|
+
__('writing output... '),
|
|
762
|
+
'darkgreen',
|
|
763
|
+
len(chunks),
|
|
764
|
+
self.app.verbosity,
|
|
765
|
+
)
|
|
646
766
|
|
|
647
767
|
def on_chunk_done(args: list[tuple[str, nodes.document]], result: None) -> None:
|
|
648
768
|
next(progress)
|
|
@@ -660,9 +780,9 @@ class Builder:
|
|
|
660
780
|
tasks.join()
|
|
661
781
|
logger.info('')
|
|
662
782
|
|
|
663
|
-
def prepare_writing(self, docnames:
|
|
783
|
+
def prepare_writing(self, docnames: Set[str]) -> None:
|
|
664
784
|
"""A place where you can add logic before :meth:`write_doc` is run"""
|
|
665
|
-
|
|
785
|
+
pass
|
|
666
786
|
|
|
667
787
|
def copy_assets(self) -> None:
|
|
668
788
|
"""Where assets (images, static files, etc) are copied before writing"""
|
|
@@ -707,3 +827,29 @@ class Builder:
|
|
|
707
827
|
except AttributeError:
|
|
708
828
|
optname = f'{default}_{option}'
|
|
709
829
|
return getattr(self.config, optname)
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
class _UnicodeDecodeErrorHandler:
|
|
833
|
+
"""Custom error handler for open() that warns and replaces."""
|
|
834
|
+
|
|
835
|
+
def __init__(self, docname: str, /) -> None:
|
|
836
|
+
self.docname = docname
|
|
837
|
+
|
|
838
|
+
def __call__(self, error: UnicodeDecodeError) -> tuple[str, int]:
|
|
839
|
+
line_start = error.object.rfind(b'\n', 0, error.start)
|
|
840
|
+
line_end = error.object.find(b'\n', error.start)
|
|
841
|
+
if line_end == -1:
|
|
842
|
+
line_end = len(error.object)
|
|
843
|
+
line_num = error.object.count(b'\n', 0, error.start) + 1
|
|
844
|
+
logger.warning(
|
|
845
|
+
__('undecodable source characters, replacing with "?": %r'),
|
|
846
|
+
(
|
|
847
|
+
error.object[line_start + 1 : error.start]
|
|
848
|
+
+ b'>>>'
|
|
849
|
+
+ error.object[error.start : error.end]
|
|
850
|
+
+ b'<<<'
|
|
851
|
+
+ error.object[error.end : line_end]
|
|
852
|
+
),
|
|
853
|
+
location=(self.docname, line_num),
|
|
854
|
+
)
|
|
855
|
+
return '?', error.end
|