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 +2 -2
- sphinx/application.py +3 -3
- sphinx/domains/math.py +2 -0
- sphinx/domains/python/_annotations.py +26 -10
- sphinx/domains/python/_object.py +4 -1
- sphinx/ext/apidoc/__init__.py +46 -1
- sphinx/ext/apidoc/_cli.py +25 -25
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +14 -14
- sphinx/ext/apidoc/_shared.py +51 -18
- sphinx/ext/autodoc/__init__.py +2 -2
- sphinx/ext/autosummary/__init__.py +11 -0
- sphinx/writers/html5.py +2 -2
- sphinx/writers/latex.py +3 -2
- sphinx/writers/texinfo.py +3 -2
- sphinx/writers/text.py +2 -2
- {sphinx-8.2.0rc1.dist-info → sphinx-8.2.0rc2.dist-info}/METADATA +3 -1
- {sphinx-8.2.0rc1.dist-info → sphinx-8.2.0rc2.dist-info}/RECORD +21 -20
- {sphinx-8.2.0rc1.dist-info → sphinx-8.2.0rc2.dist-info}/LICENSE.rst +0 -0
- {sphinx-8.2.0rc1.dist-info → sphinx-8.2.0rc2.dist-info}/WHEEL +0 -0
- {sphinx-8.2.0rc1.dist-info → sphinx-8.2.0rc2.dist-info}/entry_points.txt +0 -0
sphinx/__init__.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__version__ = '8.2.
|
|
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',
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
sphinx/domains/python/_object.py
CHANGED
|
@@ -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,
|
sphinx/ext/apidoc/__init__.py
CHANGED
|
@@ -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
|
-
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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='
|
|
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.
|
|
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.
|
|
271
|
+
elif opts.toc_file:
|
|
272
272
|
written_files.append(
|
|
273
|
-
create_modules_toc_file(modules, opts, opts.
|
|
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.
|
|
277
|
-
_remove_old_files(written_files, opts.
|
|
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.
|
|
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.
|
|
299
|
-
ensuredir(args.
|
|
298
|
+
if not args.dry_run:
|
|
299
|
+
ensuredir(args.dest_dir)
|
|
300
300
|
|
|
301
301
|
if not args.automodule_options:
|
|
302
|
-
args.automodule_options =
|
|
302
|
+
args.automodule_options = frozenset()
|
|
303
303
|
elif isinstance(args.automodule_options, str):
|
|
304
|
-
args.automodule_options =
|
|
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.
|
|
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.
|
|
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.
|
|
356
|
-
qs.generate(d, silent=True, overwrite=opts.force, templatedir=opts.
|
|
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]
|
sphinx/ext/apidoc/_generate.py
CHANGED
|
@@ -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.
|
|
67
|
-
if opts.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
153
|
-
'separatemodules': opts.
|
|
152
|
+
'modulefirst': opts.module_first,
|
|
153
|
+
'separatemodules': opts.separate_modules,
|
|
154
154
|
'automodule_options': sorted(options),
|
|
155
|
-
'show_headings': not opts.
|
|
156
|
-
'maxdepth': opts.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
252
|
+
if opts.include_private:
|
|
253
253
|
exclude_prefixes: tuple[str, ...] = ('.',)
|
|
254
254
|
else:
|
|
255
255
|
exclude_prefixes = ('.', '_')
|
sphinx/ext/apidoc/_shared.py
CHANGED
|
@@ -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],
|
|
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
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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:
|
|
52
|
+
automodule_options: Set[str] = dataclasses.field(default_factory=set)
|
|
54
53
|
suffix: str = 'rst'
|
|
55
54
|
|
|
56
|
-
remove_old: bool =
|
|
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
|
-
|
|
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
|
+
)
|
sphinx/ext/autodoc/__init__.py
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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.
|
|
910
|
-
attrs['title'] =
|
|
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
|
|
2089
|
-
self.context.append('} (%s)' % self.encode(
|
|
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
|
|
1543
|
-
self.context.append(',%s}' % self.escape_arg(
|
|
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.
|
|
1241
|
-
self.add_text(' (
|
|
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.
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
77
|
-
sphinx/domains/python/_object.py,sha256=
|
|
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=
|
|
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=
|
|
109
|
-
sphinx/ext/apidoc/
|
|
110
|
-
sphinx/ext/apidoc/
|
|
111
|
-
sphinx/ext/
|
|
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=
|
|
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=
|
|
593
|
-
sphinx/writers/latex.py,sha256=
|
|
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=
|
|
596
|
-
sphinx/writers/text.py,sha256=
|
|
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.
|
|
599
|
-
sphinx-8.2.
|
|
600
|
-
sphinx-8.2.
|
|
601
|
-
sphinx-8.2.
|
|
602
|
-
sphinx-8.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|