Sphinx 8.2.0rc1__py3-none-any.whl → 8.2.0rc2__py3-none-any.whl

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

Potentially problematic release.


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

sphinx/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = '8.2.0rc1'
5
+ __version__ = '8.2.0rc2'
6
6
  __display_version__ = __version__ # used for command line version
7
7
 
8
8
  # Keep this file executable as-is in Python 3!
@@ -34,7 +34,7 @@ warnings.filterwarnings(
34
34
  #:
35
35
  #: .. versionadded:: 1.2
36
36
  #: Before version 1.2, check the string ``sphinx.__version__``.
37
- version_info = (8, 2, 0, 'candidate', 1)
37
+ version_info = (8, 2, 0, 'candidate', 2)
38
38
 
39
39
  package_dir = _StrPath(__file__).resolve().parent
40
40
 
sphinx/application.py CHANGED
@@ -1116,7 +1116,7 @@ class Sphinx:
1116
1116
  logger.debug('[app] adding directive: %r', (name, cls))
1117
1117
  if not override and docutils.is_directive_registered(name):
1118
1118
  logger.warning(
1119
- __('directive %r is already registered, it will be overridden'),
1119
+ __('directive %r is already registered and will not be overridden'),
1120
1120
  name,
1121
1121
  type='app',
1122
1122
  subtype='add_directive',
@@ -1142,7 +1142,7 @@ class Sphinx:
1142
1142
  logger.debug('[app] adding role: %r', (name, role))
1143
1143
  if not override and docutils.is_role_registered(name):
1144
1144
  logger.warning(
1145
- __('role %r is already registered, it will be overridden'),
1145
+ __('role %r is already registered and will not be overridden'),
1146
1146
  name,
1147
1147
  type='app',
1148
1148
  subtype='add_role',
@@ -1170,7 +1170,7 @@ class Sphinx:
1170
1170
  logger.debug('[app] adding generic role: %r', (name, nodeclass))
1171
1171
  if not override and docutils.is_role_registered(name):
1172
1172
  logger.warning(
1173
- __('role %r is already registered, it will be overridden'),
1173
+ __('role %r is already registered and will not be overridden'),
1174
1174
  name,
1175
1175
  type='app',
1176
1176
  subtype='add_generic_role',
sphinx/domains/math.py CHANGED
@@ -49,6 +49,8 @@ class MathDomain(Domain):
49
49
 
50
50
  initial_data: dict[str, Any] = {
51
51
  'objects': {}, # labelid -> (docname, eqno)
52
+ # backwards compatibility
53
+ 'has_equations': {}, # https://github.com/sphinx-doc/sphinx/issues/13346
52
54
  }
53
55
  dangling_warnings = {
54
56
  'eq': 'equation not found: %(target)s',
@@ -12,6 +12,7 @@ from docutils import nodes
12
12
 
13
13
  from sphinx import addnodes
14
14
  from sphinx.addnodes import pending_xref, pending_xref_condition
15
+ from sphinx.locale import _
15
16
  from sphinx.pycode.parser import Token, TokenProcessor
16
17
  from sphinx.util.inspect import signature_from_str
17
18
 
@@ -479,19 +480,13 @@ def _parse_arglist(
479
480
  last_kind = None
480
481
  for param in sig.parameters.values():
481
482
  if param.kind != param.POSITIONAL_ONLY and last_kind == param.POSITIONAL_ONLY:
482
- # PEP-570: Separator for Positional Only Parameter: /
483
- params += addnodes.desc_parameter(
484
- '', '', addnodes.desc_sig_operator('', '/')
485
- )
483
+ params += _positional_only_separator()
486
484
  if param.kind == param.KEYWORD_ONLY and last_kind in {
487
485
  param.POSITIONAL_OR_KEYWORD,
488
486
  param.POSITIONAL_ONLY,
489
487
  None,
490
488
  }:
491
- # PEP-3102: Separator for Keyword Only Parameter: *
492
- params += addnodes.desc_parameter(
493
- '', '', addnodes.desc_sig_operator('', '*')
494
- )
489
+ params += _keyword_only_separator()
495
490
 
496
491
  node = addnodes.desc_parameter()
497
492
  if param.kind == param.VAR_POSITIONAL:
@@ -523,12 +518,33 @@ def _parse_arglist(
523
518
  last_kind = param.kind
524
519
 
525
520
  if last_kind == Parameter.POSITIONAL_ONLY:
526
- # PEP-570: Separator for Positional Only Parameter: /
527
- params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
521
+ params += _positional_only_separator()
528
522
 
529
523
  return params
530
524
 
531
525
 
526
+ def _positional_only_separator() -> addnodes.desc_parameter:
527
+ # PEP 570: Separator for positional only parameters: /
528
+ positional_only_abbr = nodes.abbreviation(
529
+ '/', '/', explanation=_('Positional-only parameter separator (PEP 570)')
530
+ )
531
+ positional_only_op = addnodes.desc_sig_operator(
532
+ '/', '', positional_only_abbr, classes=['positional-only-separator']
533
+ )
534
+ return addnodes.desc_parameter('/', '', positional_only_op)
535
+
536
+
537
+ def _keyword_only_separator() -> addnodes.desc_parameter:
538
+ # PEP 3102: Separator for keyword only parameters: *
539
+ keyword_only_abbr = nodes.abbreviation(
540
+ '*', '*', explanation=_('Keyword-only parameters separator (PEP 3102)')
541
+ )
542
+ keyword_only_op = addnodes.desc_sig_operator(
543
+ '*', '', keyword_only_abbr, classes=['keyword-only-separator']
544
+ )
545
+ return addnodes.desc_parameter('*', '', keyword_only_op)
546
+
547
+
532
548
  def _pseudo_parse_arglist(
533
549
  signode: desc_signature,
534
550
  arglist: str,
@@ -352,11 +352,14 @@ class PyObject(ObjectDescription[tuple[str, str]]):
352
352
  multi_line_parameter_list,
353
353
  trailing_comma,
354
354
  )
355
- except SyntaxError:
355
+ except SyntaxError as exc:
356
356
  # fallback to parse arglist original parser
357
357
  # (this may happen if the argument list is incorrectly used
358
358
  # as a list of bases when documenting a class)
359
359
  # it supports to represent optional arguments (ex. "func(foo [, bar])")
360
+ logger.debug(
361
+ 'syntax error in arglist (%r): %s', arglist, exc, location=signode
362
+ )
360
363
  _pseudo_parse_arglist(
361
364
  signode,
362
365
  arglist,
@@ -13,9 +13,54 @@ from __future__ import annotations
13
13
 
14
14
  from typing import TYPE_CHECKING
15
15
 
16
+ import sphinx
16
17
  from sphinx.ext.apidoc._cli import main
17
18
 
18
19
  if TYPE_CHECKING:
19
20
  from collections.abc import Sequence
20
21
 
21
- __all__: Sequence[str] = ('main',)
22
+ from sphinx.application import Sphinx
23
+ from sphinx.util.typing import ExtensionMetadata
24
+
25
+ __all__: Sequence[str] = 'main', 'setup'
26
+
27
+
28
+ def setup(app: Sphinx) -> ExtensionMetadata:
29
+ from sphinx.ext.apidoc._extension import run_apidoc
30
+
31
+ # Require autodoc
32
+ app.setup_extension('sphinx.ext.autodoc')
33
+
34
+ # Configuration values
35
+ app.add_config_value(
36
+ 'apidoc_exclude_patterns', (), 'env', types=frozenset({list, tuple})
37
+ )
38
+ app.add_config_value('apidoc_max_depth', 4, 'env', types=frozenset({int}))
39
+ app.add_config_value('apidoc_follow_links', False, 'env', types=frozenset({bool}))
40
+ app.add_config_value(
41
+ 'apidoc_separate_modules', False, 'env', types=frozenset({bool})
42
+ )
43
+ app.add_config_value(
44
+ 'apidoc_include_private', False, 'env', types=frozenset({bool})
45
+ )
46
+ app.add_config_value('apidoc_no_headings', False, 'env', types=frozenset({bool}))
47
+ app.add_config_value('apidoc_module_first', False, 'env', types=frozenset({bool}))
48
+ app.add_config_value(
49
+ 'apidoc_implicit_namespaces', False, 'env', types=frozenset({bool})
50
+ )
51
+ app.add_config_value(
52
+ 'apidoc_automodule_options',
53
+ frozenset(('members', 'undoc-members', 'show-inheritance')),
54
+ 'env',
55
+ types=frozenset({frozenset, list, set, tuple}),
56
+ )
57
+ app.add_config_value('apidoc_modules', (), 'env', types=frozenset({list, tuple}))
58
+
59
+ # Entry point to run apidoc
60
+ app.connect('builder-inited', run_apidoc)
61
+
62
+ return {
63
+ 'version': sphinx.__display_version__,
64
+ 'parallel_read_safe': True,
65
+ 'parallel_write_safe': True,
66
+ }
sphinx/ext/apidoc/_cli.py CHANGED
@@ -55,7 +55,7 @@ Note: By default this script will not overwrite already created files."""),
55
55
  '-o',
56
56
  '--output-dir',
57
57
  action='store',
58
- dest='destdir',
58
+ dest='dest_dir',
59
59
  required=True,
60
60
  help=__('directory to place all output'),
61
61
  )
@@ -69,7 +69,7 @@ Note: By default this script will not overwrite already created files."""),
69
69
  '-d',
70
70
  '--maxdepth',
71
71
  action='store',
72
- dest='maxdepth',
72
+ dest='max_depth',
73
73
  type=int,
74
74
  default=4,
75
75
  help=__('maximum depth of submodules to show in the TOC (default: 4)'),
@@ -85,7 +85,7 @@ Note: By default this script will not overwrite already created files."""),
85
85
  '-l',
86
86
  '--follow-links',
87
87
  action='store_true',
88
- dest='followlinks',
88
+ dest='follow_links',
89
89
  default=False,
90
90
  help=__(
91
91
  'follow symbolic links. Powerful when combined with collective.recipe.omelette.'
@@ -95,27 +95,27 @@ Note: By default this script will not overwrite already created files."""),
95
95
  '-n',
96
96
  '--dry-run',
97
97
  action='store_true',
98
- dest='dryrun',
98
+ dest='dry_run',
99
99
  help=__('run the script without creating files'),
100
100
  )
101
101
  parser.add_argument(
102
102
  '-e',
103
103
  '--separate',
104
104
  action='store_true',
105
- dest='separatemodules',
105
+ dest='separate_modules',
106
106
  help=__('put documentation for each module on its own page'),
107
107
  )
108
108
  parser.add_argument(
109
109
  '-P',
110
110
  '--private',
111
111
  action='store_true',
112
- dest='includeprivate',
112
+ dest='include_private',
113
113
  help=__('include "_private" modules'),
114
114
  )
115
115
  parser.add_argument(
116
116
  '--tocfile',
117
117
  action='store',
118
- dest='tocfile',
118
+ dest='toc_file',
119
119
  default='modules',
120
120
  help=__('filename of table of contents (default: modules)'),
121
121
  )
@@ -123,14 +123,14 @@ Note: By default this script will not overwrite already created files."""),
123
123
  '-T',
124
124
  '--no-toc',
125
125
  action='store_false',
126
- dest='tocfile',
126
+ dest='toc_file',
127
127
  help=__("don't create a table of contents file"),
128
128
  )
129
129
  parser.add_argument(
130
130
  '-E',
131
131
  '--no-headings',
132
132
  action='store_true',
133
- dest='noheadings',
133
+ dest='no_headings',
134
134
  help=__(
135
135
  "don't create headings for the module/package "
136
136
  'packages (e.g. when the docstrings already '
@@ -141,7 +141,7 @@ Note: By default this script will not overwrite already created files."""),
141
141
  '-M',
142
142
  '--module-first',
143
143
  action='store_true',
144
- dest='modulefirst',
144
+ dest='module_first',
145
145
  help=__('put module documentation before submodule documentation'),
146
146
  )
147
147
  parser.add_argument(
@@ -245,7 +245,7 @@ Note: By default this script will not overwrite already created files."""),
245
245
  '-t',
246
246
  '--templatedir',
247
247
  metavar='TEMPLATEDIR',
248
- dest='templatedir',
248
+ dest='template_dir',
249
249
  help=__('template directory for template files'),
250
250
  )
251
251
 
@@ -264,17 +264,17 @@ def main(argv: Sequence[str] = (), /) -> int:
264
264
  for exclude in dict.fromkeys(opts.exclude_pattern)
265
265
  )
266
266
 
267
- written_files, modules = recurse_tree(rootpath, excludes, opts, opts.templatedir)
267
+ written_files, modules = recurse_tree(rootpath, excludes, opts, opts.template_dir)
268
268
 
269
269
  if opts.full:
270
270
  _full_quickstart(opts, modules=modules)
271
- elif opts.tocfile:
271
+ elif opts.toc_file:
272
272
  written_files.append(
273
- create_modules_toc_file(modules, opts, opts.tocfile, opts.templatedir)
273
+ create_modules_toc_file(modules, opts, opts.toc_file, opts.template_dir)
274
274
  )
275
275
 
276
- if opts.remove_old and not opts.dryrun:
277
- _remove_old_files(written_files, opts.destdir, opts.suffix)
276
+ if opts.remove_old and not opts.dry_run:
277
+ _remove_old_files(written_files, opts.dest_dir, opts.suffix)
278
278
 
279
279
  return 0
280
280
 
@@ -286,7 +286,7 @@ def _parse_args(argv: Sequence[str], /) -> ApidocOptions:
286
286
  # normalise options
287
287
 
288
288
  args.module_path = root_path = Path(args.module_path).resolve()
289
- args.destdir = Path(args.destdir)
289
+ args.dest_dir = Path(args.dest_dir)
290
290
  if not root_path.is_dir():
291
291
  LOGGER.error(__('%s is not a directory.'), root_path)
292
292
  raise SystemExit(1)
@@ -295,13 +295,13 @@ def _parse_args(argv: Sequence[str], /) -> ApidocOptions:
295
295
  args.header = root_path.name
296
296
  args.suffix = args.suffix.removeprefix('.')
297
297
 
298
- if not args.dryrun:
299
- ensuredir(args.destdir)
298
+ if not args.dry_run:
299
+ ensuredir(args.dest_dir)
300
300
 
301
301
  if not args.automodule_options:
302
- args.automodule_options = set()
302
+ args.automodule_options = frozenset()
303
303
  elif isinstance(args.automodule_options, str):
304
- args.automodule_options = set(args.automodule_options.split(','))
304
+ args.automodule_options = frozenset(args.automodule_options.split(','))
305
305
 
306
306
  return ApidocOptions(**args.__dict__)
307
307
 
@@ -318,7 +318,7 @@ def _full_quickstart(opts: ApidocOptions, /, *, modules: list[str]) -> None:
318
318
  prev_module = module
319
319
  text += f' {module}\n'
320
320
  d: dict[str, Any] = {
321
- 'path': str(opts.destdir),
321
+ 'path': str(opts.dest_dir),
322
322
  'sep': False,
323
323
  'dot': '_',
324
324
  'project': opts.header,
@@ -336,7 +336,7 @@ def _full_quickstart(opts: ApidocOptions, /, *, modules: list[str]) -> None:
336
336
  'makefile': True,
337
337
  'batchfile': True,
338
338
  'make_mode': True,
339
- 'mastertocmaxdepth': opts.maxdepth,
339
+ 'mastertocmaxdepth': opts.max_depth,
340
340
  'mastertoctree': text,
341
341
  'language': 'en',
342
342
  'module_path': str(opts.module_path),
@@ -352,5 +352,5 @@ def _full_quickstart(opts: ApidocOptions, /, *, modules: list[str]) -> None:
352
352
  d['extensions'].remove(ext)
353
353
  d['extensions'].extend(ext.split(','))
354
354
 
355
- if not opts.dryrun:
356
- qs.generate(d, silent=True, overwrite=opts.force, templatedir=opts.templatedir)
355
+ if not opts.dry_run:
356
+ qs.generate(d, silent=True, overwrite=opts.force, templatedir=opts.template_dir)
@@ -0,0 +1,262 @@
1
+ """Sphinx extension for auto-generating API documentation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import fnmatch
6
+ import re
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING
9
+
10
+ from sphinx._cli.util.colour import bold
11
+ from sphinx.ext.apidoc._generate import create_modules_toc_file, recurse_tree
12
+ from sphinx.ext.apidoc._shared import (
13
+ LOGGER,
14
+ ApidocDefaults,
15
+ ApidocOptions,
16
+ _remove_old_files,
17
+ )
18
+ from sphinx.locale import __
19
+
20
+ if TYPE_CHECKING:
21
+ from collections.abc import Collection, Sequence
22
+ from typing import Any
23
+
24
+ from sphinx.application import Sphinx
25
+
26
+ _BOOL_KEYS = frozenset({
27
+ 'follow_links',
28
+ 'separate_modules',
29
+ 'include_private',
30
+ 'no_headings',
31
+ 'module_first',
32
+ 'implicit_namespaces',
33
+ })
34
+ _ALLOWED_KEYS = _BOOL_KEYS | frozenset({
35
+ 'path',
36
+ 'destination',
37
+ 'exclude_patterns',
38
+ 'automodule_options',
39
+ 'max_depth',
40
+ })
41
+
42
+
43
+ def run_apidoc(app: Sphinx) -> None:
44
+ """Run the apidoc extension."""
45
+ defaults = ApidocDefaults.from_config(app.config)
46
+ apidoc_modules: Sequence[dict[str, Any]] = app.config.apidoc_modules
47
+ srcdir: Path = app.srcdir
48
+ confdir: Path = app.confdir
49
+
50
+ LOGGER.info(bold(__('Running apidoc')))
51
+
52
+ module_options: dict[str, Any]
53
+ for i, module_options in enumerate(apidoc_modules):
54
+ _run_apidoc_module(
55
+ i,
56
+ options=module_options,
57
+ defaults=defaults,
58
+ srcdir=srcdir,
59
+ confdir=confdir,
60
+ )
61
+
62
+
63
+ def _run_apidoc_module(
64
+ i: int,
65
+ *,
66
+ options: dict[str, Any],
67
+ defaults: ApidocDefaults,
68
+ srcdir: Path,
69
+ confdir: Path,
70
+ ) -> None:
71
+ """Run apidoc for a single module."""
72
+ args = _parse_module_options(
73
+ i, options=options, defaults=defaults, srcdir=srcdir, confdir=confdir
74
+ )
75
+ if args is None:
76
+ return
77
+
78
+ exclude_patterns_compiled: list[re.Pattern[str]] = [
79
+ re.compile(fnmatch.translate(exclude)) for exclude in args.exclude_pattern
80
+ ]
81
+
82
+ written_files, modules = recurse_tree(
83
+ args.module_path, exclude_patterns_compiled, args, args.template_dir
84
+ )
85
+ if args.toc_file:
86
+ written_files.append(
87
+ create_modules_toc_file(modules, args, args.toc_file, args.template_dir)
88
+ )
89
+ if args.remove_old:
90
+ _remove_old_files(written_files, args.dest_dir, args.suffix)
91
+
92
+
93
+ def _parse_module_options(
94
+ i: int,
95
+ *,
96
+ options: dict[str, Any],
97
+ defaults: ApidocDefaults,
98
+ srcdir: Path,
99
+ confdir: Path,
100
+ ) -> ApidocOptions | None:
101
+ if not isinstance(options, dict):
102
+ LOGGER.warning(__('apidoc_modules item %i must be a dict'), i, type='apidoc')
103
+ return None
104
+
105
+ # module path should be absolute or relative to the conf directory
106
+ try:
107
+ path = Path(options['path'])
108
+ except KeyError:
109
+ LOGGER.warning(
110
+ __("apidoc_modules item %i must have a 'path' key"), i, type='apidoc'
111
+ )
112
+ return None
113
+ except TypeError:
114
+ LOGGER.warning(
115
+ __("apidoc_modules item %i 'path' must be a string"), i, type='apidoc'
116
+ )
117
+ return None
118
+ module_path = confdir / path
119
+ if not module_path.is_dir():
120
+ LOGGER.warning(
121
+ __("apidoc_modules item %i 'path' is not an existing folder: %s"),
122
+ i,
123
+ module_path,
124
+ type='apidoc',
125
+ )
126
+ return None
127
+
128
+ # destination path should be relative to the source directory
129
+ try:
130
+ destination = Path(options['destination'])
131
+ except KeyError:
132
+ LOGGER.warning(
133
+ __("apidoc_modules item %i must have a 'destination' key"),
134
+ i,
135
+ type='apidoc',
136
+ )
137
+ return None
138
+ except TypeError:
139
+ LOGGER.warning(
140
+ __("apidoc_modules item %i 'destination' must be a string"),
141
+ i,
142
+ type='apidoc',
143
+ )
144
+ return None
145
+ if destination.is_absolute():
146
+ LOGGER.warning(
147
+ __("apidoc_modules item %i 'destination' should be a relative path"),
148
+ i,
149
+ type='apidoc',
150
+ )
151
+ return None
152
+ dest_path = srcdir / destination
153
+ try:
154
+ dest_path.mkdir(parents=True, exist_ok=True)
155
+ except OSError as exc:
156
+ LOGGER.warning(
157
+ __('apidoc_modules item %i cannot create destination directory: %s'),
158
+ i,
159
+ exc.strerror,
160
+ type='apidoc',
161
+ )
162
+ return None
163
+
164
+ # exclude patterns should be absolute or relative to the conf directory
165
+ exclude_patterns: list[str] = [
166
+ str(confdir / pattern)
167
+ for pattern in _check_collection_of_strings(
168
+ i, options, key='exclude_patterns', default=defaults.exclude_patterns
169
+ )
170
+ ]
171
+
172
+ # TODO template_dir
173
+
174
+ max_depth = defaults.max_depth
175
+ if 'max_depth' in options:
176
+ if not isinstance(options['max_depth'], int):
177
+ LOGGER.warning(
178
+ __("apidoc_modules item %i '%s' must be an int"),
179
+ i,
180
+ 'max_depth',
181
+ type='apidoc',
182
+ )
183
+ else:
184
+ max_depth = options['max_depth']
185
+
186
+ bool_options: dict[str, bool] = {}
187
+ for key in sorted(_BOOL_KEYS):
188
+ if key not in options:
189
+ bool_options[key] = getattr(defaults, key)
190
+ elif not isinstance(options[key], bool):
191
+ LOGGER.warning(
192
+ __("apidoc_modules item %i '%s' must be a boolean"),
193
+ i,
194
+ key,
195
+ type='apidoc',
196
+ )
197
+ bool_options[key] = getattr(defaults, key)
198
+ else:
199
+ bool_options[key] = options[key]
200
+
201
+ # TODO per-module automodule_options
202
+ automodule_options = frozenset(
203
+ _check_collection_of_strings(
204
+ i, options, key='automodule_options', default=defaults.automodule_options
205
+ )
206
+ )
207
+
208
+ if diff := options.keys() - _ALLOWED_KEYS:
209
+ LOGGER.warning(
210
+ __('apidoc_modules item %i has unexpected keys: %s'),
211
+ i,
212
+ ', '.join(sorted(diff)),
213
+ type='apidoc',
214
+ )
215
+
216
+ return ApidocOptions(
217
+ dest_dir=dest_path,
218
+ module_path=module_path,
219
+ exclude_pattern=exclude_patterns,
220
+ automodule_options=automodule_options,
221
+ max_depth=max_depth,
222
+ quiet=True,
223
+ follow_links=bool_options['follow_links'],
224
+ separate_modules=bool_options['separate_modules'],
225
+ include_private=bool_options['include_private'],
226
+ no_headings=bool_options['no_headings'],
227
+ module_first=bool_options['module_first'],
228
+ implicit_namespaces=bool_options['implicit_namespaces'],
229
+ )
230
+
231
+
232
+ def _check_collection_of_strings(
233
+ index: int,
234
+ options: dict[str, Any],
235
+ *,
236
+ key: str,
237
+ default: Collection[str],
238
+ ) -> Collection[str]:
239
+ """Check that a key's value is a collection of strings in the options.
240
+
241
+ :returns: The value of the key, or None if invalid.
242
+ """
243
+ if key not in options:
244
+ return default
245
+ if not isinstance(options[key], list | tuple | set | frozenset):
246
+ LOGGER.warning(
247
+ __("apidoc_modules item %i '%s' must be a sequence"),
248
+ index,
249
+ key,
250
+ type='apidoc',
251
+ )
252
+ return default
253
+ for item in options[key]:
254
+ if not isinstance(item, str):
255
+ LOGGER.warning(
256
+ __("apidoc_modules item %i '%s' must contain strings"),
257
+ index,
258
+ key,
259
+ type='apidoc',
260
+ )
261
+ return default
262
+ return options[key]
@@ -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
+ )
@@ -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():
@@ -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]:
sphinx/writers/html5.py CHANGED
@@ -906,8 +906,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
906
906
 
907
907
  def visit_abbreviation(self, node: Element) -> None:
908
908
  attrs = {}
909
- if node.hasattr('explanation'):
910
- attrs['title'] = node['explanation']
909
+ if explanation := node.get('explanation', ''):
910
+ attrs['title'] = explanation
911
911
  self.body.append(self.starttag(node, 'abbr', '', **attrs))
912
912
 
913
913
  def depart_abbreviation(self, node: Element) -> None:
sphinx/writers/latex.py CHANGED
@@ -2082,11 +2082,12 @@ class LaTeXTranslator(SphinxTranslator):
2082
2082
  self.body.append('}}')
2083
2083
 
2084
2084
  def visit_abbreviation(self, node: Element) -> None:
2085
+ explanation = node.get('explanation', '')
2085
2086
  abbr = node.astext()
2086
2087
  self.body.append(r'\sphinxstyleabbreviation{')
2087
2088
  # spell out the explanation once
2088
- if node.hasattr('explanation') and abbr not in self.handled_abbrs:
2089
- self.context.append('} (%s)' % self.encode(node['explanation']))
2089
+ if explanation and abbr not in self.handled_abbrs:
2090
+ self.context.append('} (%s)' % self.encode(explanation))
2090
2091
  self.handled_abbrs.add(abbr)
2091
2092
  else:
2092
2093
  self.context.append('}')
sphinx/writers/texinfo.py CHANGED
@@ -1537,10 +1537,11 @@ class TexinfoTranslator(SphinxTranslator):
1537
1537
  pass
1538
1538
 
1539
1539
  def visit_abbreviation(self, node: Element) -> None:
1540
+ explanation = node.get('explanation', '')
1540
1541
  abbr = node.astext()
1541
1542
  self.body.append('@abbr{')
1542
- if node.hasattr('explanation') and abbr not in self.handled_abbrs:
1543
- self.context.append(',%s}' % self.escape_arg(node['explanation']))
1543
+ if explanation and abbr not in self.handled_abbrs:
1544
+ self.context.append(',%s}' % self.escape_arg(explanation))
1544
1545
  self.handled_abbrs.add(abbr)
1545
1546
  else:
1546
1547
  self.context.append('}')
sphinx/writers/text.py CHANGED
@@ -1237,8 +1237,8 @@ class TextTranslator(SphinxTranslator):
1237
1237
  self.add_text('')
1238
1238
 
1239
1239
  def depart_abbreviation(self, node: Element) -> None:
1240
- if node.hasattr('explanation'):
1241
- self.add_text(' (%s)' % node['explanation'])
1240
+ if explanation := node.get('explanation', ''):
1241
+ self.add_text(f' ({explanation})')
1242
1242
 
1243
1243
  def visit_manpage(self, node: Element) -> None:
1244
1244
  return self.visit_literal_emphasis(node)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Sphinx
3
- Version: 8.2.0rc1
3
+ Version: 8.2.0rc2
4
4
  Summary: Python documentation generator
5
5
  Author-email: Adam Turner <aa-turner@users.noreply.github.com>, Georg Brandl <georg@python.org>
6
6
  Requires-Python: >=3.11
@@ -80,6 +80,8 @@ Requires-Dist: types-requests==2.32.0.20241016 ; extra == "lint"
80
80
  Requires-Dist: types-urllib3==1.26.25.14 ; extra == "lint"
81
81
  Requires-Dist: pyright==1.1.394 ; extra == "lint"
82
82
  Requires-Dist: pytest>=8.0 ; extra == "lint"
83
+ Requires-Dist: pypi-attestations==0.0.21 ; extra == "lint"
84
+ Requires-Dist: betterproto==2.0.0b6 ; extra == "lint"
83
85
  Requires-Dist: pytest>=8.0 ; extra == "test"
84
86
  Requires-Dist: pytest-xdist[psutil]>=3.4 ; extra == "test"
85
87
  Requires-Dist: defusedxml>=0.7.1 ; extra == "test"
@@ -1,7 +1,7 @@
1
- sphinx/__init__.py,sha256=dVckQZ6ig5QscpPmyYL2kdkRNqT5haCioIizMTwSh3A,1796
1
+ sphinx/__init__.py,sha256=lfwYis272_lwAvX7LUgeOdj89vxhx5LYGdyOUd4cnPw,1796
2
2
  sphinx/__main__.py,sha256=PYSg7M8rY5VgULh3SJEaYMWsB1YFJw7f40b50yW8NEE,163
3
3
  sphinx/addnodes.py,sha256=QFvrCg9bGgH_zsGFVeUzGWcvqIQXtC-b7jXUYZEJRsk,18502
4
- sphinx/application.py,sha256=hu8uHn5oJf9c-OE3Dv8ivjaq1e-MbBFalY5yY1HB24U,66881
4
+ sphinx/application.py,sha256=FgR54sWE9-hH548ZUbe3x0v_NlRRUAZ4JjorhwDF8eg,66893
5
5
  sphinx/config.py,sha256=7Raa_GVF6S0uZWDbYL6VkG9N8OlKHM7g5s5CPgyHNtU,34297
6
6
  sphinx/deprecation.py,sha256=U4BIydQiXjU3seaMOORp6bVeVleg-3xcAl_iU7bu2eA,2521
7
7
  sphinx/errors.py,sha256=lk9KPV3Grp64NwoU81JhK0rr1ybBS_d2iaXyhosVrSg,3413
@@ -60,7 +60,7 @@ sphinx/domains/changeset.py,sha256=1X6fd-jiMIXShGfTpcHJMSddhh2dfEQ2PuTR9BTJrHw,5
60
60
  sphinx/domains/citation.py,sha256=SJf91v0GSlSOIrlbzXyGIIzmnbQTzphyBnoidATcIfo,6019
61
61
  sphinx/domains/index.py,sha256=cil8Ona4hde42Pj0T94LJoap6nGiLl3SOgB-_pv6ats,4341
62
62
  sphinx/domains/javascript.py,sha256=3ppeTmxJ8UqNYw_vsycIML9O-PmUh11iO1AeyTMHPxU,20359
63
- sphinx/domains/math.py,sha256=o3LWsF1-8FknDD66doR26Bru-eg_kasA0etHO2D_cTE,5163
63
+ sphinx/domains/math.py,sha256=hUIZZQj0_jxEvIjyTz-a0JXEeNbWYUETpksGQJJYxlI,5279
64
64
  sphinx/domains/rst.py,sha256=4f_9iD51aLTg7RmG4IX-zTUtd3jguFWVP19mxCWsnjo,11252
65
65
  sphinx/domains/c/__init__.py,sha256=cBT1gP79uP2bTU5BSnfBh9fIiShQgmQeITcqk_S7dNw,33319
66
66
  sphinx/domains/c/_ast.py,sha256=gR-xM8BBOSWqaKbWKHaD9QqXNnq9p6WvyHAnlazznlo,65877
@@ -73,8 +73,8 @@ sphinx/domains/cpp/_ids.py,sha256=jPJHiDJfOLjE4UbK-Q_HGAJ4BwdzF9Nl6btBKoVstzQ,18
73
73
  sphinx/domains/cpp/_parser.py,sha256=M-t-1Kq9hi3UOiz7uXbvvH5SASwlI-vylwNIQcoaD3E,89792
74
74
  sphinx/domains/cpp/_symbol.py,sha256=1tsROVq-jl581QK21-qB7pvRunjTQOTXHJwk677LUuo,50957
75
75
  sphinx/domains/python/__init__.py,sha256=4Aozi8Q91OvN9iVUjehu24p8hV7awVnSUHUfMEoAQiQ,38812
76
- sphinx/domains/python/_annotations.py,sha256=waAsCsmzvD-ClwJrQORKVWXg-7ZIVzA_xqBPYJXb2k0,24104
77
- sphinx/domains/python/_object.py,sha256=DTSUVp5y6Es_1NvCh_s__dpjao1busEWQpbz_oVQa7Q,18181
76
+ sphinx/domains/python/_annotations.py,sha256=n3U3HCfCaBZLFckTGeXdQvkI1MypvvQkz-CJ6H8S880,24648
77
+ sphinx/domains/python/_object.py,sha256=TnWnLL7jLs0-eW8-xHUTuXqHVjEub7DsyKMC_-37RBM,18323
78
78
  sphinx/domains/std/__init__.py,sha256=Tt5yVzybfNtHpocDE-SJgRFseYci7P3TApDoUBI0ppU,53450
79
79
  sphinx/environment/__init__.py,sha256=s7rsls8sbyYpRUYd3ZFeC1911UJNyGJOZ8USuACGI5c,42417
80
80
  sphinx/environment/adapters/__init__.py,sha256=VnDotW2UbxjWeVITmz7iTsVrzqQcvmLHr3euKqqKHwo,34
@@ -103,19 +103,20 @@ sphinx/ext/linkcode.py,sha256=GQfIOkJYeTzGZEF3w7svb1qqSE4h2zgBp_fJ_2Kev6o,3040
103
103
  sphinx/ext/mathjax.py,sha256=EjoCWBiw4vaKGw0uZnHZLjbSyDQrBL5CJuriF-OaICE,5814
104
104
  sphinx/ext/todo.py,sha256=wqLW3cy2Sd2u_1ztkajAEJdKkyL-bM65jXw8s6trSvc,8002
105
105
  sphinx/ext/viewcode.py,sha256=LFnSYN9C-Ity8956BWbWnT6DL-lH-ol2ZXv02NZy5bA,14926
106
- sphinx/ext/apidoc/__init__.py,sha256=ZQ-vDujiIGKoQAEUOQuxijGqIem24cvoE4Kqi02zyrg,632
106
+ sphinx/ext/apidoc/__init__.py,sha256=rvtSje1ayQSBwbVYJwkSPZV_NrdZiqdfvgy_dYOfAhI,2227
107
107
  sphinx/ext/apidoc/__main__.py,sha256=-kCJWW_BL2zpvylBkK3U_XqVBNKEAETeghxR_UHsJvw,182
108
- sphinx/ext/apidoc/_cli.py,sha256=YZq_RlPFbST28_RQ2CpM8Lq1wg3n3AkydxNiK1SutZ0,10145
109
- sphinx/ext/apidoc/_generate.py,sha256=MIQenFdmXQawcDvuREoOFUAUTqEApdR4sBuTI3nogb8,11895
110
- sphinx/ext/apidoc/_shared.py,sha256=Mlsrdc1N25WZRU6mvDAwEXKzYkZyYPUwM1SIZ5Fooqk,1785
111
- sphinx/ext/autodoc/__init__.py,sha256=Mfbr3-smg8dgK2VmLU1bofkr-izvzVYw-Cne0h8Isx8,121543
108
+ sphinx/ext/apidoc/_cli.py,sha256=MeApBSdy14-cXJiuEJeY1E366xFFfqSuvrYNOatcUHo,10182
109
+ sphinx/ext/apidoc/_extension.py,sha256=OjrJFA9HwEJrK392IayeGa4tnS5olRD_5FO58vxlpdw,7505
110
+ sphinx/ext/apidoc/_generate.py,sha256=EAhpB2PUwsjdPNV6UN8KCOXbgWwaeOdmV577amk29iU,11909
111
+ sphinx/ext/apidoc/_shared.py,sha256=wer5szQBKbF1be0NBW_DW2ugMb9zWZ1MvQAQE-DYbqc,2908
112
+ sphinx/ext/autodoc/__init__.py,sha256=mJxBAfeBIllFjahYOItA2Hzp1IuToICYqIG6Su0Yh3A,121552
112
113
  sphinx/ext/autodoc/directive.py,sha256=BJZK0TxBUd4TtFj9f9IKnCoWGT_dxYu6BTZUjih-hPw,6112
113
114
  sphinx/ext/autodoc/importer.py,sha256=qxvFRJA1MTMqci8jak3UlvA7de3LKp9q88pt1w-cjbI,18706
114
115
  sphinx/ext/autodoc/mock.py,sha256=OGw-6UYfZS1jVkT5gZF9X_-IzP56bmas7SyXD7rYhWY,6135
115
116
  sphinx/ext/autodoc/preserve_defaults.py,sha256=EiHd8PtR1Xhf6Mj_9jhEvPBsFOqCtMnecwAIyVIsyJA,7174
116
117
  sphinx/ext/autodoc/type_comment.py,sha256=kThxHwGawkpljf7bsT6tfchKuzyB4MOK7n6ShSmGX6I,5696
117
118
  sphinx/ext/autodoc/typehints.py,sha256=rt9RqDSiORINmvElr63kvKDt8jG3iaKOLDUmbOVbJ4w,8279
118
- sphinx/ext/autosummary/__init__.py,sha256=yUc1P67C-WB_g9dlk6uebcFgkTg0UK-uIdM91rXuoWs,34159
119
+ sphinx/ext/autosummary/__init__.py,sha256=EQt5LTPfbd9UIV6foOo5wj829qOc6K5bSUpwP_rLVUs,34547
119
120
  sphinx/ext/autosummary/generate.py,sha256=qJB7ItpMiz43xqXn5xtbUKldx7vbcPx8g-ytnfCCQ2U,30215
120
121
  sphinx/ext/autosummary/templates/autosummary/base.rst,sha256=AfG9oeDMTKBsBf2lUKr-NolOeV7ImT_JrKG3KQkEGzE,106
121
122
  sphinx/ext/autosummary/templates/autosummary/class.rst,sha256=1uu4SSX9KRCeNlcr7FMRZ-DrPuW7E6tQ7QZC1asnAL0,553
@@ -589,14 +590,14 @@ sphinx/util/texescape.py,sha256=HhjOV6qNFSF9nIddTdYozxW36AW5aScipgv6VWw0zaw,5579
589
590
  sphinx/util/typing.py,sha256=Mxhya-bwMNfO4wS2wAS1pYSB_nRR10d_kA4kduPAd6Q,25978
590
591
  sphinx/writers/__init__.py,sha256=efGdnx4MWlPEDzXACf4Q18Oi3GTyY5Ob14I_j3XXtXc,31
591
592
  sphinx/writers/html.py,sha256=S-OilBJkNb7AYA6SDdYmZ7FlPnyz-wFNWtCWNjmur4E,1911
592
- sphinx/writers/html5.py,sha256=QQe-jrd9ZqUJIku6U_ZDIJh9VovVJ2Ifq9DK7DOKNXw,38595
593
- sphinx/writers/latex.py,sha256=BsxROor8iIyjvo7J-7fKx9eZmk2oPLmTMS6ynp6UPOA,95932
593
+ sphinx/writers/html5.py,sha256=M6D7F2KxtwNmdzACx9xIBcUFU7DoXAqkpUbQjRhqpEg,38602
594
+ sphinx/writers/latex.py,sha256=uvdNZfnn1z6I59OEG1BGGiB6lYtt4fwoyI5mfYH-5wo,95958
594
595
  sphinx/writers/manpage.py,sha256=rwur1uSNhRsPlb4U1tXwtV3gqz-W1RD-yIw29Qmjxo4,15559
595
- sphinx/writers/texinfo.py,sha256=NW5AUZPllNN_8RNcLJmUWgBz0x1C7VUhpw5R1b7-oBw,52765
596
- sphinx/writers/text.py,sha256=gFnTt10DrAmI4exdOk54Tf7jUoc2GETum1yM-Qiu9N8,43911
596
+ sphinx/writers/texinfo.py,sha256=WOMdKuYov6lt9PH34gsO1UbdYE48W3GdU0sZ7tw73pE,52791
597
+ sphinx/writers/text.py,sha256=8FSF2vj0NaJHCMmHK3Rz6H8-iSMBpkyVT2VOT5-mLXA,43916
597
598
  sphinx/writers/xml.py,sha256=qaxAMR7htHmo3tQgqi9_8DD_B0HJEvz9hZH1iJwZkdk,1730
598
- sphinx-8.2.0rc1.dist-info/entry_points.txt,sha256=KU_c9jqXj7yyZylSz11XRIXG3gAZApQa0d5DmcfyA7M,188
599
- sphinx-8.2.0rc1.dist-info/LICENSE.rst,sha256=ZMlpGbuvOhO6oPEOQYzB_Ih2jOG5wH9be_SfD7I9sQY,1476
600
- sphinx-8.2.0rc1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
601
- sphinx-8.2.0rc1.dist-info/METADATA,sha256=2CSRLODfFyhCS3V7yfKv4ZiHvikX8-7sQJpYOeHOSD8,6895
602
- sphinx-8.2.0rc1.dist-info/RECORD,,
599
+ sphinx-8.2.0rc2.dist-info/entry_points.txt,sha256=KU_c9jqXj7yyZylSz11XRIXG3gAZApQa0d5DmcfyA7M,188
600
+ sphinx-8.2.0rc2.dist-info/LICENSE.rst,sha256=ZMlpGbuvOhO6oPEOQYzB_Ih2jOG5wH9be_SfD7I9sQY,1476
601
+ sphinx-8.2.0rc2.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
602
+ sphinx-8.2.0rc2.dist-info/METADATA,sha256=2alT-9iNt5jsESX3EW3ddAhXBLXGq9LCfZM59_TnN-k,7008
603
+ sphinx-8.2.0rc2.dist-info/RECORD,,