Sphinx 7.1.2__py3-none-any.whl → 7.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.

Files changed (313) hide show
  1. sphinx/__init__.py +6 -6
  2. sphinx/__main__.py +3 -1
  3. sphinx/addnodes.py +35 -22
  4. sphinx/application.py +40 -38
  5. sphinx/builders/__init__.py +16 -12
  6. sphinx/builders/_epub_base.py +15 -11
  7. sphinx/builders/changes.py +6 -4
  8. sphinx/builders/dirhtml.py +4 -2
  9. sphinx/builders/dummy.py +6 -4
  10. sphinx/builders/epub3.py +16 -8
  11. sphinx/builders/gettext.py +40 -43
  12. sphinx/builders/html/__init__.py +166 -196
  13. sphinx/builders/html/_assets.py +116 -0
  14. sphinx/builders/html/transforms.py +4 -2
  15. sphinx/builders/latex/__init__.py +12 -7
  16. sphinx/builders/latex/theming.py +5 -2
  17. sphinx/builders/latex/transforms.py +6 -3
  18. sphinx/builders/linkcheck.py +18 -11
  19. sphinx/builders/manpage.py +6 -4
  20. sphinx/builders/singlehtml.py +16 -9
  21. sphinx/builders/texinfo.py +11 -6
  22. sphinx/builders/text.py +8 -3
  23. sphinx/builders/xml.py +9 -4
  24. sphinx/cmd/build.py +27 -14
  25. sphinx/cmd/make_mode.py +13 -4
  26. sphinx/cmd/quickstart.py +13 -4
  27. sphinx/config.py +17 -14
  28. sphinx/deprecation.py +4 -2
  29. sphinx/directives/__init__.py +44 -12
  30. sphinx/directives/code.py +5 -4
  31. sphinx/directives/other.py +92 -44
  32. sphinx/directives/patches.py +1 -1
  33. sphinx/domains/__init__.py +11 -8
  34. sphinx/domains/c.py +67 -57
  35. sphinx/domains/changeset.py +3 -2
  36. sphinx/domains/citation.py +2 -1
  37. sphinx/domains/cpp.py +136 -93
  38. sphinx/domains/index.py +9 -5
  39. sphinx/domains/javascript.py +32 -19
  40. sphinx/domains/math.py +5 -3
  41. sphinx/domains/python.py +69 -57
  42. sphinx/domains/rst.py +20 -11
  43. sphinx/domains/std.py +21 -15
  44. sphinx/environment/__init__.py +97 -65
  45. sphinx/environment/adapters/indexentries.py +13 -10
  46. sphinx/environment/adapters/toctree.py +485 -308
  47. sphinx/environment/collectors/__init__.py +3 -4
  48. sphinx/environment/collectors/asset.py +10 -4
  49. sphinx/environment/collectors/dependencies.py +7 -4
  50. sphinx/environment/collectors/metadata.py +7 -5
  51. sphinx/environment/collectors/title.py +5 -3
  52. sphinx/environment/collectors/toctree.py +13 -8
  53. sphinx/errors.py +1 -1
  54. sphinx/events.py +5 -5
  55. sphinx/ext/apidoc.py +49 -27
  56. sphinx/ext/autodoc/__init__.py +179 -161
  57. sphinx/ext/autodoc/directive.py +10 -6
  58. sphinx/ext/autodoc/importer.py +22 -13
  59. sphinx/ext/autodoc/mock.py +4 -1
  60. sphinx/ext/autodoc/preserve_defaults.py +80 -12
  61. sphinx/ext/autodoc/type_comment.py +14 -10
  62. sphinx/ext/autodoc/typehints.py +7 -3
  63. sphinx/ext/autosectionlabel.py +6 -3
  64. sphinx/ext/autosummary/__init__.py +21 -15
  65. sphinx/ext/autosummary/generate.py +176 -126
  66. sphinx/ext/coverage.py +93 -8
  67. sphinx/ext/doctest.py +28 -17
  68. sphinx/ext/duration.py +19 -17
  69. sphinx/ext/extlinks.py +11 -6
  70. sphinx/ext/githubpages.py +8 -7
  71. sphinx/ext/graphviz.py +61 -17
  72. sphinx/ext/ifconfig.py +7 -4
  73. sphinx/ext/imgconverter.py +4 -2
  74. sphinx/ext/imgmath.py +29 -23
  75. sphinx/ext/inheritance_diagram.py +41 -27
  76. sphinx/ext/intersphinx.py +45 -38
  77. sphinx/ext/linkcode.py +8 -5
  78. sphinx/ext/mathjax.py +13 -9
  79. sphinx/ext/napoleon/__init__.py +3 -3
  80. sphinx/ext/napoleon/docstring.py +40 -31
  81. sphinx/ext/todo.py +10 -7
  82. sphinx/ext/viewcode.py +46 -25
  83. sphinx/extension.py +1 -1
  84. sphinx/highlighting.py +20 -12
  85. sphinx/io.py +5 -4
  86. sphinx/jinja2glue.py +24 -19
  87. sphinx/locale/__init__.py +8 -2
  88. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  89. sphinx/locale/ar/LC_MESSAGES/sphinx.po +756 -740
  90. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  91. sphinx/locale/bg/LC_MESSAGES/sphinx.po +754 -738
  92. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  93. sphinx/locale/bn/LC_MESSAGES/sphinx.po +755 -739
  94. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  95. sphinx/locale/ca/LC_MESSAGES/sphinx.po +768 -752
  96. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  97. sphinx/locale/cak/LC_MESSAGES/sphinx.po +754 -738
  98. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/cs/LC_MESSAGES/sphinx.po +758 -742
  100. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/cy/LC_MESSAGES/sphinx.po +759 -743
  102. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/da/LC_MESSAGES/sphinx.po +760 -744
  104. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/de/LC_MESSAGES/sphinx.po +759 -743
  106. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +754 -738
  108. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/el/LC_MESSAGES/sphinx.po +763 -747
  110. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +754 -738
  112. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +754 -738
  114. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +768 -752
  116. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +754 -738
  118. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/eo/LC_MESSAGES/sphinx.po +754 -738
  120. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/es/LC_MESSAGES/sphinx.po +767 -751
  122. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +754 -738
  124. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/et/LC_MESSAGES/sphinx.po +762 -746
  126. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/eu/LC_MESSAGES/sphinx.po +755 -739
  128. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/fa/LC_MESSAGES/sphinx.po +766 -750
  130. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/fi/LC_MESSAGES/sphinx.po +754 -738
  132. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/fr/LC_MESSAGES/sphinx.po +768 -752
  134. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +754 -738
  136. sphinx/locale/gl/LC_MESSAGES/sphinx.js +60 -0
  137. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/gl/LC_MESSAGES/sphinx.po +3695 -0
  139. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/he/LC_MESSAGES/sphinx.po +755 -739
  141. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/hi/LC_MESSAGES/sphinx.po +763 -747
  143. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +754 -738
  145. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/hr/LC_MESSAGES/sphinx.po +760 -744
  147. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/hu/LC_MESSAGES/sphinx.po +759 -743
  149. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/id/LC_MESSAGES/sphinx.po +765 -749
  151. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/is/LC_MESSAGES/sphinx.po +760 -744
  153. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/it/LC_MESSAGES/sphinx.po +760 -744
  155. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/ja/LC_MESSAGES/sphinx.po +767 -751
  157. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/ka/LC_MESSAGES/sphinx.po +759 -743
  159. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/ko/LC_MESSAGES/sphinx.po +767 -751
  161. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/lt/LC_MESSAGES/sphinx.po +755 -739
  163. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/lv/LC_MESSAGES/sphinx.po +755 -739
  165. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/mk/LC_MESSAGES/sphinx.po +754 -738
  167. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +755 -739
  169. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ne/LC_MESSAGES/sphinx.po +755 -739
  171. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/nl/LC_MESSAGES/sphinx.po +760 -744
  173. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/pl/LC_MESSAGES/sphinx.po +762 -745
  175. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/pt/LC_MESSAGES/sphinx.po +754 -738
  177. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +768 -752
  179. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +755 -739
  181. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/ro/LC_MESSAGES/sphinx.po +759 -743
  183. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/ru/LC_MESSAGES/sphinx.po +760 -744
  185. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/si/LC_MESSAGES/sphinx.po +754 -738
  187. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/sk/LC_MESSAGES/sphinx.po +765 -749
  189. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/sl/LC_MESSAGES/sphinx.po +755 -739
  191. sphinx/locale/sphinx.pot +748 -740
  192. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/sq/LC_MESSAGES/sphinx.po +768 -752
  194. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/sr/LC_MESSAGES/sphinx.po +754 -738
  196. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +754 -738
  198. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +754 -738
  200. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sv/LC_MESSAGES/sphinx.po +755 -739
  202. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/ta/LC_MESSAGES/sphinx.po +754 -738
  204. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/te/LC_MESSAGES/sphinx.po +754 -738
  206. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/tr/LC_MESSAGES/sphinx.po +763 -747
  208. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +760 -749
  210. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/ur/LC_MESSAGES/sphinx.po +759 -748
  212. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/vi/LC_MESSAGES/sphinx.po +754 -738
  214. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  215. sphinx/locale/yue/LC_MESSAGES/sphinx.po +754 -738
  216. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  217. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +768 -752
  218. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  219. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +754 -738
  220. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  221. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +767 -751
  222. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  223. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +754 -738
  224. sphinx/parsers.py +5 -4
  225. sphinx/project.py +52 -34
  226. sphinx/pycode/__init__.py +2 -1
  227. sphinx/pycode/ast.py +7 -13
  228. sphinx/pycode/parser.py +42 -38
  229. sphinx/registry.py +35 -29
  230. sphinx/roles.py +9 -4
  231. sphinx/search/__init__.py +5 -17
  232. sphinx/search/da.py +1 -1
  233. sphinx/search/de.py +1 -1
  234. sphinx/search/en.py +1 -1
  235. sphinx/search/es.py +1 -1
  236. sphinx/search/fi.py +1 -1
  237. sphinx/search/fr.py +1 -1
  238. sphinx/search/hu.py +1 -1
  239. sphinx/search/it.py +1 -1
  240. sphinx/search/ja.py +1 -1
  241. sphinx/search/nl.py +1 -1
  242. sphinx/search/no.py +1 -1
  243. sphinx/search/pt.py +1 -1
  244. sphinx/search/ro.py +1 -1
  245. sphinx/search/ru.py +1 -1
  246. sphinx/search/sv.py +1 -1
  247. sphinx/search/tr.py +1 -1
  248. sphinx/search/zh.py +1 -1
  249. sphinx/testing/fixtures.py +23 -30
  250. sphinx/testing/path.py +9 -0
  251. sphinx/testing/restructuredtext.py +13 -5
  252. sphinx/testing/util.py +20 -63
  253. sphinx/texinputs/sphinxlatexobjects.sty +15 -15
  254. sphinx/themes/agogo/static/agogo.css_t +10 -4
  255. sphinx/themes/basic/layout.html +1 -1
  256. sphinx/themes/basic/static/basic.css_t +4 -0
  257. sphinx/themes/basic/static/documentation_options.js_t +1 -2
  258. sphinx/themes/basic/static/searchtools.js +17 -9
  259. sphinx/themes/basic/static/sphinx_highlight.js +13 -3
  260. sphinx/themes/bizstyle/static/bizstyle.css_t +4 -0
  261. sphinx/themes/classic/theme.conf +1 -1
  262. sphinx/themes/epub/static/epub.css_t +6 -1
  263. sphinx/themes/haiku/theme.conf +1 -1
  264. sphinx/themes/nature/static/nature.css_t +4 -0
  265. sphinx/themes/nonav/static/nonav.css_t +6 -1
  266. sphinx/themes/pyramid/static/pyramid.css_t +4 -0
  267. sphinx/themes/scrolls/static/scrolls.css_t +4 -0
  268. sphinx/themes/scrolls/theme.conf +1 -1
  269. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +4 -0
  270. sphinx/theming.py +9 -7
  271. sphinx/transforms/__init__.py +79 -3
  272. sphinx/transforms/compact_bullet_list.py +6 -3
  273. sphinx/transforms/i18n.py +26 -10
  274. sphinx/transforms/post_transforms/__init__.py +21 -8
  275. sphinx/transforms/post_transforms/code.py +6 -3
  276. sphinx/transforms/post_transforms/images.py +13 -9
  277. sphinx/util/__init__.py +21 -92
  278. sphinx/util/cfamily.py +7 -4
  279. sphinx/util/display.py +3 -2
  280. sphinx/util/docfields.py +7 -6
  281. sphinx/util/docstrings.py +1 -1
  282. sphinx/util/docutils.py +41 -31
  283. sphinx/util/fileutil.py +9 -6
  284. sphinx/util/i18n.py +21 -18
  285. sphinx/util/images.py +2 -1
  286. sphinx/util/index_entries.py +27 -0
  287. sphinx/util/inspect.py +83 -67
  288. sphinx/util/inventory.py +4 -2
  289. sphinx/util/logging.py +9 -6
  290. sphinx/util/matching.py +5 -2
  291. sphinx/util/math.py +6 -3
  292. sphinx/util/nodes.py +70 -31
  293. sphinx/util/osutil.py +22 -40
  294. sphinx/util/parallel.py +4 -1
  295. sphinx/util/rst.py +7 -3
  296. sphinx/util/tags.py +11 -4
  297. sphinx/util/template.py +17 -14
  298. sphinx/util/typing.py +61 -20
  299. sphinx/versioning.py +6 -4
  300. sphinx/writers/html.py +1 -1
  301. sphinx/writers/html5.py +32 -24
  302. sphinx/writers/latex.py +67 -53
  303. sphinx/writers/manpage.py +9 -5
  304. sphinx/writers/texinfo.py +11 -9
  305. sphinx/writers/text.py +14 -9
  306. sphinx/writers/xml.py +3 -2
  307. {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/METADATA +7 -5
  308. sphinx-7.2.0.dist-info/RECORD +568 -0
  309. sphinx/testing/comparer.py +0 -97
  310. sphinx-7.1.2.dist-info/RECORD +0 -564
  311. {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/LICENSE +0 -0
  312. {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/WHEEL +0 -0
  313. {sphinx-7.1.2.dist-info → sphinx-7.2.0.dist-info}/entry_points.txt +0 -0
@@ -3,17 +3,20 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import collections
6
+ import contextlib
6
7
  import inspect
7
8
  import re
8
9
  from functools import partial
9
- from typing import Any, Callable
10
+ from typing import TYPE_CHECKING, Any, Callable
10
11
 
11
- from sphinx.application import Sphinx
12
- from sphinx.config import Config as SphinxConfig
13
12
  from sphinx.locale import _, __
14
13
  from sphinx.util import logging
15
14
  from sphinx.util.typing import get_type_hints, stringify_annotation
16
15
 
16
+ if TYPE_CHECKING:
17
+ from sphinx.application import Sphinx
18
+ from sphinx.config import Config as SphinxConfig
19
+
17
20
  logger = logging.getLogger(__name__)
18
21
 
19
22
  _directive_regex = re.compile(r'\.\. \S+::')
@@ -23,7 +26,9 @@ _numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
23
26
  _single_colon_regex = re.compile(r'(?<!:):(?!:)')
24
27
  _xref_or_code_regex = re.compile(
25
28
  r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|'
26
- r'(?:``.+?``))')
29
+ r'(?:``.+?``)|'
30
+ r'(?::meta .+:.*)|'
31
+ r'(?:`.+?\s*(?<!\x00)<.*?>`))')
27
32
  _xref_regex = re.compile(
28
33
  r'(?:(?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:)?`.+?`)',
29
34
  )
@@ -67,17 +72,13 @@ class Deque(collections.deque):
67
72
  raise StopIteration
68
73
 
69
74
 
70
- def _convert_type_spec(_type: str, translations: dict[str, str] = {}) -> str:
75
+ def _convert_type_spec(_type: str, translations: dict[str, str] | None = None) -> str:
71
76
  """Convert type specification to reference in reST."""
72
- if _type in translations:
77
+ if translations is not None and _type in translations:
73
78
  return translations[_type]
74
- else:
75
- if _type == 'None':
76
- return ':obj:`None`'
77
- else:
78
- return ':class:`%s`' % _type
79
-
80
- return _type
79
+ if _type == 'None':
80
+ return ':py:obj:`None`'
81
+ return f':py:class:`{_type}`'
81
82
 
82
83
 
83
84
  class GoogleDocstring:
@@ -108,7 +109,7 @@ class GoogleDocstring:
108
109
  The object to which the docstring belongs.
109
110
  options : :class:`sphinx.ext.autodoc.Options`, optional
110
111
  The options given to the directive: an object with attributes
111
- inherited_members, undoc_members, show_inheritance and noindex that
112
+ inherited_members, undoc_members, show_inheritance and no_index that
112
113
  are True if the flag option of same name was given to the auto
113
114
  directive.
114
115
 
@@ -156,12 +157,15 @@ class GoogleDocstring:
156
157
  obj: Any = None,
157
158
  options: Any = None,
158
159
  ) -> None:
159
- self._config = config
160
160
  self._app = app
161
-
162
- if not self._config:
161
+ if config:
162
+ self._config = config
163
+ elif app:
164
+ self._config = app.config
165
+ else:
163
166
  from sphinx.ext.napoleon import Config
164
- self._config = self._app.config if self._app else Config() # type: ignore
167
+
168
+ self._config = Config() # type: ignore[assignment]
165
169
 
166
170
  if not what:
167
171
  if inspect.isclass(obj):
@@ -314,7 +318,7 @@ class GoogleDocstring:
314
318
  for name in _name.split(","):
315
319
  fields.append((name.strip(), _type, _desc))
316
320
  elif _name or _type or _desc:
317
- fields.append((_name, _type, _desc,))
321
+ fields.append((_name, _type, _desc))
318
322
  return fields
319
323
 
320
324
  def _consume_inline_attribute(self) -> tuple[str, list[str]]:
@@ -347,7 +351,7 @@ class GoogleDocstring:
347
351
  _type = _convert_type_spec(_type, self._config.napoleon_type_aliases or {})
348
352
 
349
353
  _desc = self.__class__(_desc, self._config).lines()
350
- return [(_name, _type, _desc,)]
354
+ return [(_name, _type, _desc)]
351
355
  else:
352
356
  return []
353
357
 
@@ -606,10 +610,9 @@ class GoogleDocstring:
606
610
 
607
611
  if self._name and self._what in ('attribute', 'data', 'property'):
608
612
  res: list[str] = []
609
- try:
613
+ with contextlib.suppress(StopIteration):
610
614
  res = self._parse_attribute_docstring()
611
- except StopIteration:
612
- pass
615
+
613
616
  self._parsed_lines.extend(res)
614
617
  return
615
618
 
@@ -657,8 +660,9 @@ class GoogleDocstring:
657
660
  lines.append(f':vartype {_name}: {_type}')
658
661
  else:
659
662
  lines.append('.. attribute:: ' + _name)
660
- if self._opt and 'noindex' in self._opt:
661
- lines.append(' :noindex:')
663
+ if self._opt:
664
+ if 'no-index' in self._opt or 'noindex' in self._opt:
665
+ lines.append(' :no-index:')
662
666
  lines.append('')
663
667
 
664
668
  fields = self._format_field('', '', _desc)
@@ -725,8 +729,9 @@ class GoogleDocstring:
725
729
  lines: list[str] = []
726
730
  for _name, _type, _desc in self._consume_fields(parse_type=False):
727
731
  lines.append('.. method:: %s' % _name)
728
- if self._opt and 'noindex' in self._opt:
729
- lines.append(' :noindex:')
732
+ if self._opt:
733
+ if 'no-index' in self._opt or 'noindex' in self._opt:
734
+ lines.append(' :no-index:')
730
735
  if _desc:
731
736
  lines.extend([''] + self._indent(_desc, 3))
732
737
  lines.append('')
@@ -1016,8 +1021,11 @@ def _token_type(token: str, location: str | None = None) -> str:
1016
1021
 
1017
1022
 
1018
1023
  def _convert_numpy_type_spec(
1019
- _type: str, location: str | None = None, translations: dict = {},
1024
+ _type: str, location: str | None = None, translations: dict | None = None,
1020
1025
  ) -> str:
1026
+ if translations is None:
1027
+ translations = {}
1028
+
1021
1029
  def convert_obj(obj, translations, default_translation):
1022
1030
  translation = translations.get(obj, obj)
1023
1031
 
@@ -1048,7 +1056,8 @@ def _convert_numpy_type_spec(
1048
1056
  "reference": lambda x: x,
1049
1057
  }
1050
1058
 
1051
- converted = "".join(converters.get(type_)(token) for token, type_ in types)
1059
+ converted = "".join(converters.get(type_)(token) # type: ignore[misc]
1060
+ for token, type_ in types)
1052
1061
 
1053
1062
  return converted
1054
1063
 
@@ -1081,7 +1090,7 @@ class NumpyDocstring(GoogleDocstring):
1081
1090
  The object to which the docstring belongs.
1082
1091
  options : :class:`sphinx.ext.autodoc.Options`, optional
1083
1092
  The options given to the directive: an object with attributes
1084
- inherited_members, undoc_members, show_inheritance and noindex that
1093
+ inherited_members, undoc_members, show_inheritance and no_index that
1085
1094
  are True if the flag option of same name was given to the auto
1086
1095
  directive.
1087
1096
 
@@ -1273,7 +1282,7 @@ class NumpyDocstring(GoogleDocstring):
1273
1282
  return g[2], g[1]
1274
1283
  raise ValueError("%s is not a item name" % text)
1275
1284
 
1276
- def push_item(name: str, rest: list[str]) -> None:
1285
+ def push_item(name: str | None, rest: list[str]) -> None:
1277
1286
  if not name:
1278
1287
  return
1279
1288
  name, role = parse_item_name(name)
sphinx/ext/todo.py CHANGED
@@ -7,25 +7,28 @@ with a backlink to the original location.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from typing import Any, cast
10
+ from typing import TYPE_CHECKING, Any, cast
11
11
 
12
12
  from docutils import nodes
13
- from docutils.nodes import Element, Node
14
13
  from docutils.parsers.rst import directives
15
14
  from docutils.parsers.rst.directives.admonitions import BaseAdmonition
16
15
 
17
16
  import sphinx
18
17
  from sphinx import addnodes
19
- from sphinx.application import Sphinx
20
18
  from sphinx.domains import Domain
21
- from sphinx.environment import BuildEnvironment
22
19
  from sphinx.errors import NoUri
23
20
  from sphinx.locale import _, __
24
21
  from sphinx.util import logging, texescape
25
22
  from sphinx.util.docutils import SphinxDirective, new_document
26
- from sphinx.util.typing import OptionSpec
27
- from sphinx.writers.html import HTML5Translator
28
- from sphinx.writers.latex import LaTeXTranslator
23
+
24
+ if TYPE_CHECKING:
25
+ from docutils.nodes import Element, Node
26
+
27
+ from sphinx.application import Sphinx
28
+ from sphinx.environment import BuildEnvironment
29
+ from sphinx.util.typing import OptionSpec
30
+ from sphinx.writers.html import HTML5Translator
31
+ from sphinx.writers.latex import LaTeXTranslator
29
32
 
30
33
  logger = logging.getLogger(__name__)
31
34
 
sphinx/ext/viewcode.py CHANGED
@@ -4,25 +4,30 @@ from __future__ import annotations
4
4
 
5
5
  import posixpath
6
6
  import traceback
7
+ from importlib import import_module
7
8
  from os import path
8
- from typing import Any, Generator, Iterable, cast
9
+ from typing import TYPE_CHECKING, Any, cast
9
10
 
10
11
  from docutils import nodes
11
12
  from docutils.nodes import Element, Node
12
13
 
13
14
  import sphinx
14
15
  from sphinx import addnodes
15
- from sphinx.application import Sphinx
16
- from sphinx.builders import Builder
17
16
  from sphinx.builders.html import StandaloneHTMLBuilder
18
- from sphinx.environment import BuildEnvironment
19
17
  from sphinx.locale import _, __
20
18
  from sphinx.pycode import ModuleAnalyzer
21
19
  from sphinx.transforms.post_transforms import SphinxPostTransform
22
- from sphinx.util import get_full_modname, logging
20
+ from sphinx.util import logging
23
21
  from sphinx.util.display import status_iterator
24
22
  from sphinx.util.nodes import make_refnode
25
23
 
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Generator, Iterable
26
+
27
+ from sphinx.application import Sphinx
28
+ from sphinx.builders import Builder
29
+ from sphinx.environment import BuildEnvironment
30
+
26
31
  logger = logging.getLogger(__name__)
27
32
 
28
33
 
@@ -38,9 +43,22 @@ class viewcode_anchor(Element):
38
43
  """
39
44
 
40
45
 
41
- def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> str | None:
46
+ def _get_full_modname(modname: str, attribute: str) -> str | None:
42
47
  try:
43
- return get_full_modname(modname, attribute)
48
+ if modname is None:
49
+ # Prevents a TypeError: if the last getattr() call will return None
50
+ # then it's better to return it directly
51
+ return None
52
+ module = import_module(modname)
53
+
54
+ # Allow an attribute to have multiple parts and incidentally allow
55
+ # repeated .s in the attribute.
56
+ value = module
57
+ for attr in attribute.split('.'):
58
+ if attr:
59
+ value = getattr(value, attr)
60
+
61
+ return getattr(value, '__module__', None)
44
62
  except AttributeError:
45
63
  # sphinx.ext.viewcode can't follow class instance attribute
46
64
  # then AttributeError logging output only verbose mode.
@@ -69,10 +87,10 @@ def is_supported_builder(builder: Builder) -> bool:
69
87
  def doctree_read(app: Sphinx, doctree: Node) -> None:
70
88
  env = app.builder.env
71
89
  if not hasattr(env, '_viewcode_modules'):
72
- env._viewcode_modules = {} # type: ignore
90
+ env._viewcode_modules = {} # type: ignore[attr-defined]
73
91
 
74
92
  def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool:
75
- entry = env._viewcode_modules.get(modname, None) # type: ignore
93
+ entry = env._viewcode_modules.get(modname, None) # type: ignore[attr-defined]
76
94
  if entry is False:
77
95
  return False
78
96
 
@@ -82,7 +100,7 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
82
100
  analyzer = ModuleAnalyzer.for_module(modname)
83
101
  analyzer.find_tags()
84
102
  except Exception:
85
- env._viewcode_modules[modname] = False # type: ignore
103
+ env._viewcode_modules[modname] = False # type: ignore[attr-defined]
86
104
  return False
87
105
 
88
106
  code = analyzer.code
@@ -92,7 +110,7 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
92
110
 
93
111
  if entry is None or entry[0] != code:
94
112
  entry = code, tags, {}, refname
95
- env._viewcode_modules[modname] = entry # type: ignore
113
+ env._viewcode_modules[modname] = entry # type: ignore[attr-defined]
96
114
  _, tags, used, _ = entry
97
115
  if fullname in tags:
98
116
  used[fullname] = docname
@@ -115,7 +133,7 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
115
133
  'viewcode-follow-imported', modname, fullname,
116
134
  )
117
135
  if not new_modname:
118
- new_modname = _get_full_modname(app, modname, fullname)
136
+ new_modname = _get_full_modname(modname, fullname)
119
137
  modname = new_modname
120
138
  if not modname:
121
139
  continue
@@ -136,14 +154,14 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],
136
154
  return
137
155
  # create a _viewcode_modules dict on the main environment
138
156
  if not hasattr(env, '_viewcode_modules'):
139
- env._viewcode_modules = {} # type: ignore
157
+ env._viewcode_modules = {} # type: ignore[attr-defined]
140
158
  # now merge in the information from the subprocess
141
159
  for modname, entry in other._viewcode_modules.items():
142
- if modname not in env._viewcode_modules: # type: ignore
143
- env._viewcode_modules[modname] = entry # type: ignore
160
+ if modname not in env._viewcode_modules: # type: ignore[attr-defined]
161
+ env._viewcode_modules[modname] = entry # type: ignore[attr-defined]
144
162
  else:
145
- if env._viewcode_modules[modname]: # type: ignore
146
- used = env._viewcode_modules[modname][2] # type: ignore
163
+ if env._viewcode_modules[modname]: # type: ignore[attr-defined]
164
+ used = env._viewcode_modules[modname][2] # type: ignore[attr-defined]
147
165
  for fullname, docname in entry[2].items():
148
166
  if fullname not in used:
149
167
  used[fullname] = docname
@@ -227,7 +245,7 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non
227
245
  return
228
246
  if not is_supported_builder(app.builder):
229
247
  return
230
- highlighter = app.builder.highlighter # type: ignore
248
+ highlighter = app.builder.highlighter # type: ignore[attr-defined]
231
249
  urito = app.builder.get_relative_uri
232
250
 
233
251
  modnames = set(env._viewcode_modules)
@@ -250,7 +268,8 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non
250
268
  lexer = env.config.highlight_language
251
269
  else:
252
270
  lexer = 'python'
253
- highlighted = highlighter.highlight_block(code, lexer, linenos=False)
271
+ linenos = 'inline' * env.config.viewcode_line_numbers
272
+ highlighted = highlighter.highlight_block(code, lexer, linenos=linenos)
254
273
  # split the code into lines
255
274
  lines = highlighted.splitlines()
256
275
  # split off wrap markup from the first line of the actual code
@@ -260,15 +279,16 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non
260
279
  # now that we have code lines (starting at index 1), insert anchors for
261
280
  # the collected tags (HACK: this only works if the tag boundaries are
262
281
  # properly nested!)
263
- maxindex = len(lines) - 1
282
+ max_index = len(lines) - 1
283
+ link_text = _('[docs]')
264
284
  for name, docname in used.items():
265
285
  type, start, end = tags[name]
266
286
  backlink = urito(pagename, docname) + '#' + refname + '.' + name
267
- lines[start] = (
268
- '<div class="viewcode-block" id="%s"><a class="viewcode-back" '
269
- 'href="%s">%s</a>' % (name, backlink, _('[docs]')) +
270
- lines[start])
271
- lines[min(end, maxindex)] += '</div>'
287
+ lines[start] = (f'<div class="viewcode-block" id="{name}">\n'
288
+ f'<a class="viewcode-back" href="{backlink}">{link_text}</a>\n'
289
+ + lines[start])
290
+ lines[min(end, max_index)] += '</div>\n'
291
+
272
292
  # try to find parents (for submodules)
273
293
  parents = []
274
294
  parent = modname
@@ -324,6 +344,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
324
344
  app.add_config_value('viewcode_import', None, False)
325
345
  app.add_config_value('viewcode_enable_epub', False, False)
326
346
  app.add_config_value('viewcode_follow_imported_members', True, False)
347
+ app.add_config_value('viewcode_line_numbers', False, 'env', (bool,))
327
348
  app.connect('doctree-read', doctree_read)
328
349
  app.connect('env-merge-info', env_merge_info)
329
350
  app.connect('env-purge-doc', env_purge_doc)
sphinx/extension.py CHANGED
@@ -6,13 +6,13 @@ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from packaging.version import InvalidVersion, Version
8
8
 
9
- from sphinx.config import Config
10
9
  from sphinx.errors import VersionRequirementError
11
10
  from sphinx.locale import __
12
11
  from sphinx.util import logging
13
12
 
14
13
  if TYPE_CHECKING:
15
14
  from sphinx.application import Sphinx
15
+ from sphinx.config import Config
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
sphinx/highlighting.py CHANGED
@@ -4,13 +4,11 @@ from __future__ import annotations
4
4
 
5
5
  from functools import partial
6
6
  from importlib import import_module
7
- from typing import Any
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
9
  from pygments import highlight
10
10
  from pygments.filters import ErrorToken
11
- from pygments.formatter import Formatter
12
11
  from pygments.formatters import HtmlFormatter, LatexFormatter
13
- from pygments.lexer import Lexer
14
12
  from pygments.lexers import (
15
13
  CLexer,
16
14
  PythonConsoleLexer,
@@ -20,7 +18,6 @@ from pygments.lexers import (
20
18
  get_lexer_by_name,
21
19
  guess_lexer,
22
20
  )
23
- from pygments.style import Style
24
21
  from pygments.styles import get_style_by_name
25
22
  from pygments.util import ClassNotFound
26
23
 
@@ -28,6 +25,11 @@ from sphinx.locale import __
28
25
  from sphinx.pygments_styles import NoneStyle, SphinxStyle
29
26
  from sphinx.util import logging, texescape
30
27
 
28
+ if TYPE_CHECKING:
29
+ from pygments.formatter import Formatter
30
+ from pygments.lexer import Lexer
31
+ from pygments.style import Style
32
+
31
33
  logger = logging.getLogger(__name__)
32
34
 
33
35
  lexers: dict[str, Lexer] = {}
@@ -164,17 +166,23 @@ class PygmentsBridge:
164
166
  formatter = self.get_formatter(**kwargs)
165
167
  try:
166
168
  hlsource = highlight(source, lexer, formatter)
167
- except ErrorToken:
169
+ except ErrorToken as err:
168
170
  # this is most probably not the selected language,
169
- # so let it pass unhighlighted
171
+ # so let it pass un highlighted
170
172
  if lang == 'default':
171
- pass # automatic highlighting failed.
173
+ lang = 'none' # automatic highlighting failed.
172
174
  else:
173
- logger.warning(__('Could not lex literal_block %r as "%s". '
174
- 'Highlighting skipped.'), source, lang,
175
- type='misc', subtype='highlighting_failure',
176
- location=location)
177
- lexer = self.get_lexer(source, 'none', opts, force, location)
175
+ logger.warning(
176
+ __('Lexing literal_block %r as "%s" resulted in an error at token: %r. '
177
+ 'Retrying in relaxed mode.'),
178
+ source, lang, str(err),
179
+ type='misc', subtype='highlighting_failure',
180
+ location=location)
181
+ if force:
182
+ lang = 'none'
183
+ else:
184
+ force = True
185
+ lexer = self.get_lexer(source, lang, opts, force, location)
178
186
  hlsource = highlight(source, lexer, formatter)
179
187
 
180
188
  if self.dest == 'html':
sphinx/io.py CHANGED
@@ -6,16 +6,12 @@ from typing import TYPE_CHECKING, Any
6
6
  import docutils
7
7
  from docutils import nodes
8
8
  from docutils.core import Publisher
9
- from docutils.frontend import Values
10
9
  from docutils.io import FileInput, Input, NullOutput
11
- from docutils.parsers import Parser
12
10
  from docutils.readers import standalone
13
- from docutils.transforms import Transform
14
11
  from docutils.transforms.references import DanglingReferences
15
12
  from docutils.writers import UnfilteredWriter
16
13
 
17
14
  from sphinx import addnodes
18
- from sphinx.environment import BuildEnvironment
19
15
  from sphinx.transforms import AutoIndexUpgrader, DoctreeReadEvent, SphinxTransformer
20
16
  from sphinx.transforms.i18n import (
21
17
  Locale,
@@ -28,7 +24,12 @@ from sphinx.util.docutils import LoggingReporter
28
24
  from sphinx.versioning import UIDTransform
29
25
 
30
26
  if TYPE_CHECKING:
27
+ from docutils.frontend import Values
28
+ from docutils.parsers import Parser
29
+ from docutils.transforms import Transform
30
+
31
31
  from sphinx.application import Sphinx
32
+ from sphinx.environment import BuildEnvironment
32
33
 
33
34
 
34
35
  logger = logging.getLogger(__name__)
sphinx/jinja2glue.py CHANGED
@@ -5,15 +5,13 @@ from __future__ import annotations
5
5
  import pathlib
6
6
  from os import path
7
7
  from pprint import pformat
8
- from typing import TYPE_CHECKING, Any, Callable, Iterator
8
+ from typing import TYPE_CHECKING, Any, Callable
9
9
 
10
10
  from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
11
- from jinja2.environment import Environment
12
11
  from jinja2.sandbox import SandboxedEnvironment
13
12
  from jinja2.utils import open_if_exists
14
13
 
15
14
  from sphinx.application import TemplateBridge
16
- from sphinx.theming import Theme
17
15
  from sphinx.util import logging
18
16
  from sphinx.util.osutil import mtimes_of_files
19
17
 
@@ -23,7 +21,12 @@ except ImportError:
23
21
  from jinja2 import contextfunction as pass_context
24
22
 
25
23
  if TYPE_CHECKING:
24
+ from collections.abc import Iterator
25
+
26
+ from jinja2.environment import Environment
27
+
26
28
  from sphinx.builders import Builder
29
+ from sphinx.theming import Theme
27
30
 
28
31
 
29
32
  def _tobool(val: str) -> bool:
@@ -54,7 +57,7 @@ def _todim(val: int | str) -> str:
54
57
  return 'initial'
55
58
  elif str(val).isdigit():
56
59
  return '0' if int(val) == 0 else '%spx' % val
57
- return val # type: ignore
60
+ return val # type: ignore[return-value]
58
61
 
59
62
 
60
63
  def _slice_index(values: list, slices: int) -> Iterator[list]:
@@ -121,20 +124,22 @@ class SphinxFileSystemLoader(FileSystemLoader):
121
124
  for searchpath in self.searchpath:
122
125
  filename = str(pathlib.Path(searchpath, template))
123
126
  f = open_if_exists(filename)
124
- if f is None:
125
- continue
126
- with f:
127
- contents = f.read().decode(self.encoding)
128
-
129
- mtime = path.getmtime(filename)
130
-
131
- def uptodate() -> bool:
132
- try:
133
- return path.getmtime(filename) == mtime
134
- except OSError:
135
- return False
136
- return contents, filename, uptodate
137
- raise TemplateNotFound(template)
127
+ if f is not None:
128
+ break
129
+ else:
130
+ raise TemplateNotFound(template)
131
+
132
+ with f:
133
+ contents = f.read().decode(self.encoding)
134
+
135
+ mtime = path.getmtime(filename)
136
+
137
+ def uptodate() -> bool:
138
+ try:
139
+ return path.getmtime(filename) == mtime
140
+ except OSError:
141
+ return False
142
+ return contents, filename, uptodate
138
143
 
139
144
 
140
145
  class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
@@ -192,7 +197,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
192
197
  if use_i18n:
193
198
  self.environment.install_gettext_translations(builder.app.translator)
194
199
 
195
- def render(self, template: str, context: dict) -> str: # type: ignore
200
+ def render(self, template: str, context: dict) -> str: # type: ignore[override]
196
201
  return self.environment.get_template(template).render(context)
197
202
 
198
203
  def render_string(self, source: str, context: dict) -> str:
sphinx/locale/__init__.py CHANGED
@@ -5,7 +5,11 @@ from __future__ import annotations
5
5
  import locale
6
6
  from gettext import NullTranslations, translation
7
7
  from os import path
8
- from typing import Any, Callable, Iterable
8
+ from typing import TYPE_CHECKING
9
+
10
+ if TYPE_CHECKING:
11
+ from collections.abc import Iterable
12
+ from typing import Any, Callable
9
13
 
10
14
 
11
15
  class _TranslationProxy:
@@ -140,13 +144,15 @@ _LOCALE_DIR = path.abspath(path.dirname(__file__))
140
144
 
141
145
 
142
146
  def init_console(
143
- locale_dir: str = _LOCALE_DIR,
147
+ locale_dir: str | None = None,
144
148
  catalog: str = 'sphinx',
145
149
  ) -> tuple[NullTranslations, bool]:
146
150
  """Initialize locale for console.
147
151
 
148
152
  .. versionadded:: 1.8
149
153
  """
154
+ if locale_dir is None:
155
+ locale_dir = _LOCALE_DIR
150
156
  try:
151
157
  # encoding is ignored
152
158
  language, _ = locale.getlocale(locale.LC_MESSAGES)
Binary file