Sphinx 8.0.2__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 +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 +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.2.dist-info → sphinx-8.1.0.dist-info}/METADATA +13 -11
- sphinx-8.1.0.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.0.dist-info}/WHEEL +0 -0
- {sphinx-8.0.2.dist-info → sphinx-8.1.0.dist-info}/entry_points.txt +0 -0
sphinx/roles.py
CHANGED
|
@@ -88,15 +88,15 @@ class XRefRole(ReferenceRole):
|
|
|
88
88
|
|
|
89
89
|
def update_title_and_target(self, title: str, target: str) -> tuple[str, str]:
|
|
90
90
|
if not self.has_explicit_title:
|
|
91
|
-
if title.endswith('()'):
|
|
92
|
-
# remove parentheses
|
|
93
|
-
title = title[:-2]
|
|
94
91
|
if self.config.add_function_parentheses:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
if not title.endswith('()'):
|
|
93
|
+
# add parentheses to the title
|
|
94
|
+
title += '()'
|
|
95
|
+
else:
|
|
96
|
+
# remove parentheses
|
|
97
|
+
title = title.removesuffix('()')
|
|
98
|
+
# remove parentheses from the target
|
|
99
|
+
target = target.removesuffix('()')
|
|
100
100
|
return title, target
|
|
101
101
|
|
|
102
102
|
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
@@ -167,7 +167,11 @@ class XRefRole(ReferenceRole):
|
|
|
167
167
|
return title, ws_re.sub(' ', target)
|
|
168
168
|
|
|
169
169
|
def result_nodes(
|
|
170
|
-
self,
|
|
170
|
+
self,
|
|
171
|
+
document: nodes.document,
|
|
172
|
+
env: BuildEnvironment,
|
|
173
|
+
node: Element,
|
|
174
|
+
is_ref: bool,
|
|
171
175
|
) -> tuple[list[Node], list[system_message]]:
|
|
172
176
|
"""Called before returning the finished nodes. *node* is the reference
|
|
173
177
|
node if one was created (*is_ref* is then true), else the content node.
|
|
@@ -192,6 +196,94 @@ class AnyXRefRole(XRefRole):
|
|
|
192
196
|
return result
|
|
193
197
|
|
|
194
198
|
|
|
199
|
+
class CVE(ReferenceRole):
|
|
200
|
+
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
201
|
+
target_id = f'index-{self.env.new_serialno("index")}'
|
|
202
|
+
entries = [
|
|
203
|
+
(
|
|
204
|
+
'single',
|
|
205
|
+
_('Common Vulnerabilities and Exposures; CVE %s') % self.target,
|
|
206
|
+
target_id,
|
|
207
|
+
'',
|
|
208
|
+
None,
|
|
209
|
+
)
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
index = addnodes.index(entries=entries)
|
|
213
|
+
target = nodes.target('', '', ids=[target_id])
|
|
214
|
+
self.inliner.document.note_explicit_target(target)
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
refuri = self.build_uri()
|
|
218
|
+
reference = nodes.reference(
|
|
219
|
+
'', '', internal=False, refuri=refuri, classes=['cve']
|
|
220
|
+
)
|
|
221
|
+
if self.has_explicit_title:
|
|
222
|
+
reference += nodes.strong(self.title, self.title)
|
|
223
|
+
else:
|
|
224
|
+
title = f'CVE {self.title}'
|
|
225
|
+
reference += nodes.strong(title, title)
|
|
226
|
+
except ValueError:
|
|
227
|
+
msg = self.inliner.reporter.error(
|
|
228
|
+
__('invalid CVE number %s') % self.target, line=self.lineno
|
|
229
|
+
)
|
|
230
|
+
prb = self.inliner.problematic(self.rawtext, self.rawtext, msg)
|
|
231
|
+
return [prb], [msg]
|
|
232
|
+
|
|
233
|
+
return [index, target, reference], []
|
|
234
|
+
|
|
235
|
+
def build_uri(self) -> str:
|
|
236
|
+
base_url = self.inliner.document.settings.cve_base_url
|
|
237
|
+
ret = self.target.split('#', 1)
|
|
238
|
+
if len(ret) == 2:
|
|
239
|
+
return f'{base_url}{ret[0]}#{ret[1]}'
|
|
240
|
+
return f'{base_url}{ret[0]}'
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class CWE(ReferenceRole):
|
|
244
|
+
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
245
|
+
target_id = f'index-{self.env.new_serialno("index")}'
|
|
246
|
+
entries = [
|
|
247
|
+
(
|
|
248
|
+
'single',
|
|
249
|
+
_('Common Weakness Enumeration; CWE %s') % self.target,
|
|
250
|
+
target_id,
|
|
251
|
+
'',
|
|
252
|
+
None,
|
|
253
|
+
)
|
|
254
|
+
]
|
|
255
|
+
|
|
256
|
+
index = addnodes.index(entries=entries)
|
|
257
|
+
target = nodes.target('', '', ids=[target_id])
|
|
258
|
+
self.inliner.document.note_explicit_target(target)
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
refuri = self.build_uri()
|
|
262
|
+
reference = nodes.reference(
|
|
263
|
+
'', '', internal=False, refuri=refuri, classes=['cwe']
|
|
264
|
+
)
|
|
265
|
+
if self.has_explicit_title:
|
|
266
|
+
reference += nodes.strong(self.title, self.title)
|
|
267
|
+
else:
|
|
268
|
+
title = f'CWE {self.title}'
|
|
269
|
+
reference += nodes.strong(title, title)
|
|
270
|
+
except ValueError:
|
|
271
|
+
msg = self.inliner.reporter.error(
|
|
272
|
+
__('invalid CWE number %s') % self.target, line=self.lineno
|
|
273
|
+
)
|
|
274
|
+
prb = self.inliner.problematic(self.rawtext, self.rawtext, msg)
|
|
275
|
+
return [prb], [msg]
|
|
276
|
+
|
|
277
|
+
return [index, target, reference], []
|
|
278
|
+
|
|
279
|
+
def build_uri(self) -> str:
|
|
280
|
+
base_url = self.inliner.document.settings.cwe_base_url
|
|
281
|
+
ret = self.target.split('#', 1)
|
|
282
|
+
if len(ret) == 2:
|
|
283
|
+
return f'{base_url}{int(ret[0])}.html#{ret[1]}'
|
|
284
|
+
return f'{base_url}{int(ret[0])}.html'
|
|
285
|
+
|
|
286
|
+
|
|
195
287
|
class PEP(ReferenceRole):
|
|
196
288
|
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
197
289
|
target_id = 'index-%s' % self.env.new_serialno('index')
|
|
@@ -211,7 +303,9 @@ class PEP(ReferenceRole):
|
|
|
211
303
|
|
|
212
304
|
try:
|
|
213
305
|
refuri = self.build_uri()
|
|
214
|
-
reference = nodes.reference(
|
|
306
|
+
reference = nodes.reference(
|
|
307
|
+
'', '', internal=False, refuri=refuri, classes=['pep']
|
|
308
|
+
)
|
|
215
309
|
if self.has_explicit_title:
|
|
216
310
|
reference += nodes.strong(self.title, self.title)
|
|
217
311
|
else:
|
|
@@ -238,7 +332,8 @@ class PEP(ReferenceRole):
|
|
|
238
332
|
class RFC(ReferenceRole):
|
|
239
333
|
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
240
334
|
target_id = 'index-%s' % self.env.new_serialno('index')
|
|
241
|
-
|
|
335
|
+
formatted_target = _format_rfc_target(self.target)
|
|
336
|
+
entries = [('single', f'RFC; {formatted_target}', target_id, '', None)]
|
|
242
337
|
|
|
243
338
|
index = addnodes.index(entries=entries)
|
|
244
339
|
target = nodes.target('', '', ids=[target_id])
|
|
@@ -246,11 +341,13 @@ class RFC(ReferenceRole):
|
|
|
246
341
|
|
|
247
342
|
try:
|
|
248
343
|
refuri = self.build_uri()
|
|
249
|
-
reference = nodes.reference(
|
|
344
|
+
reference = nodes.reference(
|
|
345
|
+
'', '', internal=False, refuri=refuri, classes=['rfc']
|
|
346
|
+
)
|
|
250
347
|
if self.has_explicit_title:
|
|
251
348
|
reference += nodes.strong(self.title, self.title)
|
|
252
349
|
else:
|
|
253
|
-
title =
|
|
350
|
+
title = formatted_target
|
|
254
351
|
reference += nodes.strong(title, title)
|
|
255
352
|
except ValueError:
|
|
256
353
|
msg = self.inliner.reporter.error(
|
|
@@ -270,6 +367,24 @@ class RFC(ReferenceRole):
|
|
|
270
367
|
return base_url + self.inliner.rfc_url % int(ret[0])
|
|
271
368
|
|
|
272
369
|
|
|
370
|
+
def _format_rfc_target(target: str, /) -> str:
|
|
371
|
+
"""
|
|
372
|
+
Takes an RFC number with an optional anchor (like ``123#section-2.5.3``)
|
|
373
|
+
and attempts to produce a human-friendly title for it.
|
|
374
|
+
|
|
375
|
+
We have a set of known anchors that we format nicely,
|
|
376
|
+
everything else we leave alone.
|
|
377
|
+
"""
|
|
378
|
+
number, _, anchor = target.partition('#')
|
|
379
|
+
if anchor:
|
|
380
|
+
first, _, remaining = anchor.partition('-')
|
|
381
|
+
if first in {'appendix', 'page', 'section'}:
|
|
382
|
+
if remaining:
|
|
383
|
+
return f'RFC {number} {first.title()} {remaining}'
|
|
384
|
+
return f'RFC {number} {first.title()}'
|
|
385
|
+
return f'RFC {target}'
|
|
386
|
+
|
|
387
|
+
|
|
273
388
|
class GUILabel(SphinxRole):
|
|
274
389
|
amp_re = re.compile(r'(?<!&)&(?![&\s])')
|
|
275
390
|
|
|
@@ -446,12 +561,17 @@ specific_docroles: dict[str, RoleFunction] = {
|
|
|
446
561
|
'download': XRefRole(nodeclass=addnodes.download_reference),
|
|
447
562
|
# links to anything
|
|
448
563
|
'any': AnyXRefRole(warn_dangling=True),
|
|
564
|
+
# external links
|
|
565
|
+
'cve': CVE(),
|
|
566
|
+
'cwe': CWE(),
|
|
449
567
|
'pep': PEP(),
|
|
450
568
|
'rfc': RFC(),
|
|
569
|
+
# emphasised things
|
|
451
570
|
'guilabel': GUILabel(),
|
|
452
571
|
'menuselection': MenuSelection(),
|
|
453
572
|
'file': EmphasizedLiteral(),
|
|
454
573
|
'samp': EmphasizedLiteral(),
|
|
574
|
+
# other
|
|
455
575
|
'abbr': Abbreviation(),
|
|
456
576
|
'manpage': Manpage(),
|
|
457
577
|
}
|
sphinx/search/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Create a full-text search index for offline search."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
import dataclasses
|
|
@@ -15,11 +16,12 @@ from docutils import nodes
|
|
|
15
16
|
from docutils.nodes import Element, Node
|
|
16
17
|
|
|
17
18
|
from sphinx import addnodes, package_dir
|
|
18
|
-
from sphinx.environment import BuildEnvironment
|
|
19
19
|
from sphinx.util.index_entries import split_index_msg
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from collections.abc import Iterable
|
|
22
|
+
from collections.abc import Callable, Iterable
|
|
23
|
+
|
|
24
|
+
from sphinx.environment import BuildEnvironment
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
class SearchLanguage:
|
|
@@ -52,10 +54,11 @@ class SearchLanguage:
|
|
|
52
54
|
This class is used to preprocess search word which Sphinx HTML readers
|
|
53
55
|
type, before searching index. Default implementation does nothing.
|
|
54
56
|
"""
|
|
57
|
+
|
|
55
58
|
lang: str = ''
|
|
56
59
|
language_name: str = ''
|
|
57
60
|
stopwords: set[str] = set()
|
|
58
|
-
js_splitter_code: str =
|
|
61
|
+
js_splitter_code: str = ''
|
|
59
62
|
js_stemmer_rawcode: str = ''
|
|
60
63
|
js_stemmer_code = """
|
|
61
64
|
/**
|
|
@@ -105,16 +108,14 @@ var Stemmer = function() {
|
|
|
105
108
|
Return true if the target word should be registered in the search index.
|
|
106
109
|
This method is called after stemming.
|
|
107
110
|
"""
|
|
108
|
-
return (
|
|
109
|
-
len(word)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
word in self.stopwords
|
|
113
|
-
))))
|
|
111
|
+
return len(word) == 0 or not (
|
|
112
|
+
((len(word) < 3) and (12353 < ord(word[0]) < 12436))
|
|
113
|
+
or (ord(word[0]) < 256 and (word in self.stopwords))
|
|
114
|
+
)
|
|
114
115
|
|
|
115
116
|
|
|
116
117
|
# SearchEnglish imported after SearchLanguage is defined due to circular import
|
|
117
|
-
from sphinx.search.en import SearchEnglish
|
|
118
|
+
from sphinx.search.en import SearchEnglish # NoQA: E402
|
|
118
119
|
|
|
119
120
|
|
|
120
121
|
def parse_stop_word(source: str) -> set[str]:
|
|
@@ -165,10 +166,10 @@ class _JavaScriptIndex:
|
|
|
165
166
|
return self.PREFIX + json.dumps(data, sort_keys=True) + self.SUFFIX
|
|
166
167
|
|
|
167
168
|
def loads(self, s: str) -> Any:
|
|
168
|
-
data = s[len(self.PREFIX)
|
|
169
|
-
if not data or not s.startswith(self.PREFIX) or not
|
|
170
|
-
|
|
171
|
-
raise ValueError(
|
|
169
|
+
data = s[len(self.PREFIX) : -len(self.SUFFIX)]
|
|
170
|
+
if not data or not s.startswith(self.PREFIX) or not s.endswith(self.SUFFIX):
|
|
171
|
+
msg = 'invalid data'
|
|
172
|
+
raise ValueError(msg)
|
|
172
173
|
return json.loads(data)
|
|
173
174
|
|
|
174
175
|
def dump(self, data: Any, f: IO[str]) -> None:
|
|
@@ -187,9 +188,8 @@ def _is_meta_keywords(
|
|
|
187
188
|
) -> bool:
|
|
188
189
|
if node.get('name') == 'keywords':
|
|
189
190
|
meta_lang = node.get('lang')
|
|
190
|
-
if meta_lang is None
|
|
191
|
-
|
|
192
|
-
elif meta_lang == lang: # matched to html_search_language
|
|
191
|
+
if meta_lang is None or meta_lang == lang:
|
|
192
|
+
# lang not specified or matched to html_search_language
|
|
193
193
|
return True
|
|
194
194
|
|
|
195
195
|
return False
|
|
@@ -222,8 +222,18 @@ class WordCollector(nodes.NodeVisitor):
|
|
|
222
222
|
# Some people might put content in raw HTML that should be searched,
|
|
223
223
|
# so we just amateurishly strip HTML tags and index the remaining
|
|
224
224
|
# content
|
|
225
|
-
nodetext = re.sub(
|
|
226
|
-
|
|
225
|
+
nodetext = re.sub(
|
|
226
|
+
r'<style.*?</style>',
|
|
227
|
+
'',
|
|
228
|
+
node.astext(),
|
|
229
|
+
flags=re.IGNORECASE | re.DOTALL,
|
|
230
|
+
)
|
|
231
|
+
nodetext = re.sub(
|
|
232
|
+
r'<script.*?</script>',
|
|
233
|
+
'',
|
|
234
|
+
nodetext,
|
|
235
|
+
flags=re.IGNORECASE | re.DOTALL,
|
|
236
|
+
)
|
|
227
237
|
nodetext = re.sub(r'<[^<]+?>', '', nodetext)
|
|
228
238
|
self.found_words.extend(self.lang.split(nodetext))
|
|
229
239
|
raise nodes.SkipNode
|
|
@@ -245,12 +255,15 @@ class IndexBuilder:
|
|
|
245
255
|
Helper class that creates a search index based on the doctrees
|
|
246
256
|
passed to the `feed` method.
|
|
247
257
|
"""
|
|
258
|
+
|
|
248
259
|
formats = {
|
|
249
|
-
'json':
|
|
250
|
-
'pickle':
|
|
260
|
+
'json': json,
|
|
261
|
+
'pickle': pickle,
|
|
251
262
|
}
|
|
252
263
|
|
|
253
|
-
def __init__(
|
|
264
|
+
def __init__(
|
|
265
|
+
self, env: BuildEnvironment, lang: str, options: dict[str, str], scoring: str
|
|
266
|
+
) -> None:
|
|
254
267
|
self.env = env
|
|
255
268
|
# docname -> title
|
|
256
269
|
self._titles: dict[str, str | None] = env._search_index_titles
|
|
@@ -261,9 +274,13 @@ class IndexBuilder:
|
|
|
261
274
|
# stemmed words in titles -> set(docname)
|
|
262
275
|
self._title_mapping: dict[str, set[str]] = env._search_index_title_mapping
|
|
263
276
|
# docname -> all titles in document
|
|
264
|
-
self._all_titles: dict[str, list[tuple[str, str | None]]] =
|
|
277
|
+
self._all_titles: dict[str, list[tuple[str, str | None]]] = (
|
|
278
|
+
env._search_index_all_titles
|
|
279
|
+
)
|
|
265
280
|
# docname -> list(index entry)
|
|
266
|
-
self._index_entries: dict[str, list[tuple[str, str, str]]] =
|
|
281
|
+
self._index_entries: dict[str, list[tuple[str, str, str]]] = (
|
|
282
|
+
env._search_index_index_entries
|
|
283
|
+
)
|
|
267
284
|
# objtype -> index
|
|
268
285
|
self._objtypes: dict[tuple[str, str], int] = env._search_index_objtypes
|
|
269
286
|
# objtype index -> (domain, type, objname (localized))
|
|
@@ -290,7 +307,7 @@ class IndexBuilder:
|
|
|
290
307
|
self.js_scorer_code = fp.read().decode()
|
|
291
308
|
else:
|
|
292
309
|
self.js_scorer_code = ''
|
|
293
|
-
self.js_splitter_code =
|
|
310
|
+
self.js_splitter_code = ''
|
|
294
311
|
|
|
295
312
|
def load(self, stream: IO, format: Any) -> None:
|
|
296
313
|
"""Reconstruct from frozen data."""
|
|
@@ -298,15 +315,15 @@ class IndexBuilder:
|
|
|
298
315
|
format = self.formats[format]
|
|
299
316
|
frozen = format.load(stream)
|
|
300
317
|
# if an old index is present, we treat it as not existing.
|
|
301
|
-
if not isinstance(frozen, dict) or
|
|
302
|
-
|
|
303
|
-
raise ValueError(
|
|
318
|
+
if not isinstance(frozen, dict) or frozen.get('envversion') != self.env.version:
|
|
319
|
+
msg = 'old format'
|
|
320
|
+
raise ValueError(msg)
|
|
304
321
|
index2fn = frozen['docnames']
|
|
305
|
-
self._filenames = dict(zip(index2fn, frozen['filenames']))
|
|
306
|
-
self._titles = dict(zip(index2fn, frozen['titles']))
|
|
322
|
+
self._filenames = dict(zip(index2fn, frozen['filenames'], strict=True))
|
|
323
|
+
self._titles = dict(zip(index2fn, frozen['titles'], strict=True))
|
|
307
324
|
self._all_titles = {}
|
|
308
325
|
|
|
309
|
-
for docname in self._titles
|
|
326
|
+
for docname in self._titles:
|
|
310
327
|
self._all_titles[docname] = []
|
|
311
328
|
for title, doc_tuples in frozen['alltitles'].items():
|
|
312
329
|
for doc, titleid in doc_tuples:
|
|
@@ -331,14 +348,15 @@ class IndexBuilder:
|
|
|
331
348
|
format = self.formats[format]
|
|
332
349
|
format.dump(self.freeze(), stream)
|
|
333
350
|
|
|
334
|
-
def get_objects(
|
|
335
|
-
|
|
351
|
+
def get_objects(
|
|
352
|
+
self, fn2index: dict[str, int]
|
|
353
|
+
) -> dict[str, list[tuple[int, int, int, str, str]]]:
|
|
336
354
|
rv: dict[str, list[tuple[int, int, int, str, str]]] = {}
|
|
337
355
|
otypes = self._objtypes
|
|
338
356
|
onames = self._objnames
|
|
339
|
-
for
|
|
340
|
-
|
|
341
|
-
|
|
357
|
+
for domain in self.env.domains.sorted():
|
|
358
|
+
sorted_objects = sorted(domain.get_objects())
|
|
359
|
+
for fullname, dispname, type, docname, anchor, prio in sorted_objects:
|
|
342
360
|
if docname not in fn2index:
|
|
343
361
|
continue
|
|
344
362
|
if prio < 0:
|
|
@@ -348,17 +366,20 @@ class IndexBuilder:
|
|
|
348
366
|
prefix, _, name = dispname.rpartition('.')
|
|
349
367
|
plist = rv.setdefault(prefix, [])
|
|
350
368
|
try:
|
|
351
|
-
typeindex = otypes[
|
|
369
|
+
typeindex = otypes[domain.name, type]
|
|
352
370
|
except KeyError:
|
|
353
371
|
typeindex = len(otypes)
|
|
354
|
-
otypes[
|
|
372
|
+
otypes[domain.name, type] = typeindex
|
|
355
373
|
otype = domain.object_types.get(type)
|
|
356
374
|
if otype:
|
|
357
375
|
# use str() to fire translation proxies
|
|
358
|
-
onames[typeindex] = (
|
|
359
|
-
|
|
376
|
+
onames[typeindex] = (
|
|
377
|
+
domain.name,
|
|
378
|
+
type,
|
|
379
|
+
str(domain.get_type_name(otype)),
|
|
380
|
+
)
|
|
360
381
|
else:
|
|
361
|
-
onames[typeindex] = (
|
|
382
|
+
onames[typeindex] = (domain.name, type, type)
|
|
362
383
|
if anchor == fullname:
|
|
363
384
|
shortanchor = ''
|
|
364
385
|
elif anchor == type + '-' + fullname:
|
|
@@ -368,7 +389,9 @@ class IndexBuilder:
|
|
|
368
389
|
plist.append((fn2index[docname], typeindex, prio, shortanchor, name))
|
|
369
390
|
return rv
|
|
370
391
|
|
|
371
|
-
def get_terms(
|
|
392
|
+
def get_terms(
|
|
393
|
+
self, fn2index: dict[str, int]
|
|
394
|
+
) -> tuple[dict[str, list[int] | int], dict[str, list[int] | int]]:
|
|
372
395
|
"""
|
|
373
396
|
Return a mapping of document and title terms to their corresponding sorted document IDs.
|
|
374
397
|
|
|
@@ -377,10 +400,10 @@ class IndexBuilder:
|
|
|
377
400
|
of integers.
|
|
378
401
|
"""
|
|
379
402
|
rvs: tuple[dict[str, list[int] | int], dict[str, list[int] | int]] = ({}, {})
|
|
380
|
-
for rv, mapping in zip(rvs, (self._mapping, self._title_mapping)):
|
|
403
|
+
for rv, mapping in zip(rvs, (self._mapping, self._title_mapping), strict=True):
|
|
381
404
|
for k, v in mapping.items():
|
|
382
405
|
if len(v) == 1:
|
|
383
|
-
fn, = v
|
|
406
|
+
(fn,) = v
|
|
384
407
|
if fn in fn2index:
|
|
385
408
|
rv[k] = fn2index[fn]
|
|
386
409
|
else:
|
|
@@ -389,7 +412,7 @@ class IndexBuilder:
|
|
|
389
412
|
|
|
390
413
|
def freeze(self) -> dict[str, Any]:
|
|
391
414
|
"""Create a usable data structure for serializing."""
|
|
392
|
-
docnames, titles = zip(*sorted(self._titles.items()))
|
|
415
|
+
docnames, titles = zip(*sorted(self._titles.items()), strict=True)
|
|
393
416
|
filenames = [self._filenames.get(docname) for docname in docnames]
|
|
394
417
|
fn2index = {f: i for (i, f) in enumerate(docnames)}
|
|
395
418
|
terms, title_terms = self.get_terms(fn2index)
|
|
@@ -406,15 +429,28 @@ class IndexBuilder:
|
|
|
406
429
|
index_entries: dict[str, list[tuple[int, str, bool]]] = {}
|
|
407
430
|
for docname, entries in self._index_entries.items():
|
|
408
431
|
for entry, entry_id, main_entry in entries:
|
|
409
|
-
index_entries.setdefault(entry.lower(), []).append((
|
|
432
|
+
index_entries.setdefault(entry.lower(), []).append((
|
|
433
|
+
fn2index[docname],
|
|
434
|
+
entry_id,
|
|
435
|
+
main_entry == 'main',
|
|
436
|
+
))
|
|
410
437
|
|
|
411
|
-
return
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
438
|
+
return {
|
|
439
|
+
'docnames': docnames,
|
|
440
|
+
'filenames': filenames,
|
|
441
|
+
'titles': titles,
|
|
442
|
+
'terms': terms,
|
|
443
|
+
'objects': objects,
|
|
444
|
+
'objtypes': objtypes,
|
|
445
|
+
'objnames': objnames,
|
|
446
|
+
'titleterms': title_terms,
|
|
447
|
+
'envversion': self.env.version,
|
|
448
|
+
'alltitles': alltitles,
|
|
449
|
+
'indexentries': index_entries,
|
|
450
|
+
}
|
|
415
451
|
|
|
416
452
|
def label(self) -> str:
|
|
417
|
-
return f
|
|
453
|
+
return f'{self.lang.language_name} (code: {self.lang.lang})'
|
|
418
454
|
|
|
419
455
|
def prune(self, docnames: Iterable[str]) -> None:
|
|
420
456
|
"""Remove data for all docnames not in the list."""
|
|
@@ -434,7 +470,9 @@ class IndexBuilder:
|
|
|
434
470
|
for wordnames in self._title_mapping.values():
|
|
435
471
|
wordnames.intersection_update(docnames)
|
|
436
472
|
|
|
437
|
-
def feed(
|
|
473
|
+
def feed(
|
|
474
|
+
self, docname: str, filename: str, title: str, doctree: nodes.document
|
|
475
|
+
) -> None:
|
|
438
476
|
"""Feed a doctree to the index."""
|
|
439
477
|
self._titles[docname] = title
|
|
440
478
|
self._filenames[docname] = filename
|
|
@@ -487,40 +525,12 @@ class IndexBuilder:
|
|
|
487
525
|
self._index_entries[docname] = sorted(_index_entries)
|
|
488
526
|
|
|
489
527
|
def _word_collector(self, doctree: nodes.document) -> WordStore:
|
|
490
|
-
def _visit_nodes(node: nodes.Node) -> None:
|
|
491
|
-
if isinstance(node, nodes.comment):
|
|
492
|
-
return
|
|
493
|
-
elif isinstance(node, nodes.raw):
|
|
494
|
-
if 'html' in node.get('format', '').split():
|
|
495
|
-
# Some people might put content in raw HTML that should be searched,
|
|
496
|
-
# so we just amateurishly strip HTML tags and index the remaining
|
|
497
|
-
# content
|
|
498
|
-
nodetext = re.sub(r'<style.*?</style>', '', node.astext(),
|
|
499
|
-
flags=re.IGNORECASE | re.DOTALL)
|
|
500
|
-
nodetext = re.sub(r'<script.*?</script>', '', nodetext,
|
|
501
|
-
flags=re.IGNORECASE | re.DOTALL)
|
|
502
|
-
nodetext = re.sub(r'<[^<]+?>', '', nodetext)
|
|
503
|
-
word_store.words.extend(split(nodetext))
|
|
504
|
-
return
|
|
505
|
-
elif (isinstance(node, nodes.meta)
|
|
506
|
-
and _is_meta_keywords(node, language)):
|
|
507
|
-
keywords = [keyword.strip() for keyword in node['content'].split(',')]
|
|
508
|
-
word_store.words.extend(keywords)
|
|
509
|
-
elif isinstance(node, nodes.Text):
|
|
510
|
-
word_store.words.extend(split(node.astext()))
|
|
511
|
-
elif isinstance(node, nodes.title):
|
|
512
|
-
title, is_main_title = node.astext(), len(word_store.titles) == 0
|
|
513
|
-
ids = node.parent['ids']
|
|
514
|
-
title_node_id = None if is_main_title else ids[0] if ids else None
|
|
515
|
-
word_store.titles.append((title, title_node_id))
|
|
516
|
-
word_store.title_words.extend(split(title))
|
|
517
|
-
for child in node.children:
|
|
518
|
-
_visit_nodes(child)
|
|
519
|
-
|
|
520
528
|
word_store = WordStore()
|
|
521
529
|
split = self.lang.split
|
|
522
530
|
language = self.lang.lang
|
|
523
|
-
|
|
531
|
+
_feed_visit_nodes(
|
|
532
|
+
doctree, word_store=word_store, split=split, language=language
|
|
533
|
+
)
|
|
524
534
|
return word_store
|
|
525
535
|
|
|
526
536
|
def context_for_searchtool(self) -> dict[str, Any]:
|
|
@@ -553,11 +563,60 @@ class IndexBuilder:
|
|
|
553
563
|
"""Returns JS code that will be inserted into language_data.js."""
|
|
554
564
|
if self.lang.js_stemmer_rawcode:
|
|
555
565
|
js_dir = path.join(package_dir, 'search', 'minified-js')
|
|
556
|
-
with open(
|
|
566
|
+
with open(
|
|
567
|
+
path.join(js_dir, 'base-stemmer.js'), encoding='utf-8'
|
|
568
|
+
) as js_file:
|
|
557
569
|
base_js = js_file.read()
|
|
558
|
-
with open(
|
|
570
|
+
with open(
|
|
571
|
+
path.join(js_dir, self.lang.js_stemmer_rawcode), encoding='utf-8'
|
|
572
|
+
) as js_file:
|
|
559
573
|
language_js = js_file.read()
|
|
560
|
-
return (
|
|
561
|
-
|
|
574
|
+
return (
|
|
575
|
+
f'{base_js}\n{language_js}\nStemmer = {self.lang.language_name}Stemmer;'
|
|
576
|
+
)
|
|
562
577
|
else:
|
|
563
578
|
return self.lang.js_stemmer_code
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def _feed_visit_nodes(
|
|
582
|
+
node: nodes.Node,
|
|
583
|
+
*,
|
|
584
|
+
word_store: WordStore,
|
|
585
|
+
split: Callable[[str], list[str]],
|
|
586
|
+
language: str,
|
|
587
|
+
) -> None:
|
|
588
|
+
if isinstance(node, nodes.comment):
|
|
589
|
+
return
|
|
590
|
+
elif isinstance(node, nodes.raw):
|
|
591
|
+
if 'html' in node.get('format', '').split():
|
|
592
|
+
# Some people might put content in raw HTML that should be searched,
|
|
593
|
+
# so we just amateurishly strip HTML tags and index the remaining
|
|
594
|
+
# content
|
|
595
|
+
nodetext = re.sub(
|
|
596
|
+
r'<style.*?</style>',
|
|
597
|
+
'',
|
|
598
|
+
node.astext(),
|
|
599
|
+
flags=re.IGNORECASE | re.DOTALL,
|
|
600
|
+
)
|
|
601
|
+
nodetext = re.sub(
|
|
602
|
+
r'<script.*?</script>',
|
|
603
|
+
'',
|
|
604
|
+
nodetext,
|
|
605
|
+
flags=re.IGNORECASE | re.DOTALL,
|
|
606
|
+
)
|
|
607
|
+
nodetext = re.sub(r'<[^<]+?>', '', nodetext)
|
|
608
|
+
word_store.words.extend(split(nodetext))
|
|
609
|
+
return
|
|
610
|
+
elif isinstance(node, nodes.meta) and _is_meta_keywords(node, language):
|
|
611
|
+
keywords = [keyword.strip() for keyword in node['content'].split(',')]
|
|
612
|
+
word_store.words.extend(keywords)
|
|
613
|
+
elif isinstance(node, nodes.Text):
|
|
614
|
+
word_store.words.extend(split(node.astext()))
|
|
615
|
+
elif isinstance(node, nodes.title):
|
|
616
|
+
title, is_main_title = node.astext(), len(word_store.titles) == 0
|
|
617
|
+
ids = node.parent['ids']
|
|
618
|
+
title_node_id = None if is_main_title else ids[0] if ids else None
|
|
619
|
+
word_store.titles.append((title, title_node_id))
|
|
620
|
+
word_store.title_words.extend(split(title))
|
|
621
|
+
for child in node.children:
|
|
622
|
+
_feed_visit_nodes(child, word_store=word_store, split=split, language=language)
|
sphinx/search/da.py
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING, Dict
|
|
6
|
-
|
|
7
5
|
import snowballstemmer
|
|
8
6
|
|
|
9
7
|
from sphinx.search import SearchLanguage, parse_stop_word
|
|
10
8
|
|
|
11
|
-
danish_stopwords = parse_stop_word(
|
|
9
|
+
danish_stopwords = parse_stop_word("""
|
|
12
10
|
| source: https://snowball.tartarus.org/algorithms/danish/stop.txt
|
|
13
11
|
og | and
|
|
14
12
|
i | in
|
|
@@ -104,7 +102,7 @@ været | be
|
|
|
104
102
|
thi | for (conj)
|
|
105
103
|
jer | you
|
|
106
104
|
sådan | such, like this/like that
|
|
107
|
-
|
|
105
|
+
""")
|
|
108
106
|
|
|
109
107
|
|
|
110
108
|
class SearchDanish(SearchLanguage):
|
sphinx/search/de.py
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING, Dict
|
|
6
|
-
|
|
7
5
|
import snowballstemmer
|
|
8
6
|
|
|
9
7
|
from sphinx.search import SearchLanguage, parse_stop_word
|
|
10
8
|
|
|
11
|
-
german_stopwords = parse_stop_word(
|
|
9
|
+
german_stopwords = parse_stop_word("""
|
|
12
10
|
|source: https://snowball.tartarus.org/algorithms/german/stop.txt
|
|
13
11
|
aber | but
|
|
14
12
|
|
|
@@ -287,7 +285,7 @@ zum | zu + dem
|
|
|
287
285
|
zur | zu + der
|
|
288
286
|
zwar | indeed
|
|
289
287
|
zwischen | between
|
|
290
|
-
|
|
288
|
+
""")
|
|
291
289
|
|
|
292
290
|
|
|
293
291
|
class SearchGerman(SearchLanguage):
|
sphinx/search/en.py
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING, Dict
|
|
6
|
-
|
|
7
5
|
import snowballstemmer
|
|
8
6
|
|
|
9
7
|
from sphinx.search import SearchLanguage
|
|
10
8
|
|
|
11
|
-
english_stopwords = set(
|
|
9
|
+
english_stopwords = set(
|
|
10
|
+
"""
|
|
12
11
|
a and are as at
|
|
13
12
|
be but by
|
|
14
13
|
for
|
|
@@ -18,7 +17,8 @@ of on or
|
|
|
18
17
|
such
|
|
19
18
|
that the their then there these they this to
|
|
20
19
|
was will with
|
|
21
|
-
""".split()
|
|
20
|
+
""".split()
|
|
21
|
+
)
|
|
22
22
|
|
|
23
23
|
js_porter_stemmer = """
|
|
24
24
|
/**
|