Sphinx 8.1.2__py3-none-any.whl → 8.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +50 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +134 -61
- sphinx/domains/python/_object.py +155 -68
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +66 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +99 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +281 -142
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/sphinx.pot +2069 -1964
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +63 -52
- sphinx/writers/latex.py +83 -67
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +47 -47
- sphinx/writers/text.py +50 -32
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
- sphinx-8.2.0.dist-info/RECORD +606 -0
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- sphinx-8.1.2.dist-info/RECORD +0 -598
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
sphinx/util/i18n.py
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
import os.path
|
|
6
7
|
import re
|
|
7
|
-
import
|
|
8
|
-
from
|
|
9
|
-
from os import path
|
|
10
|
-
from typing import TYPE_CHECKING, NamedTuple
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
11
10
|
|
|
12
11
|
import babel.dates
|
|
13
12
|
from babel.messages.mofile import write_mo
|
|
@@ -16,12 +15,8 @@ from babel.messages.pofile import read_po
|
|
|
16
15
|
from sphinx.errors import SphinxError
|
|
17
16
|
from sphinx.locale import __
|
|
18
17
|
from sphinx.util import logging
|
|
19
|
-
from sphinx.util.
|
|
20
|
-
|
|
21
|
-
_last_modified_time,
|
|
22
|
-
canon_path,
|
|
23
|
-
relpath,
|
|
24
|
-
)
|
|
18
|
+
from sphinx.util._pathlib import _StrPath
|
|
19
|
+
from sphinx.util.osutil import SEP, _last_modified_time
|
|
25
20
|
|
|
26
21
|
if TYPE_CHECKING:
|
|
27
22
|
import datetime as dt
|
|
@@ -33,7 +28,7 @@ if TYPE_CHECKING:
|
|
|
33
28
|
from sphinx.environment import BuildEnvironment
|
|
34
29
|
|
|
35
30
|
class DateFormatter(Protocol):
|
|
36
|
-
def __call__(
|
|
31
|
+
def __call__(
|
|
37
32
|
self,
|
|
38
33
|
date: dt.date | None = ...,
|
|
39
34
|
format: str = ...,
|
|
@@ -41,7 +36,7 @@ if TYPE_CHECKING:
|
|
|
41
36
|
) -> str: ...
|
|
42
37
|
|
|
43
38
|
class TimeFormatter(Protocol):
|
|
44
|
-
def __call__(
|
|
39
|
+
def __call__(
|
|
45
40
|
self,
|
|
46
41
|
time: dt.time | dt.datetime | float | None = ...,
|
|
47
42
|
format: str = ...,
|
|
@@ -50,7 +45,7 @@ if TYPE_CHECKING:
|
|
|
50
45
|
) -> str: ...
|
|
51
46
|
|
|
52
47
|
class DatetimeFormatter(Protocol):
|
|
53
|
-
def __call__(
|
|
48
|
+
def __call__(
|
|
54
49
|
self,
|
|
55
50
|
datetime: dt.date | dt.time | float | None = ...,
|
|
56
51
|
format: str = ...,
|
|
@@ -60,56 +55,67 @@ if TYPE_CHECKING:
|
|
|
60
55
|
|
|
61
56
|
Formatter: TypeAlias = DateFormatter | TimeFormatter | DatetimeFormatter
|
|
62
57
|
|
|
63
|
-
|
|
64
|
-
from datetime import UTC
|
|
65
|
-
else:
|
|
66
|
-
UTC = timezone.utc
|
|
58
|
+
from datetime import UTC
|
|
67
59
|
|
|
68
60
|
logger = logging.getLogger(__name__)
|
|
69
61
|
|
|
70
62
|
|
|
71
|
-
class
|
|
72
|
-
base_dir
|
|
73
|
-
domain: str
|
|
74
|
-
charset: str
|
|
63
|
+
class CatalogInfo:
|
|
64
|
+
__slots__ = 'base_dir', 'domain', 'charset'
|
|
75
65
|
|
|
66
|
+
def __init__(
|
|
67
|
+
self, base_dir: str | os.PathLike[str], domain: str, charset: str
|
|
68
|
+
) -> None:
|
|
69
|
+
self.base_dir = _StrPath(base_dir)
|
|
70
|
+
self.domain = domain
|
|
71
|
+
self.charset = charset
|
|
76
72
|
|
|
77
|
-
class CatalogInfo(LocaleFileInfoBase):
|
|
78
73
|
@property
|
|
79
74
|
def po_file(self) -> str:
|
|
80
|
-
return self.domain
|
|
75
|
+
return f'{self.domain}.po'
|
|
81
76
|
|
|
82
77
|
@property
|
|
83
78
|
def mo_file(self) -> str:
|
|
84
|
-
return self.domain
|
|
79
|
+
return f'{self.domain}.mo'
|
|
85
80
|
|
|
86
81
|
@property
|
|
87
|
-
def po_path(self) ->
|
|
88
|
-
return
|
|
82
|
+
def po_path(self) -> _StrPath:
|
|
83
|
+
return self.base_dir / self.po_file
|
|
89
84
|
|
|
90
85
|
@property
|
|
91
|
-
def mo_path(self) ->
|
|
92
|
-
return
|
|
86
|
+
def mo_path(self) -> _StrPath:
|
|
87
|
+
return self.base_dir / self.mo_file
|
|
93
88
|
|
|
94
89
|
def is_outdated(self) -> bool:
|
|
95
|
-
return (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
) # fmt: skip
|
|
90
|
+
return not self.mo_path.exists() or (
|
|
91
|
+
_last_modified_time(self.mo_path) < _last_modified_time(self.po_path)
|
|
92
|
+
)
|
|
99
93
|
|
|
100
94
|
def write_mo(self, locale: str, use_fuzzy: bool = False) -> None:
|
|
101
95
|
with open(self.po_path, encoding=self.charset) as file_po:
|
|
102
96
|
try:
|
|
103
97
|
po = read_po(file_po, locale)
|
|
104
98
|
except Exception as exc:
|
|
105
|
-
logger.warning(
|
|
99
|
+
logger.warning(
|
|
100
|
+
__('reading error: %s, %s'),
|
|
101
|
+
self.po_path,
|
|
102
|
+
exc,
|
|
103
|
+
type='i18n',
|
|
104
|
+
subtype='not_readable',
|
|
105
|
+
)
|
|
106
106
|
return
|
|
107
107
|
|
|
108
108
|
with open(self.mo_path, 'wb') as file_mo:
|
|
109
109
|
try:
|
|
110
110
|
write_mo(file_mo, po, use_fuzzy)
|
|
111
111
|
except Exception as exc:
|
|
112
|
-
logger.warning(
|
|
112
|
+
logger.warning(
|
|
113
|
+
__('writing error: %s, %s'),
|
|
114
|
+
self.mo_path,
|
|
115
|
+
exc,
|
|
116
|
+
type='i18n',
|
|
117
|
+
subtype='not_writeable',
|
|
118
|
+
)
|
|
113
119
|
|
|
114
120
|
|
|
115
121
|
class CatalogRepository:
|
|
@@ -122,42 +128,38 @@ class CatalogRepository:
|
|
|
122
128
|
language: str,
|
|
123
129
|
encoding: str,
|
|
124
130
|
) -> None:
|
|
125
|
-
self.basedir = basedir
|
|
131
|
+
self.basedir = _StrPath(basedir)
|
|
126
132
|
self._locale_dirs = locale_dirs
|
|
127
133
|
self.language = language
|
|
128
134
|
self.encoding = encoding
|
|
129
135
|
|
|
130
136
|
@property
|
|
131
|
-
def locale_dirs(self) -> Iterator[
|
|
137
|
+
def locale_dirs(self) -> Iterator[_StrPath]:
|
|
132
138
|
if not self.language:
|
|
133
139
|
return
|
|
134
140
|
|
|
135
141
|
for locale_dir in self._locale_dirs:
|
|
136
|
-
|
|
137
|
-
locale_path
|
|
138
|
-
|
|
139
|
-
yield locale_dir
|
|
142
|
+
locale_path = self.basedir / locale_dir / self.language / 'LC_MESSAGES'
|
|
143
|
+
if locale_path.exists():
|
|
144
|
+
yield self.basedir / locale_dir
|
|
140
145
|
else:
|
|
141
146
|
logger.verbose(__('locale_dir %s does not exist'), locale_path)
|
|
142
147
|
|
|
143
148
|
@property
|
|
144
|
-
def pofiles(self) -> Iterator[tuple[
|
|
149
|
+
def pofiles(self) -> Iterator[tuple[_StrPath, _StrPath]]:
|
|
145
150
|
for locale_dir in self.locale_dirs:
|
|
146
|
-
|
|
147
|
-
for
|
|
151
|
+
locale_path = locale_dir / self.language / 'LC_MESSAGES'
|
|
152
|
+
for abs_path in locale_path.rglob('*.po'):
|
|
153
|
+
rel_path = abs_path.relative_to(locale_path)
|
|
148
154
|
# skip dot-directories
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for filename in filenames:
|
|
153
|
-
if filename.endswith('.po'):
|
|
154
|
-
fullpath = path.join(root, filename)
|
|
155
|
-
yield basedir, relpath(fullpath, basedir)
|
|
155
|
+
if any(part.startswith('.') for part in rel_path.parts[:-1]):
|
|
156
|
+
continue
|
|
157
|
+
yield locale_path, rel_path
|
|
156
158
|
|
|
157
159
|
@property
|
|
158
160
|
def catalogs(self) -> Iterator[CatalogInfo]:
|
|
159
161
|
for basedir, filename in self.pofiles:
|
|
160
|
-
domain =
|
|
162
|
+
domain = filename.with_suffix('').as_posix()
|
|
161
163
|
yield CatalogInfo(basedir, domain, self.encoding)
|
|
162
164
|
|
|
163
165
|
|
|
@@ -173,11 +175,11 @@ def docname_to_domain(docname: str, compaction: bool | str) -> str:
|
|
|
173
175
|
|
|
174
176
|
# date_format mappings: ustrftime() to babel.dates.format_datetime()
|
|
175
177
|
date_format_mappings = {
|
|
176
|
-
'%a': 'EEE', # Weekday as locale
|
|
177
|
-
'%A': 'EEEE', # Weekday as locale
|
|
178
|
-
'%b': 'MMM', # Month as locale
|
|
179
|
-
'%B': 'MMMM', # Month as locale
|
|
180
|
-
'%c': 'medium', # Locale
|
|
178
|
+
'%a': 'EEE', # Weekday as locale's abbreviated name.
|
|
179
|
+
'%A': 'EEEE', # Weekday as locale's full name.
|
|
180
|
+
'%b': 'MMM', # Month as locale's abbreviated name.
|
|
181
|
+
'%B': 'MMMM', # Month as locale's full name.
|
|
182
|
+
'%c': 'medium', # Locale's appropriate date and time representation.
|
|
181
183
|
'%-d': 'd', # Day of the month as a decimal number.
|
|
182
184
|
'%d': 'dd', # Day of the month as a zero-padded decimal number.
|
|
183
185
|
'%-H': 'H', # Hour (24-hour clock) as a decimal number [0,23].
|
|
@@ -190,7 +192,7 @@ date_format_mappings = {
|
|
|
190
192
|
'%m': 'MM', # Month as a zero-padded decimal number.
|
|
191
193
|
'%-M': 'm', # Minute as a decimal number [0,59].
|
|
192
194
|
'%M': 'mm', # Minute as a zero-padded decimal number [00,59].
|
|
193
|
-
'%p': 'a', # Locale
|
|
195
|
+
'%p': 'a', # Locale's equivalent of either AM or PM.
|
|
194
196
|
'%-S': 's', # Second as a decimal number.
|
|
195
197
|
'%S': 'ss', # Second as a zero-padded decimal number.
|
|
196
198
|
'%U': 'WW', # Week number of the year (Sunday as the first day of the week)
|
|
@@ -202,8 +204,8 @@ date_format_mappings = {
|
|
|
202
204
|
# Monday are considered to be in week 0.
|
|
203
205
|
'%W': 'WW', # Week number of the year (Monday as the first day of the week)
|
|
204
206
|
# as a zero-padded decimal number.
|
|
205
|
-
'%x': 'medium', # Locale
|
|
206
|
-
'%X': 'medium', # Locale
|
|
207
|
+
'%x': 'medium', # Locale's appropriate date representation.
|
|
208
|
+
'%X': 'medium', # Locale's appropriate time representation.
|
|
207
209
|
'%y': 'YY', # Year without century as a zero-padded decimal number.
|
|
208
210
|
'%Y': 'yyyy', # Year with century as a decimal number.
|
|
209
211
|
'%Z': 'zzz', # Time zone name (no characters if no time zone exists).
|
|
@@ -230,6 +232,12 @@ def babel_format_date(
|
|
|
230
232
|
return formatter(date, format, locale=locale)
|
|
231
233
|
except (ValueError, babel.core.UnknownLocaleError):
|
|
232
234
|
# fallback to English
|
|
235
|
+
logger.warning(
|
|
236
|
+
__('Invalid Babel locale: %r.'),
|
|
237
|
+
locale,
|
|
238
|
+
type='i18n',
|
|
239
|
+
subtype='babel',
|
|
240
|
+
)
|
|
233
241
|
return formatter(date, format, locale='en')
|
|
234
242
|
except AttributeError:
|
|
235
243
|
logger.warning(
|
|
@@ -238,6 +246,8 @@ def babel_format_date(
|
|
|
238
246
|
'if you want to output it directly: %s'
|
|
239
247
|
),
|
|
240
248
|
format,
|
|
249
|
+
type='i18n',
|
|
250
|
+
subtype='babel',
|
|
241
251
|
)
|
|
242
252
|
return format
|
|
243
253
|
|
|
@@ -255,6 +265,9 @@ def format_date(
|
|
|
255
265
|
source_date_epoch = os.getenv('SOURCE_DATE_EPOCH')
|
|
256
266
|
if source_date_epoch is not None:
|
|
257
267
|
date = datetime.fromtimestamp(float(source_date_epoch), tz=UTC)
|
|
268
|
+
# If SOURCE_DATE_EPOCH is set, users likely want a reproducible result,
|
|
269
|
+
# so enforce GMT/UTC for consistency.
|
|
270
|
+
local_time = False
|
|
258
271
|
else:
|
|
259
272
|
date = datetime.now(tz=UTC)
|
|
260
273
|
|
|
@@ -296,15 +309,15 @@ def get_image_filename_for_language(
|
|
|
296
309
|
filename: str | os.PathLike[str],
|
|
297
310
|
env: BuildEnvironment,
|
|
298
311
|
) -> str:
|
|
299
|
-
root, ext = path.splitext(filename)
|
|
300
|
-
dirname = path.dirname(root)
|
|
301
|
-
docpath = path.dirname(env.docname)
|
|
312
|
+
root, ext = os.path.splitext(filename)
|
|
313
|
+
dirname = os.path.dirname(root)
|
|
314
|
+
docpath = os.path.dirname(env.docname)
|
|
302
315
|
try:
|
|
303
316
|
return env.config.figure_language_filename.format(
|
|
304
317
|
root=root,
|
|
305
318
|
ext=ext,
|
|
306
319
|
path=dirname and dirname + SEP,
|
|
307
|
-
basename=path.basename(root),
|
|
320
|
+
basename=os.path.basename(root),
|
|
308
321
|
docpath=docpath and docpath + SEP,
|
|
309
322
|
language=env.config.language,
|
|
310
323
|
)
|
|
@@ -316,7 +329,7 @@ def get_image_filename_for_language(
|
|
|
316
329
|
def search_image_for_language(filename: str, env: BuildEnvironment) -> str:
|
|
317
330
|
translated = get_image_filename_for_language(filename, env)
|
|
318
331
|
_, abspath = env.relfn2path(translated)
|
|
319
|
-
if path.exists(abspath):
|
|
332
|
+
if os.path.exists(abspath):
|
|
320
333
|
return translated
|
|
321
334
|
else:
|
|
322
335
|
return filename
|
sphinx/util/images.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import base64
|
|
6
|
-
from
|
|
6
|
+
from pathlib import Path
|
|
7
7
|
from typing import TYPE_CHECKING, NamedTuple, overload
|
|
8
8
|
|
|
9
9
|
import imagesize
|
|
@@ -37,7 +37,8 @@ class DataURI(NamedTuple):
|
|
|
37
37
|
data: bytes
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def get_image_size(filename: str) -> tuple[int, int] | None:
|
|
40
|
+
def get_image_size(filename: str | PathLike[str]) -> tuple[int, int] | None:
|
|
41
|
+
filename = Path(filename)
|
|
41
42
|
try:
|
|
42
43
|
size = imagesize.get(filename)
|
|
43
44
|
if size[0] == -1:
|
|
@@ -55,11 +56,11 @@ def get_image_size(filename: str) -> tuple[int, int] | None:
|
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
@overload
|
|
58
|
-
def guess_mimetype(filename: PathLike[str] | str, default: str) -> str: ...
|
|
59
|
+
def guess_mimetype(filename: PathLike[str] | str, default: str) -> str: ...
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
@overload
|
|
62
|
-
def guess_mimetype(
|
|
63
|
+
def guess_mimetype(
|
|
63
64
|
filename: PathLike[str] | str, default: None = None
|
|
64
65
|
) -> str | None: ...
|
|
65
66
|
|
|
@@ -68,10 +69,11 @@ def guess_mimetype(
|
|
|
68
69
|
filename: PathLike[str] | str = '',
|
|
69
70
|
default: str | None = None,
|
|
70
71
|
) -> str | None:
|
|
71
|
-
|
|
72
|
+
filename = Path(filename)
|
|
73
|
+
ext = filename.suffix.lower()
|
|
72
74
|
if ext in mime_suffixes:
|
|
73
75
|
return mime_suffixes[ext]
|
|
74
|
-
if
|
|
76
|
+
if filename.exists():
|
|
75
77
|
try:
|
|
76
78
|
imgtype = _image_type_from_file(filename)
|
|
77
79
|
except ValueError:
|