Sphinx 8.1.3__py3-none-any.whl → 8.2.0rc1__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 (193) hide show
  1. sphinx/__init__.py +8 -4
  2. sphinx/__main__.py +2 -0
  3. sphinx/_cli/__init__.py +2 -5
  4. sphinx/_cli/util/colour.py +34 -11
  5. sphinx/_cli/util/errors.py +128 -61
  6. sphinx/addnodes.py +51 -35
  7. sphinx/application.py +362 -230
  8. sphinx/builders/__init__.py +87 -64
  9. sphinx/builders/_epub_base.py +65 -56
  10. sphinx/builders/changes.py +17 -23
  11. sphinx/builders/dirhtml.py +8 -13
  12. sphinx/builders/epub3.py +70 -38
  13. sphinx/builders/gettext.py +93 -73
  14. sphinx/builders/html/__init__.py +240 -186
  15. sphinx/builders/html/_assets.py +9 -2
  16. sphinx/builders/html/_build_info.py +3 -0
  17. sphinx/builders/latex/__init__.py +64 -54
  18. sphinx/builders/latex/constants.py +14 -11
  19. sphinx/builders/latex/nodes.py +2 -0
  20. sphinx/builders/latex/theming.py +8 -9
  21. sphinx/builders/latex/transforms.py +7 -5
  22. sphinx/builders/linkcheck.py +193 -149
  23. sphinx/builders/manpage.py +17 -17
  24. sphinx/builders/singlehtml.py +28 -16
  25. sphinx/builders/texinfo.py +28 -21
  26. sphinx/builders/text.py +10 -15
  27. sphinx/builders/xml.py +10 -19
  28. sphinx/cmd/build.py +49 -119
  29. sphinx/cmd/make_mode.py +35 -31
  30. sphinx/cmd/quickstart.py +78 -62
  31. sphinx/config.py +265 -163
  32. sphinx/directives/__init__.py +51 -54
  33. sphinx/directives/admonitions.py +107 -0
  34. sphinx/directives/code.py +24 -19
  35. sphinx/directives/other.py +21 -42
  36. sphinx/directives/patches.py +28 -16
  37. sphinx/domains/__init__.py +54 -31
  38. sphinx/domains/_domains_container.py +22 -17
  39. sphinx/domains/_index.py +5 -8
  40. sphinx/domains/c/__init__.py +366 -245
  41. sphinx/domains/c/_ast.py +378 -256
  42. sphinx/domains/c/_ids.py +89 -31
  43. sphinx/domains/c/_parser.py +283 -214
  44. sphinx/domains/c/_symbol.py +269 -198
  45. sphinx/domains/changeset.py +39 -24
  46. sphinx/domains/citation.py +54 -24
  47. sphinx/domains/cpp/__init__.py +517 -362
  48. sphinx/domains/cpp/_ast.py +999 -682
  49. sphinx/domains/cpp/_ids.py +133 -65
  50. sphinx/domains/cpp/_parser.py +746 -588
  51. sphinx/domains/cpp/_symbol.py +692 -489
  52. sphinx/domains/index.py +10 -8
  53. sphinx/domains/javascript.py +152 -74
  54. sphinx/domains/math.py +48 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +114 -57
  57. sphinx/domains/python/_object.py +151 -67
  58. sphinx/domains/rst.py +94 -49
  59. sphinx/domains/std/__init__.py +510 -249
  60. sphinx/environment/__init__.py +345 -61
  61. sphinx/environment/adapters/asset.py +7 -1
  62. sphinx/environment/adapters/indexentries.py +15 -20
  63. sphinx/environment/adapters/toctree.py +19 -9
  64. sphinx/environment/collectors/__init__.py +3 -1
  65. sphinx/environment/collectors/asset.py +18 -15
  66. sphinx/environment/collectors/dependencies.py +8 -10
  67. sphinx/environment/collectors/metadata.py +6 -4
  68. sphinx/environment/collectors/title.py +3 -1
  69. sphinx/environment/collectors/toctree.py +4 -4
  70. sphinx/errors.py +1 -3
  71. sphinx/events.py +4 -4
  72. sphinx/ext/apidoc/__init__.py +21 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_generate.py +356 -0
  76. sphinx/ext/apidoc/_shared.py +66 -0
  77. sphinx/ext/autodoc/__init__.py +829 -480
  78. sphinx/ext/autodoc/directive.py +57 -21
  79. sphinx/ext/autodoc/importer.py +184 -67
  80. sphinx/ext/autodoc/mock.py +25 -10
  81. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  82. sphinx/ext/autodoc/type_comment.py +56 -29
  83. sphinx/ext/autodoc/typehints.py +49 -26
  84. sphinx/ext/autosectionlabel.py +28 -11
  85. sphinx/ext/autosummary/__init__.py +271 -143
  86. sphinx/ext/autosummary/generate.py +121 -51
  87. sphinx/ext/coverage.py +152 -91
  88. sphinx/ext/doctest.py +169 -101
  89. sphinx/ext/duration.py +12 -6
  90. sphinx/ext/extlinks.py +33 -21
  91. sphinx/ext/githubpages.py +8 -8
  92. sphinx/ext/graphviz.py +175 -109
  93. sphinx/ext/ifconfig.py +11 -6
  94. sphinx/ext/imgconverter.py +48 -25
  95. sphinx/ext/imgmath.py +127 -97
  96. sphinx/ext/inheritance_diagram.py +177 -103
  97. sphinx/ext/intersphinx/__init__.py +22 -13
  98. sphinx/ext/intersphinx/__main__.py +3 -1
  99. sphinx/ext/intersphinx/_cli.py +18 -14
  100. sphinx/ext/intersphinx/_load.py +91 -82
  101. sphinx/ext/intersphinx/_resolve.py +108 -74
  102. sphinx/ext/intersphinx/_shared.py +2 -2
  103. sphinx/ext/linkcode.py +28 -12
  104. sphinx/ext/mathjax.py +60 -29
  105. sphinx/ext/napoleon/__init__.py +19 -7
  106. sphinx/ext/napoleon/docstring.py +229 -231
  107. sphinx/ext/todo.py +44 -49
  108. sphinx/ext/viewcode.py +105 -57
  109. sphinx/extension.py +3 -1
  110. sphinx/highlighting.py +13 -7
  111. sphinx/io.py +9 -13
  112. sphinx/jinja2glue.py +29 -26
  113. sphinx/locale/__init__.py +8 -9
  114. sphinx/parsers.py +8 -7
  115. sphinx/project.py +2 -2
  116. sphinx/pycode/__init__.py +31 -21
  117. sphinx/pycode/ast.py +6 -3
  118. sphinx/pycode/parser.py +14 -8
  119. sphinx/pygments_styles.py +4 -5
  120. sphinx/registry.py +192 -92
  121. sphinx/roles.py +58 -7
  122. sphinx/search/__init__.py +75 -54
  123. sphinx/search/en.py +11 -13
  124. sphinx/search/fi.py +1 -1
  125. sphinx/search/ja.py +8 -6
  126. sphinx/search/nl.py +1 -1
  127. sphinx/search/zh.py +19 -21
  128. sphinx/testing/fixtures.py +26 -29
  129. sphinx/testing/path.py +26 -62
  130. sphinx/testing/restructuredtext.py +14 -8
  131. sphinx/testing/util.py +21 -19
  132. sphinx/texinputs/make.bat.jinja +50 -50
  133. sphinx/texinputs/sphinx.sty +4 -3
  134. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  135. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  136. sphinx/themes/basic/static/searchtools.js +8 -5
  137. sphinx/theming.py +49 -61
  138. sphinx/transforms/__init__.py +17 -38
  139. sphinx/transforms/compact_bullet_list.py +5 -3
  140. sphinx/transforms/i18n.py +8 -21
  141. sphinx/transforms/post_transforms/__init__.py +142 -93
  142. sphinx/transforms/post_transforms/code.py +5 -5
  143. sphinx/transforms/post_transforms/images.py +28 -24
  144. sphinx/transforms/references.py +3 -1
  145. sphinx/util/__init__.py +109 -60
  146. sphinx/util/_files.py +39 -23
  147. sphinx/util/_importer.py +4 -1
  148. sphinx/util/_inventory_file_reader.py +76 -0
  149. sphinx/util/_io.py +2 -2
  150. sphinx/util/_lines.py +6 -3
  151. sphinx/util/_pathlib.py +40 -2
  152. sphinx/util/build_phase.py +2 -0
  153. sphinx/util/cfamily.py +19 -14
  154. sphinx/util/console.py +44 -179
  155. sphinx/util/display.py +9 -10
  156. sphinx/util/docfields.py +140 -122
  157. sphinx/util/docstrings.py +1 -1
  158. sphinx/util/docutils.py +118 -77
  159. sphinx/util/fileutil.py +25 -26
  160. sphinx/util/http_date.py +2 -0
  161. sphinx/util/i18n.py +77 -64
  162. sphinx/util/images.py +8 -6
  163. sphinx/util/inspect.py +147 -38
  164. sphinx/util/inventory.py +215 -116
  165. sphinx/util/logging.py +33 -33
  166. sphinx/util/matching.py +12 -4
  167. sphinx/util/nodes.py +18 -13
  168. sphinx/util/osutil.py +38 -39
  169. sphinx/util/parallel.py +22 -13
  170. sphinx/util/parsing.py +2 -1
  171. sphinx/util/png.py +6 -2
  172. sphinx/util/requests.py +33 -2
  173. sphinx/util/rst.py +3 -2
  174. sphinx/util/tags.py +1 -1
  175. sphinx/util/template.py +18 -10
  176. sphinx/util/texescape.py +8 -6
  177. sphinx/util/typing.py +148 -122
  178. sphinx/versioning.py +3 -3
  179. sphinx/writers/html.py +3 -1
  180. sphinx/writers/html5.py +61 -50
  181. sphinx/writers/latex.py +80 -65
  182. sphinx/writers/manpage.py +19 -38
  183. sphinx/writers/texinfo.py +44 -45
  184. sphinx/writers/text.py +48 -30
  185. sphinx/writers/xml.py +11 -8
  186. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
  187. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
  188. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
  189. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
  190. sphinx/builders/html/transforms.py +0 -90
  191. sphinx/ext/apidoc.py +0 -721
  192. sphinx/util/exceptions.py +0 -74
  193. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/domains/index.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any, ClassVar
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from docutils import nodes
8
8
  from docutils.parsers.rst import directives
@@ -16,6 +16,7 @@ from sphinx.util.nodes import process_index_entry
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from collections.abc import Set
19
+ from typing import Any, ClassVar
19
20
 
20
21
  from docutils.nodes import Node, system_message
21
22
 
@@ -48,21 +49,20 @@ class IndexDomain(Domain):
48
49
  """Process a document after it is read by the environment."""
49
50
  entries = self.entries.setdefault(env.docname, [])
50
51
  for node in list(document.findall(addnodes.index)):
52
+ node_entries = node['entries']
51
53
  try:
52
- for (entry_type, value, _target_id, _main, _category_key) in node['entries']:
54
+ for entry_type, value, _target_id, _main, _category_key in node_entries:
53
55
  split_index_msg(entry_type, value)
54
56
  except ValueError as exc:
55
- logger.warning(str(exc), location=node)
57
+ logger.warning(str(exc), location=node, type='index')
56
58
  node.parent.remove(node)
57
59
  else:
58
- for entry in node['entries']:
60
+ for entry in node_entries:
59
61
  entries.append(entry)
60
62
 
61
63
 
62
64
  class IndexDirective(SphinxDirective):
63
- """
64
- Directive to add entries to the index.
65
- """
65
+ """Directive to add entries to the index."""
66
66
 
67
67
  has_content = False
68
68
  required_arguments = 1
@@ -88,7 +88,9 @@ class IndexDirective(SphinxDirective):
88
88
  indexnode['inline'] = False
89
89
  self.set_source_info(indexnode)
90
90
  for entry in arguments:
91
- indexnode['entries'].extend(process_index_entry(entry, targetnode['ids'][0]))
91
+ indexnode['entries'].extend(
92
+ process_index_entry(entry, targetnode['ids'][0])
93
+ )
92
94
  return [indexnode, targetnode]
93
95
 
94
96
 
@@ -3,7 +3,8 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import contextlib
6
- from typing import TYPE_CHECKING, Any, ClassVar
6
+ from types import NoneType
7
+ from typing import TYPE_CHECKING
7
8
 
8
9
  from docutils import nodes
9
10
  from docutils.parsers.rst import directives
@@ -21,6 +22,7 @@ from sphinx.util.nodes import make_id, make_refnode
21
22
 
22
23
  if TYPE_CHECKING:
23
24
  from collections.abc import Iterator, Set
25
+ from typing import Any, ClassVar
24
26
 
25
27
  from docutils.nodes import Element, Node
26
28
 
@@ -34,9 +36,7 @@ logger = logging.getLogger(__name__)
34
36
 
35
37
 
36
38
  class JSObject(ObjectDescription[tuple[str, str]]):
37
- """
38
- Description of a JavaScript object.
39
- """
39
+ """Description of a JavaScript object."""
40
40
 
41
41
  #: If set to ``True`` this object is callable and a `desc_parameterlist` is
42
42
  #: added
@@ -100,14 +100,20 @@ class JSObject(ObjectDescription[tuple[str, str]]):
100
100
  signode['object'] = prefix
101
101
  signode['fullname'] = fullname
102
102
 
103
- max_len = (self.env.config.javascript_maximum_signature_line_length
104
- or self.env.config.maximum_signature_line_length
105
- or 0)
103
+ max_len = (
104
+ self.config.javascript_maximum_signature_line_length
105
+ or self.config.maximum_signature_line_length
106
+ or 0
107
+ )
106
108
  multi_line_parameter_list = (
107
109
  'single-line-parameter-list' not in self.options
108
110
  and (len(sig) > max_len > 0)
109
111
  )
110
112
 
113
+ trailing_comma = (
114
+ self.env.config.javascript_trailing_comma_in_multi_line_signatures
115
+ )
116
+
111
117
  display_prefix = self.get_display_prefix()
112
118
  if display_prefix:
113
119
  signode += addnodes.desc_annotation('', '', *display_prefix)
@@ -118,17 +124,22 @@ class JSObject(ObjectDescription[tuple[str, str]]):
118
124
  elif mod_name:
119
125
  actual_prefix = mod_name
120
126
  if actual_prefix:
121
- addName = addnodes.desc_addname('', '')
127
+ add_name = addnodes.desc_addname('', '')
122
128
  for p in actual_prefix.split('.'):
123
- addName += addnodes.desc_sig_name(p, p)
124
- addName += addnodes.desc_sig_punctuation('.', '.')
125
- signode += addName
129
+ add_name += addnodes.desc_sig_name(p, p)
130
+ add_name += addnodes.desc_sig_punctuation('.', '.')
131
+ signode += add_name
126
132
  signode += addnodes.desc_name('', '', addnodes.desc_sig_name(name, name))
127
133
  if self.has_arguments:
128
134
  if not arglist:
129
135
  signode += addnodes.desc_parameterlist()
130
136
  else:
131
- _pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
137
+ _pseudo_parse_arglist(
138
+ signode,
139
+ arglist,
140
+ multi_line_parameter_list,
141
+ trailing_comma,
142
+ )
132
143
  return fullname, prefix
133
144
 
134
145
  def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
@@ -142,10 +153,11 @@ class JSObject(ObjectDescription[tuple[str, str]]):
142
153
  else:
143
154
  return tuple(fullname.split('.'))
144
155
 
145
- def add_target_and_index(self, name_obj: tuple[str, str], sig: str,
146
- signode: desc_signature) -> None:
147
- mod_name = self.env.ref_context.get('js:module')
148
- fullname = (mod_name + '.' if mod_name else '') + name_obj[0]
156
+ def add_target_and_index(
157
+ self, name_obj: tuple[str, str], sig: str, signode: desc_signature
158
+ ) -> None:
159
+ mod_name = self.env.ref_context.get('js:module', '')
160
+ fullname = (f'{mod_name}.' if mod_name else '') + name_obj[0]
149
161
  node_id = make_id(self.env, self.state.document, '', fullname)
150
162
  signode['ids'].append(node_id)
151
163
  self.state.document.note_explicit_target(signode)
@@ -154,9 +166,14 @@ class JSObject(ObjectDescription[tuple[str, str]]):
154
166
  domain.note_object(fullname, self.objtype, node_id, location=signode)
155
167
 
156
168
  if 'no-index-entry' not in self.options:
157
- indextext = self.get_index_text(mod_name, name_obj) # type: ignore[arg-type]
158
- if indextext:
159
- self.indexnode['entries'].append(('single', indextext, node_id, '', None))
169
+ if index_text := self.get_index_text(mod_name, name_obj):
170
+ self.indexnode['entries'].append((
171
+ 'single',
172
+ index_text,
173
+ node_id,
174
+ '',
175
+ None,
176
+ ))
160
177
 
161
178
  def get_index_text(self, objectname: str, name_obj: tuple[str, str]) -> str:
162
179
  name, obj = name_obj
@@ -223,14 +240,13 @@ class JSObject(ObjectDescription[tuple[str, str]]):
223
240
  with contextlib.suppress(IndexError):
224
241
  objects.pop()
225
242
 
226
- self.env.ref_context['js:object'] = (objects[-1] if len(objects) > 0
227
- else None)
243
+ self.env.ref_context['js:object'] = objects[-1] if len(objects) > 0 else None
228
244
 
229
245
  def _toc_entry_name(self, sig_node: desc_signature) -> str:
230
246
  if not sig_node.get('_toc_parts'):
231
247
  return ''
232
248
 
233
- config = self.env.app.config
249
+ config = self.config
234
250
  objtype = sig_node.parent.get('objtype')
235
251
  if config.add_function_parentheses and objtype in {'function', 'method'}:
236
252
  parens = '()'
@@ -252,16 +268,32 @@ class JSCallable(JSObject):
252
268
  has_arguments = True
253
269
 
254
270
  doc_field_types = [
255
- TypedField('arguments', label=_('Arguments'),
256
- names=('argument', 'arg', 'parameter', 'param'),
257
- typerolename='func', typenames=('paramtype', 'type')),
258
- GroupedField('errors', label=_('Throws'), rolename='func',
259
- names=('throws', ),
260
- can_collapse=True),
261
- Field('returnvalue', label=_('Returns'), has_arg=False,
262
- names=('returns', 'return')),
263
- Field('returntype', label=_('Return type'), has_arg=False,
264
- names=('rtype',)),
271
+ TypedField(
272
+ 'arguments',
273
+ label=_('Arguments'),
274
+ names=('argument', 'arg', 'parameter', 'param'),
275
+ typerolename='func',
276
+ typenames=('paramtype', 'type'),
277
+ ),
278
+ GroupedField(
279
+ 'errors',
280
+ label=_('Throws'),
281
+ rolename='func',
282
+ names=('throws',),
283
+ can_collapse=True,
284
+ ),
285
+ Field(
286
+ 'returnvalue',
287
+ label=_('Returns'),
288
+ has_arg=False,
289
+ names=('returns', 'return'),
290
+ ),
291
+ Field(
292
+ 'returntype',
293
+ label=_('Return type'),
294
+ has_arg=False,
295
+ names=('rtype',),
296
+ ),
265
297
  ]
266
298
 
267
299
 
@@ -271,13 +303,14 @@ class JSConstructor(JSCallable):
271
303
  allow_nesting = True
272
304
 
273
305
  def get_display_prefix(self) -> list[Node]:
274
- return [addnodes.desc_sig_keyword('class', 'class'),
275
- addnodes.desc_sig_space()]
306
+ return [
307
+ addnodes.desc_sig_keyword('class', 'class'),
308
+ addnodes.desc_sig_space(),
309
+ ]
276
310
 
277
311
 
278
312
  class JSModule(SphinxDirective):
279
- """
280
- Directive to mark description of a new JavaScript module.
313
+ """Directive to mark description of a new JavaScript module.
281
314
 
282
315
  This directive specifies the module name that will be used by objects that
283
316
  follow this directive.
@@ -300,6 +333,7 @@ class JSModule(SphinxDirective):
300
333
  final_argument_whitespace = False
301
334
  option_spec: ClassVar[OptionSpec] = {
302
335
  'no-index': directives.flag,
336
+ 'no-index-entry': directives.flag,
303
337
  'no-contents-entry': directives.flag,
304
338
  'no-typesetting': directives.flag,
305
339
  'noindex': directives.flag,
@@ -324,16 +358,20 @@ class JSModule(SphinxDirective):
324
358
  domain = self.env.domains.javascript_domain
325
359
 
326
360
  node_id = make_id(self.env, self.state.document, 'module', mod_name)
327
- domain.note_module(mod_name, node_id)
361
+ domain.note_module(modname=mod_name, node_id=node_id)
328
362
  # Make a duplicate entry in 'objects' to facilitate searching for
329
363
  # the module in JavaScriptDomain.find_obj()
330
- domain.note_object(mod_name, 'module', node_id,
331
- location=(self.env.docname, self.lineno))
364
+ domain.note_object(
365
+ mod_name, 'module', node_id, location=(self.env.docname, self.lineno)
366
+ )
332
367
 
333
368
  # The node order is: index node first, then target node
334
- indextext = _('%s (module)') % mod_name
335
- inode = addnodes.index(entries=[('single', indextext, node_id, '', None)])
336
- ret.append(inode)
369
+ if 'no-index-entry' not in self.options:
370
+ index_text = _('%s (module)') % mod_name
371
+ inode = addnodes.index(
372
+ entries=[('single', index_text, node_id, '', None)]
373
+ )
374
+ ret.append(inode)
337
375
  target = nodes.target('', '', ids=[node_id], ismod=True)
338
376
  self.state.document.note_explicit_target(target)
339
377
  ret.append(target)
@@ -342,8 +380,14 @@ class JSModule(SphinxDirective):
342
380
 
343
381
 
344
382
  class JSXRefRole(XRefRole):
345
- def process_link(self, env: BuildEnvironment, refnode: Element,
346
- has_explicit_title: bool, title: str, target: str) -> tuple[str, str]:
383
+ def process_link(
384
+ self,
385
+ env: BuildEnvironment,
386
+ refnode: Element,
387
+ has_explicit_title: bool,
388
+ title: str,
389
+ target: str,
390
+ ) -> tuple[str, str]:
347
391
  # basically what sphinx.domains.python.PyXRefRole does
348
392
  refnode['js:object'] = env.ref_context.get('js:object')
349
393
  refnode['js:module'] = env.ref_context.get('js:module')
@@ -354,7 +398,7 @@ class JSXRefRole(XRefRole):
354
398
  title = title[1:]
355
399
  dot = title.rfind('.')
356
400
  if dot != -1:
357
- title = title[dot + 1:]
401
+ title = title[dot + 1 :]
358
402
  if target[0:1] == '.':
359
403
  target = target[1:]
360
404
  refnode['refspecific'] = True
@@ -368,28 +412,28 @@ class JavaScriptDomain(Domain):
368
412
  label = 'JavaScript'
369
413
  # if you add a new object type make sure to edit JSObject.get_index_string
370
414
  object_types = {
371
- 'function': ObjType(_('function'), 'func'),
372
- 'method': ObjType(_('method'), 'meth'),
373
- 'class': ObjType(_('class'), 'class'),
374
- 'data': ObjType(_('data'), 'data'),
415
+ 'function': ObjType(_('function'), 'func'),
416
+ 'method': ObjType(_('method'), 'meth'),
417
+ 'class': ObjType(_('class'), 'class'),
418
+ 'data': ObjType(_('data'), 'data'),
375
419
  'attribute': ObjType(_('attribute'), 'attr'),
376
- 'module': ObjType(_('module'), 'mod'),
420
+ 'module': ObjType(_('module'), 'mod'),
377
421
  }
378
422
  directives = {
379
- 'function': JSCallable,
380
- 'method': JSCallable,
381
- 'class': JSConstructor,
382
- 'data': JSObject,
423
+ 'function': JSCallable,
424
+ 'method': JSCallable,
425
+ 'class': JSConstructor,
426
+ 'data': JSObject,
383
427
  'attribute': JSObject,
384
- 'module': JSModule,
428
+ 'module': JSModule,
385
429
  }
386
430
  roles = {
387
- 'func': JSXRefRole(fix_parens=True),
388
- 'meth': JSXRefRole(fix_parens=True),
431
+ 'func': JSXRefRole(fix_parens=True),
432
+ 'meth': JSXRefRole(fix_parens=True),
389
433
  'class': JSXRefRole(fix_parens=True),
390
- 'data': JSXRefRole(),
391
- 'attr': JSXRefRole(),
392
- 'mod': JSXRefRole(),
434
+ 'data': JSXRefRole(),
435
+ 'attr': JSXRefRole(),
436
+ 'mod': JSXRefRole(),
393
437
  }
394
438
  initial_data: dict[str, dict[str, tuple[str, str]]] = {
395
439
  'objects': {}, # fullname -> docname, node_id, objtype
@@ -398,14 +442,22 @@ class JavaScriptDomain(Domain):
398
442
 
399
443
  @property
400
444
  def objects(self) -> dict[str, tuple[str, str, str]]:
401
- return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype
445
+ # fullname -> docname, node_id, objtype
446
+ return self.data.setdefault('objects', {})
402
447
 
403
- def note_object(self, fullname: str, objtype: str, node_id: str,
404
- location: Any = None) -> None:
448
+ def note_object(
449
+ self, fullname: str, objtype: str, node_id: str, location: Any = None
450
+ ) -> None:
405
451
  if fullname in self.objects:
406
452
  docname = self.objects[fullname][0]
407
- logger.warning(__('duplicate %s description of %s, other %s in %s'),
408
- objtype, fullname, objtype, docname, location=location)
453
+ logger.warning(
454
+ __('duplicate %s description of %s, other %s in %s'),
455
+ objtype,
456
+ fullname,
457
+ objtype,
458
+ docname,
459
+ location=location,
460
+ )
409
461
  self.objects[fullname] = (self.env.docname, node_id, objtype)
410
462
 
411
463
  @property
@@ -464,9 +516,16 @@ class JavaScriptDomain(Domain):
464
516
 
465
517
  return newname, object_
466
518
 
467
- def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
468
- typ: str, target: str, node: pending_xref, contnode: Element,
469
- ) -> Element | None:
519
+ def resolve_xref(
520
+ self,
521
+ env: BuildEnvironment,
522
+ fromdocname: str,
523
+ builder: Builder,
524
+ typ: str,
525
+ target: str,
526
+ node: pending_xref,
527
+ contnode: Element,
528
+ ) -> nodes.reference | None:
470
529
  mod_name = node.get('js:module')
471
530
  prefix = node.get('js:object')
472
531
  searchorder = 1 if node.hasattr('refspecific') else 0
@@ -475,16 +534,26 @@ class JavaScriptDomain(Domain):
475
534
  return None
476
535
  return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
477
536
 
478
- def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
479
- target: str, node: pending_xref, contnode: Element,
480
- ) -> list[tuple[str, Element]]:
537
+ def resolve_any_xref(
538
+ self,
539
+ env: BuildEnvironment,
540
+ fromdocname: str,
541
+ builder: Builder,
542
+ target: str,
543
+ node: pending_xref,
544
+ contnode: Element,
545
+ ) -> list[tuple[str, nodes.reference]]:
481
546
  mod_name = node.get('js:module')
482
547
  prefix = node.get('js:object')
483
548
  name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)
484
549
  if not obj:
485
550
  return []
486
- return [('js:' + self.role_for_objtype(obj[2]), # type: ignore[operator]
487
- make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name))]
551
+ return [
552
+ (
553
+ f'js:{self.role_for_objtype(obj[2])}',
554
+ make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name),
555
+ )
556
+ ]
488
557
 
489
558
  def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
490
559
  for refname, (docname, node_id, typ) in list(self.objects.items()):
@@ -503,7 +572,16 @@ class JavaScriptDomain(Domain):
503
572
  def setup(app: Sphinx) -> ExtensionMetadata:
504
573
  app.add_domain(JavaScriptDomain)
505
574
  app.add_config_value(
506
- 'javascript_maximum_signature_line_length', None, 'env', {int, type(None)},
575
+ 'javascript_maximum_signature_line_length',
576
+ None,
577
+ 'env',
578
+ types=frozenset({int, NoneType}),
579
+ )
580
+ app.add_config_value(
581
+ 'javascript_trailing_comma_in_multi_line_signatures',
582
+ True,
583
+ 'env',
584
+ types=frozenset({bool}),
507
585
  )
508
586
  return {
509
587
  'version': 'builtin',
sphinx/domains/math.py CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from docutils import nodes
8
- from docutils.nodes import Element, Node, make_id, system_message
8
+ from docutils.nodes import make_id
9
9
 
10
10
  from sphinx.domains import Domain
11
11
  from sphinx.locale import __
@@ -15,6 +15,9 @@ from sphinx.util.nodes import make_refnode
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from collections.abc import Iterable, Set
18
+ from typing import Any
19
+
20
+ from docutils.nodes import Element, Node, system_message
18
21
 
19
22
  from sphinx.addnodes import pending_xref
20
23
  from sphinx.application import Sphinx
@@ -27,8 +30,13 @@ logger = logging.getLogger(__name__)
27
30
 
28
31
 
29
32
  class MathReferenceRole(XRefRole):
30
- def result_nodes(self, document: nodes.document, env: BuildEnvironment, node: Element,
31
- is_ref: bool) -> tuple[list[Node], list[system_message]]:
33
+ def result_nodes(
34
+ self,
35
+ document: nodes.document,
36
+ env: BuildEnvironment,
37
+ node: Element,
38
+ is_ref: bool,
39
+ ) -> tuple[list[Node], list[system_message]]:
32
40
  node['refdomain'] = 'math'
33
41
  return [node], []
34
42
 
@@ -41,7 +49,6 @@ class MathDomain(Domain):
41
49
 
42
50
  initial_data: dict[str, Any] = {
43
51
  'objects': {}, # labelid -> (docname, eqno)
44
- 'has_equations': {}, # docname -> bool
45
52
  }
46
53
  dangling_warnings = {
47
54
  'eq': 'equation not found: %(target)s',
@@ -60,8 +67,12 @@ class MathDomain(Domain):
60
67
  def note_equation(self, docname: str, labelid: str, location: Any = None) -> None:
61
68
  if labelid in self.equations:
62
69
  other = self.equations[labelid][0]
63
- logger.warning(__('duplicate label of equation %s, other instance in %s'),
64
- labelid, other, location=location)
70
+ logger.warning(
71
+ __('duplicate label of equation %s, other instance in %s'),
72
+ labelid,
73
+ other,
74
+ location=location,
75
+ )
65
76
 
66
77
  self.equations[labelid] = (docname, self.env.new_serialno('eqno') + 1)
67
78
 
@@ -71,32 +82,27 @@ class MathDomain(Domain):
71
82
  else:
72
83
  return None
73
84
 
74
- def process_doc(self, env: BuildEnvironment, docname: str,
75
- document: nodes.document) -> None:
76
- def math_node(node: Node) -> bool:
77
- return isinstance(node, nodes.math | nodes.math_block)
78
-
79
- self.data['has_equations'][docname] = any(document.findall(math_node))
80
-
81
85
  def clear_doc(self, docname: str) -> None:
82
86
  for equation_id, (doc, _eqno) in list(self.equations.items()):
83
87
  if doc == docname:
84
88
  del self.equations[equation_id]
85
89
 
86
- self.data['has_equations'].pop(docname, None)
87
-
88
90
  def merge_domaindata(self, docnames: Set[str], otherdata: dict[str, Any]) -> None:
89
91
  for labelid, (doc, eqno) in otherdata['objects'].items():
90
92
  if doc in docnames:
91
93
  self.equations[labelid] = (doc, eqno)
92
94
 
93
- for docname in docnames:
94
- self.data['has_equations'][docname] = otherdata['has_equations'][docname]
95
-
96
- def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
97
- typ: str, target: str, node: pending_xref, contnode: Element,
98
- ) -> Element | None:
99
- assert typ in ('eq', 'numref')
95
+ def resolve_xref(
96
+ self,
97
+ env: BuildEnvironment,
98
+ fromdocname: str,
99
+ builder: Builder,
100
+ typ: str,
101
+ target: str,
102
+ node: pending_xref,
103
+ contnode: Element,
104
+ ) -> nodes.reference | None:
105
+ assert typ in {'eq', 'numref'}
100
106
  result = self.equations.get(target)
101
107
  if result:
102
108
  docname, number = result
@@ -104,7 +110,8 @@ class MathDomain(Domain):
104
110
  node_id = make_id('equation-%s' % target)
105
111
  if env.config.math_numfig and env.config.numfig:
106
112
  if docname in env.toc_fignumbers:
107
- numbers = env.toc_fignumbers[docname]['displaymath'].get(node_id, ())
113
+ toc_dm = env.toc_fignumbers[docname]['displaymath']
114
+ numbers = toc_dm.get(node_id, ())
108
115
  eqno = '.'.join(map(str, numbers))
109
116
  eqno = env.config.math_numsep.join(eqno.rsplit('.', 1))
110
117
  else:
@@ -113,21 +120,27 @@ class MathDomain(Domain):
113
120
  eqno = str(number)
114
121
 
115
122
  try:
116
- eqref_format = env.config.math_eqref_format or "({number})"
123
+ eqref_format = env.config.math_eqref_format or '({number})'
117
124
  title = nodes.Text(eqref_format.format(number=eqno))
118
125
  except KeyError as exc:
119
- logger.warning(__('Invalid math_eqref_format: %r'), exc,
120
- location=node)
121
- title = nodes.Text("(%d)" % number)
122
- title = nodes.Text("(%d)" % number)
126
+ logger.warning(__('Invalid math_eqref_format: %r'), exc, location=node)
127
+ title = nodes.Text('(%d)' % number)
123
128
  return make_refnode(builder, fromdocname, docname, node_id, title)
124
129
  else:
125
130
  return None
126
131
 
127
- def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
128
- target: str, node: pending_xref, contnode: Element,
129
- ) -> list[tuple[str, Element]]:
130
- refnode = self.resolve_xref(env, fromdocname, builder, 'eq', target, node, contnode)
132
+ def resolve_any_xref(
133
+ self,
134
+ env: BuildEnvironment,
135
+ fromdocname: str,
136
+ builder: Builder,
137
+ target: str,
138
+ node: pending_xref,
139
+ contnode: Element,
140
+ ) -> list[tuple[str, nodes.reference]]:
141
+ refnode = self.resolve_xref(
142
+ env, fromdocname, builder, 'eq', target, node, contnode
143
+ )
131
144
  if refnode is None:
132
145
  return []
133
146
  else:
@@ -137,13 +150,8 @@ class MathDomain(Domain):
137
150
  return []
138
151
 
139
152
  def has_equations(self, docname: str | None = None) -> bool:
140
- if not docname:
141
- return any(self.data['has_equations'].values())
142
-
143
- return (
144
- self.data['has_equations'].get(docname, False)
145
- or any(map(self.has_equations, self.env.toctree_includes.get(docname, ())))
146
- )
153
+ # retained for backwards compatibility
154
+ return True
147
155
 
148
156
 
149
157
  def setup(app: Sphinx) -> ExtensionMetadata: