Sphinx 8.2.0rc1__py3-none-any.whl → 8.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Sphinx might be problematic. Click here for more details.

Files changed (164) hide show
  1. sphinx/__init__.py +2 -2
  2. sphinx/application.py +3 -3
  3. sphinx/domains/math.py +2 -0
  4. sphinx/domains/python/_annotations.py +26 -10
  5. sphinx/domains/python/_object.py +4 -1
  6. sphinx/ext/apidoc/__init__.py +46 -1
  7. sphinx/ext/apidoc/_cli.py +25 -25
  8. sphinx/ext/apidoc/_extension.py +262 -0
  9. sphinx/ext/apidoc/_generate.py +14 -14
  10. sphinx/ext/apidoc/_shared.py +51 -18
  11. sphinx/ext/autodoc/__init__.py +3 -3
  12. sphinx/ext/autodoc/directive.py +1 -1
  13. sphinx/ext/autodoc/mock.py +1 -1
  14. sphinx/ext/autosummary/__init__.py +11 -0
  15. sphinx/ext/napoleon/__init__.py +23 -24
  16. sphinx/ext/viewcode.py +12 -8
  17. sphinx/highlighting.py +1 -1
  18. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  19. sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
  20. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  21. sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
  22. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  23. sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
  24. sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
  25. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  26. sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
  27. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
  28. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
  29. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
  30. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  31. sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
  32. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  33. sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
  34. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  35. sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
  36. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  37. sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
  38. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  39. sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
  40. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  41. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
  42. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  43. sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
  44. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  45. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
  46. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  47. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
  48. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  49. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
  50. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  51. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
  52. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  53. sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
  54. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  55. sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
  56. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  57. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
  58. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  59. sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
  60. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  61. sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
  62. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  63. sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
  64. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  65. sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
  66. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  67. sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
  68. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  69. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
  70. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  71. sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
  72. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  73. sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
  74. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  75. sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
  76. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  77. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
  78. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  79. sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
  80. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  81. sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
  82. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  83. sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
  84. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  85. sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
  86. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  87. sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
  88. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  89. sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
  90. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  91. sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
  92. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  93. sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
  94. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  95. sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
  96. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  97. sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
  98. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
  100. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
  102. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
  104. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
  106. sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
  107. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  108. sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
  109. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  110. sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
  111. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  112. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
  113. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  114. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
  115. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  116. sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
  117. sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
  118. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
  120. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
  122. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
  124. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
  126. sphinx/locale/sphinx.pot +2069 -1964
  127. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  128. sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
  129. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  130. sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
  131. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  132. sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
  133. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  134. sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
  135. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  136. sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
  137. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
  139. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
  141. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
  143. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
  145. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
  147. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
  149. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
  151. sphinx/testing/path.py +8 -0
  152. sphinx/themes/basic/static/basic.css.jinja +0 -8
  153. sphinx/util/_files.py +2 -2
  154. sphinx/util/fileutil.py +2 -1
  155. sphinx/util/osutil.py +6 -1
  156. sphinx/writers/html5.py +2 -2
  157. sphinx/writers/latex.py +3 -2
  158. sphinx/writers/texinfo.py +3 -2
  159. sphinx/writers/text.py +2 -2
  160. {sphinx-8.2.0rc1.dist-info → sphinx-8.2.1.dist-info}/METADATA +8 -5
  161. {sphinx-8.2.0rc1.dist-info → sphinx-8.2.1.dist-info}/RECORD +164 -160
  162. {sphinx-8.2.0rc1.dist-info → sphinx-8.2.1.dist-info}/WHEEL +1 -1
  163. {sphinx-8.2.0rc1.dist-info → sphinx-8.2.1.dist-info}/entry_points.txt +0 -0
  164. {sphinx-8.2.0rc1.dist-info → sphinx-8.2.1.dist-info/licenses}/LICENSE.rst +0 -0
@@ -63,8 +63,8 @@ def is_package_dir(
63
63
 
64
64
  def write_file(name: str, text: str, opts: ApidocOptions) -> Path:
65
65
  """Write the output file for module/package <name>."""
66
- fname = Path(opts.destdir, f'{name}.{opts.suffix}')
67
- if opts.dryrun:
66
+ fname = Path(opts.dest_dir, f'{name}.{opts.suffix}')
67
+ if opts.dry_run:
68
68
  if not opts.quiet:
69
69
  LOGGER.info(__('Would create file %s.'), fname)
70
70
  return fname
@@ -87,12 +87,12 @@ def create_module_file(
87
87
  ) -> Path:
88
88
  """Build the text of the file and write the file."""
89
89
  options = set(OPTIONS if not opts.automodule_options else opts.automodule_options)
90
- if opts.includeprivate:
90
+ if opts.include_private:
91
91
  options.add('private-members')
92
92
 
93
93
  qualname = module_join(package, basename)
94
94
  context = {
95
- 'show_headings': not opts.noheadings,
95
+ 'show_headings': not opts.no_headings,
96
96
  'basename': basename,
97
97
  'qualname': qualname,
98
98
  'automodule_options': sorted(options),
@@ -140,7 +140,7 @@ def create_package_file(
140
140
  module_join(master_package, subroot, modname) for modname in submodules
141
141
  ]
142
142
  options = OPTIONS.copy()
143
- if opts.includeprivate:
143
+ if opts.include_private:
144
144
  options.add('private-members')
145
145
 
146
146
  pkgname = module_join(master_package, subroot)
@@ -149,11 +149,11 @@ def create_package_file(
149
149
  'subpackages': subpackages,
150
150
  'submodules': submodules,
151
151
  'is_namespace': is_namespace,
152
- 'modulefirst': opts.modulefirst,
153
- 'separatemodules': opts.separatemodules,
152
+ 'modulefirst': opts.module_first,
153
+ 'separatemodules': opts.separate_modules,
154
154
  'automodule_options': sorted(options),
155
- 'show_headings': not opts.noheadings,
156
- 'maxdepth': opts.maxdepth,
155
+ 'show_headings': not opts.no_headings,
156
+ 'maxdepth': opts.max_depth,
157
157
  }
158
158
  if user_template_dir is not None:
159
159
  template_path = [user_template_dir, template_dir]
@@ -165,7 +165,7 @@ def create_package_file(
165
165
  text = ReSTRenderer(template_path).render('package.rst.jinja', context)
166
166
  written.append(write_file(pkgname, text, opts))
167
167
 
168
- if submodules and opts.separatemodules:
168
+ if submodules and opts.separate_modules:
169
169
  written.extend([
170
170
  create_module_file(None, submodule, opts, user_template_dir)
171
171
  for submodule in submodules
@@ -192,7 +192,7 @@ def create_modules_toc_file(
192
192
 
193
193
  context = {
194
194
  'header': opts.header,
195
- 'maxdepth': opts.maxdepth,
195
+ 'maxdepth': opts.max_depth,
196
196
  'docnames': modules,
197
197
  }
198
198
  template_path: Sequence[str | os.PathLike[str]]
@@ -230,7 +230,7 @@ def is_skipped_module(
230
230
  # skip if the file doesn't exist
231
231
  return True
232
232
  # skip if the module has a "private" name
233
- return filename.name.startswith('_') and not opts.includeprivate
233
+ return filename.name.startswith('_') and not opts.include_private
234
234
 
235
235
 
236
236
  def walk(
@@ -239,7 +239,7 @@ def walk(
239
239
  opts: ApidocOptions,
240
240
  ) -> Iterator[tuple[str, list[str], list[str]]]:
241
241
  """Walk through the directory and list files and subdirectories up."""
242
- for root, subs, files in os.walk(root_path, followlinks=opts.followlinks):
242
+ for root, subs, files in os.walk(root_path, followlinks=opts.follow_links):
243
243
  # document only Python module files (that aren't excluded)
244
244
  files = sorted(
245
245
  f
@@ -249,7 +249,7 @@ def walk(
249
249
 
250
250
  # remove hidden ('.') and private ('_') directories, as well as
251
251
  # excluded dirs
252
- if opts.includeprivate:
252
+ if opts.include_private:
253
253
  exclude_prefixes: tuple[str, ...] = ('.',)
254
254
  else:
255
255
  exclude_prefixes = ('.', '_')
@@ -7,18 +7,20 @@ from sphinx.locale import __
7
7
  from sphinx.util import logging
8
8
 
9
9
  if TYPE_CHECKING:
10
- from collections.abc import Sequence
10
+ from collections.abc import Sequence, Set
11
11
  from pathlib import Path
12
- from typing import Final
12
+ from typing import Final, Self
13
+
14
+ from sphinx.config import Config
13
15
 
14
16
  LOGGER: Final[logging.SphinxLoggerAdapter] = logging.getLogger('sphinx.ext.apidoc')
15
17
 
16
18
 
17
19
  def _remove_old_files(
18
- written_files: Sequence[Path], destdir: Path, suffix: str
20
+ written_files: Sequence[Path], dest_dir: Path, suffix: str
19
21
  ) -> None:
20
22
  files_to_keep = frozenset(written_files)
21
- for existing in destdir.rglob(f'*.{suffix}'):
23
+ for existing in dest_dir.rglob(f'*.{suffix}'):
22
24
  if existing not in files_to_keep:
23
25
  try:
24
26
  existing.unlink()
@@ -35,25 +37,26 @@ def _remove_old_files(
35
37
  class ApidocOptions:
36
38
  """Options for apidoc."""
37
39
 
40
+ dest_dir: Path
38
41
  module_path: Path
39
- destdir: Path
40
42
 
41
43
  exclude_pattern: Sequence[str] = ()
42
- quiet: bool = False
43
- maxdepth: int = 4
44
- force: bool = False
45
- followlinks: bool = False
46
- dryrun: bool = False
47
- separatemodules: bool = False
48
- includeprivate: bool = False
49
- tocfile: str = 'modules'
50
- noheadings: bool = False
51
- modulefirst: bool = False
44
+ max_depth: int = 4
45
+ follow_links: bool = False
46
+ separate_modules: bool = False
47
+ include_private: bool = False
48
+ toc_file: str = 'modules'
49
+ no_headings: bool = False
50
+ module_first: bool = False
52
51
  implicit_namespaces: bool = False
53
- automodule_options: set[str] = dataclasses.field(default_factory=set)
52
+ automodule_options: Set[str] = dataclasses.field(default_factory=set)
54
53
  suffix: str = 'rst'
55
54
 
56
- remove_old: bool = False
55
+ remove_old: bool = True
56
+
57
+ quiet: bool = False
58
+ dry_run: bool = False
59
+ force: bool = True
57
60
 
58
61
  # --full only
59
62
  full: bool = False
@@ -63,4 +66,34 @@ class ApidocOptions:
63
66
  version: str | None = None
64
67
  release: str | None = None
65
68
  extensions: Sequence[str] | None = None
66
- templatedir: str | None = None
69
+ template_dir: str | None = None
70
+
71
+
72
+ @dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
73
+ class ApidocDefaults:
74
+ """Default values for apidoc options."""
75
+
76
+ exclude_patterns: list[str]
77
+ automodule_options: frozenset[str]
78
+ max_depth: int
79
+ follow_links: bool
80
+ separate_modules: bool
81
+ include_private: bool
82
+ no_headings: bool
83
+ module_first: bool
84
+ implicit_namespaces: bool
85
+
86
+ @classmethod
87
+ def from_config(cls, config: Config, /) -> Self:
88
+ """Collect the default values for apidoc options."""
89
+ return cls(
90
+ exclude_patterns=config.apidoc_exclude_patterns,
91
+ automodule_options=frozenset(config.apidoc_automodule_options),
92
+ max_depth=config.apidoc_max_depth,
93
+ follow_links=config.apidoc_follow_links,
94
+ separate_modules=config.apidoc_separate_modules,
95
+ include_private=config.apidoc_include_private,
96
+ no_headings=config.apidoc_no_headings,
97
+ module_first=config.apidoc_module_first,
98
+ implicit_namespaces=config.apidoc_implicit_namespaces,
99
+ )
@@ -291,7 +291,7 @@ def between(
291
291
  # This class is used only in ``sphinx.ext.autodoc.directive``,
292
292
  # But we define this class here to keep compatibility
293
293
  # See: https://github.com/sphinx-doc/sphinx/issues/4538
294
- class Options(dict[str, Any]):
294
+ class Options(dict[str, Any]): # NoQA: FURB189
295
295
  """A dict/attribute hybrid that returns None on nonexisting keys."""
296
296
 
297
297
  def copy(self) -> Options:
@@ -381,7 +381,7 @@ class Documenter:
381
381
 
382
382
  def get_attr(self, obj: Any, name: str, *defargs: Any) -> Any:
383
383
  """getattr() override for types such as Zope interfaces."""
384
- return autodoc_attrgetter(self.env._registry, obj, name, *defargs)
384
+ return autodoc_attrgetter(obj, name, *defargs, registry=self.env._registry)
385
385
 
386
386
  @classmethod
387
387
  def can_document_member(
@@ -3139,7 +3139,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
3139
3139
 
3140
3140
 
3141
3141
  def autodoc_attrgetter(
3142
- registry: SphinxComponentRegistry, obj: Any, name: str, *defargs: Any
3142
+ obj: Any, name: str, *defargs: Any, registry: SphinxComponentRegistry
3143
3143
  ) -> Any:
3144
3144
  """Alternative getattr() for types"""
3145
3145
  for typ, func in registry.autodoc_attrgetters.items():
@@ -52,7 +52,7 @@ AUTODOC_EXTENDABLE_OPTIONS = frozenset({
52
52
  })
53
53
 
54
54
 
55
- class DummyOptionSpec(dict[str, Callable[[str], str]]):
55
+ class DummyOptionSpec(dict[str, Callable[[str], str]]): # NoQA: FURB189
56
56
  """An option_spec allows any options."""
57
57
 
58
58
  def __bool__(self) -> bool:
@@ -30,7 +30,7 @@ class _MockObject:
30
30
  __sphinx_mock__ = True
31
31
  __sphinx_decorator_args__: tuple[Any, ...] = ()
32
32
 
33
- def __new__(cls, *args: Any, **kwargs: Any) -> Any:
33
+ def __new__(cls, *args: Any, **kwargs: Any) -> Any: # NoQA: ARG004
34
34
  if len(args) == 3 and isinstance(args[1], tuple):
35
35
  superclass = args[1][-1].__class__
36
36
  if superclass is cls:
@@ -180,6 +180,17 @@ class FakeDirective(DocumenterBridge):
180
180
  super().__init__(env, None, Options(), 0, state)
181
181
 
182
182
 
183
+ def get_documenter(app: Sphinx, obj: Any, parent: Any) -> type[Documenter]:
184
+ """Get an autodoc.Documenter class suitable for documenting the given
185
+ object.
186
+
187
+ *obj* is the Python object to be documented, and *parent* is an
188
+ another Python object (e.g. a module or a class) to which *obj*
189
+ belongs to.
190
+ """
191
+ return _get_documenter(obj, parent, registry=app.registry)
192
+
193
+
183
194
  def _get_documenter(
184
195
  obj: Any, parent: Any, *, registry: SphinxComponentRegistry
185
196
  ) -> type[Documenter]:
@@ -11,6 +11,7 @@ from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
11
11
  from sphinx.util import inspect
12
12
 
13
13
  if TYPE_CHECKING:
14
+ from collections.abc import Sequence, Set
14
15
  from typing import Any
15
16
 
16
17
  from sphinx.config import _ConfigRebuild
@@ -270,27 +271,27 @@ class Config:
270
271
 
271
272
  """
272
273
 
273
- _config_values: dict[str, tuple[Any, _ConfigRebuild]] = {
274
- 'napoleon_google_docstring': (True, 'env'),
275
- 'napoleon_numpy_docstring': (True, 'env'),
276
- 'napoleon_include_init_with_doc': (False, 'env'),
277
- 'napoleon_include_private_with_doc': (False, 'env'),
278
- 'napoleon_include_special_with_doc': (False, 'env'),
279
- 'napoleon_use_admonition_for_examples': (False, 'env'),
280
- 'napoleon_use_admonition_for_notes': (False, 'env'),
281
- 'napoleon_use_admonition_for_references': (False, 'env'),
282
- 'napoleon_use_ivar': (False, 'env'),
283
- 'napoleon_use_param': (True, 'env'),
284
- 'napoleon_use_rtype': (True, 'env'),
285
- 'napoleon_use_keyword': (True, 'env'),
286
- 'napoleon_preprocess_types': (False, 'env'),
287
- 'napoleon_type_aliases': (None, 'env'),
288
- 'napoleon_custom_sections': (None, 'env'),
289
- 'napoleon_attr_annotations': (True, 'env'),
290
- }
274
+ _config_values: Sequence[tuple[str, bool | None, _ConfigRebuild, Set[type]]] = (
275
+ ('napoleon_google_docstring', True, 'env', frozenset({bool})),
276
+ ('napoleon_numpy_docstring', True, 'env', frozenset({bool})),
277
+ ('napoleon_include_init_with_doc', False, 'env', frozenset({bool})),
278
+ ('napoleon_include_private_with_doc', False, 'env', frozenset({bool})),
279
+ ('napoleon_include_special_with_doc', False, 'env', frozenset({bool})),
280
+ ('napoleon_use_admonition_for_examples', False, 'env', frozenset({bool})),
281
+ ('napoleon_use_admonition_for_notes', False, 'env', frozenset({bool})),
282
+ ('napoleon_use_admonition_for_references', False, 'env', frozenset({bool})),
283
+ ('napoleon_use_ivar', False, 'env', frozenset({bool})),
284
+ ('napoleon_use_param', True, 'env', frozenset({bool})),
285
+ ('napoleon_use_rtype', True, 'env', frozenset({bool})),
286
+ ('napoleon_use_keyword', True, 'env', frozenset({bool})),
287
+ ('napoleon_preprocess_types', False, 'env', frozenset({bool})),
288
+ ('napoleon_type_aliases', None, 'env', frozenset({dict, NoneType})),
289
+ ('napoleon_custom_sections', None, 'env', frozenset({list, tuple, NoneType})),
290
+ ('napoleon_attr_annotations', True, 'env', frozenset({bool})),
291
+ )
291
292
 
292
293
  def __init__(self, **settings: Any) -> None:
293
- for name, (default, _rebuild) in self._config_values.items():
294
+ for name, default, _rebuild, _types in self._config_values:
294
295
  setattr(self, name, default)
295
296
  for name, value in settings.items():
296
297
  setattr(self, name, value)
@@ -331,11 +332,9 @@ def setup(app: Sphinx) -> ExtensionMetadata:
331
332
  app.connect('autodoc-process-docstring', _process_docstring)
332
333
  app.connect('autodoc-skip-member', _skip_member)
333
334
 
334
- for name, (default, rebuild) in Config._config_values.items():
335
- if isinstance(default, bool):
336
- app.add_config_value(name, default, rebuild, types=frozenset({bool}))
337
- else:
338
- app.add_config_value(name, default, rebuild, types=frozenset({NoneType}))
335
+ for name, default, rebuild, types in Config._config_values:
336
+ app.add_config_value(name, default, rebuild, types=types)
337
+
339
338
  return {
340
339
  'version': sphinx.__display_version__,
341
340
  'parallel_read_safe': True,
sphinx/ext/viewcode.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import importlib.util
5
+ import importlib
6
6
  import operator
7
7
  import posixpath
8
8
  import traceback
@@ -62,16 +62,20 @@ def _get_full_modname(modname: str, attribute: str) -> str | None:
62
62
  num_parts = len(module_path)
63
63
  for i in range(num_parts, 0, -1):
64
64
  mod_root = '.'.join(module_path[:i])
65
- module_spec = importlib.util.find_spec(mod_root)
66
- if module_spec is not None:
65
+ try:
66
+ # import_module() caches the module in sys.modules
67
+ module = importlib.import_module(mod_root)
67
68
  break
69
+ except ModuleNotFoundError:
70
+ continue
71
+ except BaseException as exc:
72
+ # Importing modules may cause any side effects, including
73
+ # SystemExit, so we need to catch all errors.
74
+ msg = f"viewcode failed to import '{mod_root}'."
75
+ raise ImportError(msg) from exc
68
76
  else:
69
77
  return None
70
- # Load and execute the module
71
- module = importlib.util.module_from_spec(module_spec)
72
- if module_spec.loader is None:
73
- return None
74
- module_spec.loader.exec_module(module)
78
+
75
79
  if i != num_parts:
76
80
  for mod in module_path[i:]:
77
81
  module = getattr(module, mod)
sphinx/highlighting.py CHANGED
@@ -171,7 +171,7 @@ class PygmentsBridge:
171
171
  lang,
172
172
  location=location,
173
173
  type='misc',
174
- subtype='higlighting_failure',
174
+ subtype='highlighting_failure',
175
175
  )
176
176
  lexer = lexer_classes['none'](**opts)
177
177
 
Binary file