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.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +48 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +114 -57
- sphinx/domains/python/_object.py +151 -67
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +21 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +66 -0
- sphinx/ext/autodoc/__init__.py +829 -480
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +271 -143
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +61 -50
- sphinx/writers/latex.py +80 -65
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +44 -45
- sphinx/writers/text.py +48 -30
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/ext/autodoc/__init__.py
CHANGED
|
@@ -10,13 +10,14 @@ from __future__ import annotations
|
|
|
10
10
|
import functools
|
|
11
11
|
import operator
|
|
12
12
|
import re
|
|
13
|
+
import sys
|
|
13
14
|
from inspect import Parameter, Signature
|
|
14
15
|
from typing import TYPE_CHECKING, Any, NewType, TypeVar
|
|
15
16
|
|
|
16
17
|
from docutils.statemachine import StringList
|
|
17
18
|
|
|
18
19
|
import sphinx
|
|
19
|
-
from sphinx.config import ENUM
|
|
20
|
+
from sphinx.config import ENUM
|
|
20
21
|
from sphinx.errors import PycodeError
|
|
21
22
|
from sphinx.ext.autodoc.importer import get_class_members, import_module, import_object
|
|
22
23
|
from sphinx.ext.autodoc.mock import ismock, mock, undecorate
|
|
@@ -31,13 +32,7 @@ from sphinx.util.inspect import (
|
|
|
31
32
|
safe_getattr,
|
|
32
33
|
stringify_signature,
|
|
33
34
|
)
|
|
34
|
-
from sphinx.util.typing import
|
|
35
|
-
ExtensionMetadata,
|
|
36
|
-
OptionSpec,
|
|
37
|
-
get_type_hints,
|
|
38
|
-
restify,
|
|
39
|
-
stringify_annotation,
|
|
40
|
-
)
|
|
35
|
+
from sphinx.util.typing import get_type_hints, restify, stringify_annotation
|
|
41
36
|
|
|
42
37
|
if TYPE_CHECKING:
|
|
43
38
|
from collections.abc import Callable, Iterator, Sequence
|
|
@@ -45,8 +40,12 @@ if TYPE_CHECKING:
|
|
|
45
40
|
from typing import ClassVar, Literal, TypeAlias
|
|
46
41
|
|
|
47
42
|
from sphinx.application import Sphinx
|
|
48
|
-
from sphinx.
|
|
43
|
+
from sphinx.config import Config
|
|
44
|
+
from sphinx.environment import BuildEnvironment, _CurrentDocument
|
|
45
|
+
from sphinx.events import EventManager
|
|
49
46
|
from sphinx.ext.autodoc.directive import DocumenterBridge
|
|
47
|
+
from sphinx.registry import SphinxComponentRegistry
|
|
48
|
+
from sphinx.util.typing import ExtensionMetadata, OptionSpec, _RestifyMode
|
|
50
49
|
|
|
51
50
|
_AutodocObjType = Literal[
|
|
52
51
|
'module', 'class', 'exception', 'function', 'method', 'attribute'
|
|
@@ -65,17 +64,27 @@ MethodDescriptorType = type(type.__subclasses__)
|
|
|
65
64
|
|
|
66
65
|
#: extended signature RE: with explicit module name separated by ::
|
|
67
66
|
py_ext_sig_re = re.compile(
|
|
68
|
-
r
|
|
67
|
+
r"""^ ([\w.]+::)? # explicit module name
|
|
69
68
|
([\w.]+\.)? # module and/or class name(s)
|
|
70
69
|
(\w+) \s* # thing name
|
|
71
|
-
(?: \[\s*(
|
|
70
|
+
(?: \[\s*(.*?)\s*])? # optional: type parameters list
|
|
72
71
|
(?: \((.*)\) # optional: arguments
|
|
73
72
|
(?:\s* -> \s* (.*))? # return annotation
|
|
74
73
|
)? $ # and nothing more
|
|
75
|
-
|
|
74
|
+
""",
|
|
75
|
+
re.VERBOSE,
|
|
76
|
+
)
|
|
76
77
|
special_member_re = re.compile(r'^__\S+__$')
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
def _get_render_mode(
|
|
81
|
+
typehints_format: Literal['fully-qualified', 'short'],
|
|
82
|
+
) -> _RestifyMode:
|
|
83
|
+
if typehints_format == 'short':
|
|
84
|
+
return 'smart'
|
|
85
|
+
return 'fully-qualified-except-typing'
|
|
86
|
+
|
|
87
|
+
|
|
79
88
|
def identity(x: Any) -> Any:
|
|
80
89
|
return x
|
|
81
90
|
|
|
@@ -106,7 +115,7 @@ SLOTSATTR = object()
|
|
|
106
115
|
|
|
107
116
|
def members_option(arg: Any) -> object | list[str]:
|
|
108
117
|
"""Used to convert the :members: option to auto directives."""
|
|
109
|
-
if arg in
|
|
118
|
+
if arg in {None, True}:
|
|
110
119
|
return ALL
|
|
111
120
|
elif arg is False:
|
|
112
121
|
return None
|
|
@@ -116,14 +125,14 @@ def members_option(arg: Any) -> object | list[str]:
|
|
|
116
125
|
|
|
117
126
|
def exclude_members_option(arg: Any) -> object | set[str]:
|
|
118
127
|
"""Used to convert the :exclude-members: option."""
|
|
119
|
-
if arg in
|
|
128
|
+
if arg in {None, True}:
|
|
120
129
|
return EMPTY
|
|
121
130
|
return {x.strip() for x in arg.split(',') if x.strip()}
|
|
122
131
|
|
|
123
132
|
|
|
124
133
|
def inherited_members_option(arg: Any) -> set[str]:
|
|
125
134
|
"""Used to convert the :inherited-members: option to auto directives."""
|
|
126
|
-
if arg in
|
|
135
|
+
if arg in {None, True}:
|
|
127
136
|
return {'object'}
|
|
128
137
|
elif arg:
|
|
129
138
|
return {x.strip() for x in arg.split(',')}
|
|
@@ -133,9 +142,9 @@ def inherited_members_option(arg: Any) -> set[str]:
|
|
|
133
142
|
|
|
134
143
|
def member_order_option(arg: Any) -> str | None:
|
|
135
144
|
"""Used to convert the :member-order: option to auto directives."""
|
|
136
|
-
if arg in
|
|
145
|
+
if arg in {None, True}:
|
|
137
146
|
return None
|
|
138
|
-
elif arg in
|
|
147
|
+
elif arg in {'alphabetical', 'bysource', 'groupwise'}:
|
|
139
148
|
return arg
|
|
140
149
|
else:
|
|
141
150
|
raise ValueError(__('invalid value for member-order option: %s') % arg)
|
|
@@ -143,7 +152,7 @@ def member_order_option(arg: Any) -> str | None:
|
|
|
143
152
|
|
|
144
153
|
def class_doc_from_option(arg: Any) -> str | None:
|
|
145
154
|
"""Used to convert the :class-doc-from: option to autoclass directives."""
|
|
146
|
-
if arg in
|
|
155
|
+
if arg in {'both', 'class', 'init'}:
|
|
147
156
|
return arg
|
|
148
157
|
else:
|
|
149
158
|
raise ValueError(__('invalid value for class-doc-from option: %s') % arg)
|
|
@@ -153,7 +162,7 @@ SUPPRESS = object()
|
|
|
153
162
|
|
|
154
163
|
|
|
155
164
|
def annotation_option(arg: Any) -> Any:
|
|
156
|
-
if arg in
|
|
165
|
+
if arg in {None, True}:
|
|
157
166
|
# suppress showing the representation of the object
|
|
158
167
|
return SUPPRESS
|
|
159
168
|
else:
|
|
@@ -167,7 +176,7 @@ def bool_option(arg: Any) -> bool:
|
|
|
167
176
|
return True
|
|
168
177
|
|
|
169
178
|
|
|
170
|
-
def merge_members_option(options: dict) -> None:
|
|
179
|
+
def merge_members_option(options: dict[str, Any]) -> None:
|
|
171
180
|
"""Merge :private-members: and :special-members: options to the
|
|
172
181
|
:members: option.
|
|
173
182
|
"""
|
|
@@ -177,14 +186,16 @@ def merge_members_option(options: dict) -> None:
|
|
|
177
186
|
|
|
178
187
|
members = options.setdefault('members', [])
|
|
179
188
|
for key in ('private-members', 'special-members'):
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
other_members = options.get(key)
|
|
190
|
+
if other_members is not None and other_members is not ALL:
|
|
191
|
+
for member in other_members:
|
|
182
192
|
if member not in members:
|
|
183
193
|
members.append(member)
|
|
184
194
|
|
|
185
195
|
|
|
186
196
|
# Some useful event listener factories for autodoc-process-docstring.
|
|
187
197
|
|
|
198
|
+
|
|
188
199
|
def cut_lines(
|
|
189
200
|
pre: int, post: int = 0, what: Sequence[str] | None = None
|
|
190
201
|
) -> _AutodocProcessDocstringListener:
|
|
@@ -195,6 +206,7 @@ def cut_lines(
|
|
|
195
206
|
Use like this (e.g. in the ``setup()`` function of :file:`conf.py`)::
|
|
196
207
|
|
|
197
208
|
from sphinx.ext.autodoc import cut_lines
|
|
209
|
+
|
|
198
210
|
app.connect('autodoc-process-docstring', cut_lines(4, what={'module'}))
|
|
199
211
|
|
|
200
212
|
This can (and should) be used in place of :confval:`automodule_skip_lines`.
|
|
@@ -225,6 +237,7 @@ def cut_lines(
|
|
|
225
237
|
# make sure there is a blank line at the end
|
|
226
238
|
if lines and lines[-1]:
|
|
227
239
|
lines.append('')
|
|
240
|
+
|
|
228
241
|
return process
|
|
229
242
|
|
|
230
243
|
|
|
@@ -271,11 +284,13 @@ def between(
|
|
|
271
284
|
# make sure there is a blank line at the end
|
|
272
285
|
if lines and lines[-1]:
|
|
273
286
|
lines.append('')
|
|
287
|
+
|
|
274
288
|
return process
|
|
275
289
|
|
|
276
290
|
|
|
277
291
|
# This class is used only in ``sphinx.ext.autodoc.directive``,
|
|
278
|
-
# But we define this class here to keep compatibility
|
|
292
|
+
# But we define this class here to keep compatibility
|
|
293
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/4538
|
|
279
294
|
class Options(dict[str, Any]):
|
|
280
295
|
"""A dict/attribute hybrid that returns None on nonexisting keys."""
|
|
281
296
|
|
|
@@ -296,18 +311,43 @@ class ObjectMember:
|
|
|
296
311
|
represent each member of the object.
|
|
297
312
|
"""
|
|
298
313
|
|
|
299
|
-
|
|
300
|
-
|
|
314
|
+
__slots__ = '__name__', 'object', 'docstring', 'class_', 'skipped'
|
|
315
|
+
|
|
316
|
+
__name__: str
|
|
317
|
+
object: Any
|
|
318
|
+
docstring: str | None
|
|
319
|
+
class_: Any
|
|
320
|
+
skipped: bool
|
|
321
|
+
|
|
322
|
+
def __init__(
|
|
323
|
+
self,
|
|
324
|
+
name: str,
|
|
325
|
+
obj: Any,
|
|
326
|
+
*,
|
|
327
|
+
docstring: str | None = None,
|
|
328
|
+
class_: Any = None,
|
|
329
|
+
skipped: bool = False,
|
|
330
|
+
) -> None:
|
|
301
331
|
self.__name__ = name
|
|
302
332
|
self.object = obj
|
|
303
333
|
self.docstring = docstring
|
|
304
|
-
self.skipped = skipped
|
|
305
334
|
self.class_ = class_
|
|
335
|
+
self.skipped = skipped
|
|
336
|
+
|
|
337
|
+
def __repr__(self) -> str:
|
|
338
|
+
return (
|
|
339
|
+
f'ObjectMember('
|
|
340
|
+
f'name={self.__name__!r}, '
|
|
341
|
+
f'obj={self.object!r}, '
|
|
342
|
+
f'docstring={self.docstring!r}, '
|
|
343
|
+
f'class_={self.class_!r}, '
|
|
344
|
+
f'skipped={self.skipped!r}'
|
|
345
|
+
f')'
|
|
346
|
+
)
|
|
306
347
|
|
|
307
348
|
|
|
308
349
|
class Documenter:
|
|
309
|
-
"""
|
|
310
|
-
A Documenter knows how to autodocument a single object type. When
|
|
350
|
+
"""A Documenter knows how to autodocument a single object type. When
|
|
311
351
|
registered with the AutoDirective, it will be used to document objects
|
|
312
352
|
of that type when needed by autodoc.
|
|
313
353
|
|
|
@@ -335,25 +375,30 @@ class Documenter:
|
|
|
335
375
|
|
|
336
376
|
option_spec: ClassVar[OptionSpec] = {
|
|
337
377
|
'no-index': bool_option,
|
|
378
|
+
'no-index-entry': bool_option,
|
|
338
379
|
'noindex': bool_option,
|
|
339
380
|
}
|
|
340
381
|
|
|
341
382
|
def get_attr(self, obj: Any, name: str, *defargs: Any) -> Any:
|
|
342
383
|
"""getattr() override for types such as Zope interfaces."""
|
|
343
|
-
return autodoc_attrgetter(self.env.
|
|
384
|
+
return autodoc_attrgetter(self.env._registry, obj, name, *defargs)
|
|
344
385
|
|
|
345
386
|
@classmethod
|
|
346
387
|
def can_document_member(
|
|
347
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
388
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
348
389
|
) -> bool:
|
|
349
390
|
"""Called to see if a member can be documented by this Documenter."""
|
|
350
391
|
msg = 'must be implemented in subclasses'
|
|
351
392
|
raise NotImplementedError(msg)
|
|
352
393
|
|
|
353
|
-
def __init__(
|
|
394
|
+
def __init__(
|
|
395
|
+
self, directive: DocumenterBridge, name: str, indent: str = ''
|
|
396
|
+
) -> None:
|
|
354
397
|
self.directive = directive
|
|
355
398
|
self.config: Config = directive.env.config
|
|
356
399
|
self.env: BuildEnvironment = directive.env
|
|
400
|
+
self._current_document: _CurrentDocument = directive.env.current_document
|
|
401
|
+
self._events: EventManager = directive.env.events
|
|
357
402
|
self.options = directive.genopt
|
|
358
403
|
self.name = name
|
|
359
404
|
self.indent = indent
|
|
@@ -378,7 +423,7 @@ class Documenter:
|
|
|
378
423
|
@property
|
|
379
424
|
def documenters(self) -> dict[str, type[Documenter]]:
|
|
380
425
|
"""Returns registered Documenter classes"""
|
|
381
|
-
return self.env.
|
|
426
|
+
return self.env._registry.documenters
|
|
382
427
|
|
|
383
428
|
def add_line(self, line: str, source: str, *lineno: int) -> None:
|
|
384
429
|
"""Append one line of generated reST to the output."""
|
|
@@ -387,8 +432,9 @@ class Documenter:
|
|
|
387
432
|
else:
|
|
388
433
|
self.directive.result.append('', source, *lineno)
|
|
389
434
|
|
|
390
|
-
def resolve_name(
|
|
391
|
-
|
|
435
|
+
def resolve_name(
|
|
436
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
437
|
+
) -> tuple[str | None, list[str]]:
|
|
392
438
|
"""Resolve the module and name of the object to document given by the
|
|
393
439
|
arguments and the current module/class.
|
|
394
440
|
|
|
@@ -410,8 +456,12 @@ class Documenter:
|
|
|
410
456
|
# an autogenerated one
|
|
411
457
|
matched = py_ext_sig_re.match(self.name)
|
|
412
458
|
if matched is None:
|
|
413
|
-
logger.warning(
|
|
414
|
-
|
|
459
|
+
logger.warning(
|
|
460
|
+
__('invalid signature for auto%s (%r)'),
|
|
461
|
+
self.objtype,
|
|
462
|
+
self.name,
|
|
463
|
+
type='autodoc',
|
|
464
|
+
)
|
|
415
465
|
return False
|
|
416
466
|
explicit_modname, path, base, tp_list, args, retann = matched.groups()
|
|
417
467
|
|
|
@@ -432,8 +482,7 @@ class Documenter:
|
|
|
432
482
|
self.modname = modname
|
|
433
483
|
self.args = args
|
|
434
484
|
self.retann = retann
|
|
435
|
-
self.fullname = ((self.modname or '')
|
|
436
|
-
('.' + '.'.join(self.objpath) if self.objpath else ''))
|
|
485
|
+
self.fullname = '.'.join((self.modname or '', *self.objpath))
|
|
437
486
|
return True
|
|
438
487
|
|
|
439
488
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -445,8 +494,7 @@ class Documenter:
|
|
|
445
494
|
with mock(self.config.autodoc_mock_imports):
|
|
446
495
|
try:
|
|
447
496
|
ret = import_object(
|
|
448
|
-
self.modname, self.objpath, self.objtype,
|
|
449
|
-
attrgetter=self.get_attr,
|
|
497
|
+
self.modname, self.objpath, self.objtype, attrgetter=self.get_attr
|
|
450
498
|
)
|
|
451
499
|
self.module, self.parent, self.object_name, self.object = ret
|
|
452
500
|
if ismock(self.object):
|
|
@@ -514,7 +562,7 @@ class Documenter:
|
|
|
514
562
|
"""
|
|
515
563
|
if self.args is not None:
|
|
516
564
|
# signature given explicitly
|
|
517
|
-
args =
|
|
565
|
+
args = f'({self.args})'
|
|
518
566
|
retann = self.retann
|
|
519
567
|
else:
|
|
520
568
|
# try to introspect the signature
|
|
@@ -527,13 +575,23 @@ class Documenter:
|
|
|
527
575
|
args = matched.group(1)
|
|
528
576
|
retann = matched.group(2)
|
|
529
577
|
except Exception as exc:
|
|
530
|
-
logger.warning(
|
|
531
|
-
|
|
578
|
+
logger.warning(
|
|
579
|
+
__('error while formatting arguments for %s: %s'),
|
|
580
|
+
self.fullname,
|
|
581
|
+
exc,
|
|
582
|
+
type='autodoc',
|
|
583
|
+
)
|
|
532
584
|
args = None
|
|
533
585
|
|
|
534
|
-
result = self.
|
|
535
|
-
|
|
536
|
-
|
|
586
|
+
result = self._events.emit_firstresult(
|
|
587
|
+
'autodoc-process-signature',
|
|
588
|
+
self.objtype,
|
|
589
|
+
self.fullname,
|
|
590
|
+
self.object,
|
|
591
|
+
self.options,
|
|
592
|
+
args,
|
|
593
|
+
retann,
|
|
594
|
+
)
|
|
537
595
|
if result:
|
|
538
596
|
args, retann = result
|
|
539
597
|
|
|
@@ -551,14 +609,15 @@ class Documenter:
|
|
|
551
609
|
|
|
552
610
|
# one signature per line, indented by column
|
|
553
611
|
prefix = f'.. {domain}:{directive}:: '
|
|
554
|
-
for i, sig_line in enumerate(sig.split(
|
|
555
|
-
self.add_line(f'{prefix}{name}{sig_line}',
|
|
556
|
-
sourcename)
|
|
612
|
+
for i, sig_line in enumerate(sig.split('\n')):
|
|
613
|
+
self.add_line(f'{prefix}{name}{sig_line}', sourcename)
|
|
557
614
|
if i == 0:
|
|
558
|
-
prefix =
|
|
615
|
+
prefix = ' ' * len(prefix)
|
|
559
616
|
|
|
560
617
|
if self.options.no_index or self.options.noindex:
|
|
561
618
|
self.add_line(' :no-index:', sourcename)
|
|
619
|
+
if self.options.no_index_entry:
|
|
620
|
+
self.add_line(' :no-index-entry:', sourcename)
|
|
562
621
|
if self.objpath:
|
|
563
622
|
# Be explicit about the module, this is necessary since .. class::
|
|
564
623
|
# etc. don't support a prepended module name
|
|
@@ -570,8 +629,13 @@ class Documenter:
|
|
|
570
629
|
When it returns None, autodoc-process-docstring will not be called for this
|
|
571
630
|
object.
|
|
572
631
|
"""
|
|
573
|
-
docstring = getdoc(
|
|
574
|
-
|
|
632
|
+
docstring = getdoc(
|
|
633
|
+
self.object,
|
|
634
|
+
self.get_attr,
|
|
635
|
+
self.config.autodoc_inherit_docstrings,
|
|
636
|
+
self.parent,
|
|
637
|
+
self.object_name,
|
|
638
|
+
)
|
|
575
639
|
if docstring:
|
|
576
640
|
tab_width = self.directive.state.document.settings.tab_width
|
|
577
641
|
return [prepare_docstring(docstring, tab_width)]
|
|
@@ -580,21 +644,27 @@ class Documenter:
|
|
|
580
644
|
def process_doc(self, docstrings: list[list[str]]) -> Iterator[str]:
|
|
581
645
|
"""Let the user process the docstrings before adding them."""
|
|
582
646
|
for docstringlines in docstrings:
|
|
583
|
-
if self.
|
|
647
|
+
if self._events is not None:
|
|
584
648
|
# let extensions preprocess docstrings
|
|
585
|
-
self.
|
|
586
|
-
|
|
587
|
-
|
|
649
|
+
self._events.emit(
|
|
650
|
+
'autodoc-process-docstring',
|
|
651
|
+
self.objtype,
|
|
652
|
+
self.fullname,
|
|
653
|
+
self.object,
|
|
654
|
+
self.options,
|
|
655
|
+
docstringlines,
|
|
656
|
+
)
|
|
588
657
|
|
|
589
|
-
if docstringlines and docstringlines[-1]
|
|
658
|
+
if docstringlines and docstringlines[-1]:
|
|
590
659
|
# append a blank line to the end of the docstring
|
|
591
660
|
docstringlines.append('')
|
|
592
661
|
|
|
593
662
|
yield from docstringlines
|
|
594
663
|
|
|
595
664
|
def get_sourcename(self) -> str:
|
|
596
|
-
|
|
597
|
-
|
|
665
|
+
obj_module = inspect.safe_getattr(self.object, '__module__', None)
|
|
666
|
+
obj_qualname = inspect.safe_getattr(self.object, '__qualname__', None)
|
|
667
|
+
if obj_module and obj_qualname:
|
|
598
668
|
# Get the correct location of docstring from self.object
|
|
599
669
|
# to support inherited methods
|
|
600
670
|
fullname = f'{self.object.__module__}.{self.object.__qualname__}'
|
|
@@ -655,8 +725,9 @@ class Documenter:
|
|
|
655
725
|
msg = 'must be implemented in subclasses'
|
|
656
726
|
raise NotImplementedError(msg)
|
|
657
727
|
|
|
658
|
-
def filter_members(
|
|
659
|
-
|
|
728
|
+
def filter_members(
|
|
729
|
+
self, members: list[ObjectMember], want_all: bool
|
|
730
|
+
) -> list[tuple[str, Any, bool]]:
|
|
660
731
|
"""Filter the given member list.
|
|
661
732
|
|
|
662
733
|
Members are skipped if
|
|
@@ -670,12 +741,22 @@ class Documenter:
|
|
|
670
741
|
The user can override the skipping decision by connecting to the
|
|
671
742
|
``autodoc-skip-member`` event.
|
|
672
743
|
"""
|
|
744
|
+
|
|
673
745
|
def is_filtered_inherited_member(name: str, obj: Any) -> bool:
|
|
674
746
|
inherited_members = self.options.inherited_members or set()
|
|
747
|
+
seen = set()
|
|
675
748
|
|
|
676
749
|
if inspect.isclass(self.object):
|
|
677
750
|
for cls in self.object.__mro__:
|
|
678
|
-
if
|
|
751
|
+
if name in cls.__dict__:
|
|
752
|
+
seen.add(cls)
|
|
753
|
+
if (
|
|
754
|
+
cls.__name__ in inherited_members
|
|
755
|
+
and cls != self.object
|
|
756
|
+
and any(
|
|
757
|
+
issubclass(potential_child, cls) for potential_child in seen
|
|
758
|
+
)
|
|
759
|
+
):
|
|
679
760
|
# given member is a member of specified *super class*
|
|
680
761
|
return True
|
|
681
762
|
if name in cls.__dict__:
|
|
@@ -706,8 +787,13 @@ class Documenter:
|
|
|
706
787
|
isattr = member is INSTANCEATTR or (namespace, membername) in attr_docs
|
|
707
788
|
|
|
708
789
|
try:
|
|
709
|
-
doc = getdoc(
|
|
710
|
-
|
|
790
|
+
doc = getdoc(
|
|
791
|
+
member,
|
|
792
|
+
self.get_attr,
|
|
793
|
+
self.config.autodoc_inherit_docstrings,
|
|
794
|
+
self.object,
|
|
795
|
+
membername,
|
|
796
|
+
)
|
|
711
797
|
if not isinstance(doc, str):
|
|
712
798
|
# Ignore non-string __doc__
|
|
713
799
|
doc = None
|
|
@@ -740,14 +826,18 @@ class Documenter:
|
|
|
740
826
|
if ismock(member) and (namespace, membername) not in attr_docs:
|
|
741
827
|
# mocked module or object
|
|
742
828
|
pass
|
|
743
|
-
elif (
|
|
744
|
-
|
|
829
|
+
elif (
|
|
830
|
+
self.options.exclude_members
|
|
831
|
+
and membername in self.options.exclude_members
|
|
832
|
+
):
|
|
745
833
|
# remove members given by exclude-members
|
|
746
834
|
keep = False
|
|
747
835
|
elif want_all and special_member_re.match(membername):
|
|
748
836
|
# special __methods__
|
|
749
|
-
if (
|
|
750
|
-
|
|
837
|
+
if (
|
|
838
|
+
self.options.special_members
|
|
839
|
+
and membername in self.options.special_members
|
|
840
|
+
):
|
|
751
841
|
if membername == '__doc__': # NoQA: SIM114
|
|
752
842
|
keep = False
|
|
753
843
|
elif is_filtered_inherited_member(membername, obj):
|
|
@@ -776,8 +866,9 @@ class Documenter:
|
|
|
776
866
|
else:
|
|
777
867
|
keep = False
|
|
778
868
|
else:
|
|
779
|
-
if
|
|
780
|
-
|
|
869
|
+
if self.options.members is ALL and is_filtered_inherited_member(
|
|
870
|
+
membername, obj
|
|
871
|
+
):
|
|
781
872
|
keep = False
|
|
782
873
|
else:
|
|
783
874
|
# ignore undocumented members if :undoc-members: is not given
|
|
@@ -789,17 +880,30 @@ class Documenter:
|
|
|
789
880
|
|
|
790
881
|
# give the user a chance to decide whether this member
|
|
791
882
|
# should be skipped
|
|
792
|
-
if self.
|
|
883
|
+
if self._events is not None:
|
|
793
884
|
# let extensions preprocess docstrings
|
|
794
|
-
skip_user = self.
|
|
795
|
-
'autodoc-skip-member',
|
|
796
|
-
|
|
885
|
+
skip_user = self._events.emit_firstresult(
|
|
886
|
+
'autodoc-skip-member',
|
|
887
|
+
self.objtype,
|
|
888
|
+
membername,
|
|
889
|
+
member,
|
|
890
|
+
not keep,
|
|
891
|
+
self.options,
|
|
892
|
+
)
|
|
797
893
|
if skip_user is not None:
|
|
798
894
|
keep = not skip_user
|
|
799
895
|
except Exception as exc:
|
|
800
|
-
logger.warning(
|
|
801
|
-
|
|
802
|
-
|
|
896
|
+
logger.warning(
|
|
897
|
+
__(
|
|
898
|
+
'autodoc: failed to determine %s.%s (%r) to be documented, '
|
|
899
|
+
'the following exception was raised:\n%s'
|
|
900
|
+
),
|
|
901
|
+
self.name,
|
|
902
|
+
membername,
|
|
903
|
+
member,
|
|
904
|
+
exc,
|
|
905
|
+
type='autodoc',
|
|
906
|
+
)
|
|
803
907
|
keep = False
|
|
804
908
|
|
|
805
909
|
if keep:
|
|
@@ -814,21 +918,24 @@ class Documenter:
|
|
|
814
918
|
*self.options.members*.
|
|
815
919
|
"""
|
|
816
920
|
# set current namespace for finding members
|
|
817
|
-
self.
|
|
921
|
+
self._current_document.autodoc_module = self.modname
|
|
818
922
|
if self.objpath:
|
|
819
|
-
self.
|
|
923
|
+
self._current_document.autodoc_class = self.objpath[0]
|
|
820
924
|
|
|
821
|
-
want_all = (
|
|
822
|
-
|
|
823
|
-
|
|
925
|
+
want_all = (
|
|
926
|
+
all_members or self.options.inherited_members or self.options.members is ALL
|
|
927
|
+
)
|
|
824
928
|
# find out which members are documentable
|
|
825
929
|
members_check_module, members = self.get_object_members(want_all)
|
|
826
930
|
|
|
827
931
|
# document non-skipped members
|
|
828
|
-
|
|
829
|
-
for
|
|
830
|
-
classes = [
|
|
831
|
-
|
|
932
|
+
member_documenters: list[tuple[Documenter, bool]] = []
|
|
933
|
+
for mname, member, isattr in self.filter_members(members, want_all):
|
|
934
|
+
classes = [
|
|
935
|
+
cls
|
|
936
|
+
for cls in self.documenters.values()
|
|
937
|
+
if cls.can_document_member(member, mname, isattr, self)
|
|
938
|
+
]
|
|
832
939
|
if not classes:
|
|
833
940
|
# don't know how to document this member
|
|
834
941
|
continue
|
|
@@ -838,22 +945,39 @@ class Documenter:
|
|
|
838
945
|
# of inner classes can be documented
|
|
839
946
|
full_mname = f'{self.modname}::' + '.'.join((*self.objpath, mname))
|
|
840
947
|
documenter = classes[-1](self.directive, full_mname, self.indent)
|
|
841
|
-
|
|
948
|
+
member_documenters.append((documenter, isattr))
|
|
842
949
|
|
|
843
950
|
member_order = self.options.member_order or self.config.autodoc_member_order
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
951
|
+
# We now try to import all objects before ordering them. This is to
|
|
952
|
+
# avoid possible circular imports if we were to import objects after
|
|
953
|
+
# their associated documenters have been sorted.
|
|
954
|
+
member_documenters = [
|
|
955
|
+
(documenter, isattr)
|
|
956
|
+
for documenter, isattr in member_documenters
|
|
957
|
+
if documenter.parse_name() and documenter.import_object()
|
|
958
|
+
]
|
|
959
|
+
member_documenters = self.sort_members(member_documenters, member_order)
|
|
960
|
+
|
|
961
|
+
for documenter, isattr in member_documenters:
|
|
962
|
+
assert documenter.modname
|
|
963
|
+
# We can directly call ._generate() since the documenters
|
|
964
|
+
# already called parse_name() and import_object() before.
|
|
965
|
+
#
|
|
966
|
+
# Note that those two methods above do not emit events, so
|
|
967
|
+
# whatever objects we deduced should not have changed.
|
|
968
|
+
documenter._generate(
|
|
969
|
+
all_members=True,
|
|
970
|
+
real_modname=self.real_modname,
|
|
971
|
+
check_module=members_check_module and not isattr,
|
|
972
|
+
)
|
|
850
973
|
|
|
851
974
|
# reset current objects
|
|
852
|
-
self.
|
|
853
|
-
self.
|
|
975
|
+
self._current_document.autodoc_module = ''
|
|
976
|
+
self._current_document.autodoc_class = ''
|
|
854
977
|
|
|
855
|
-
def sort_members(
|
|
856
|
-
|
|
978
|
+
def sort_members(
|
|
979
|
+
self, documenters: list[tuple[Documenter, bool]], order: str
|
|
980
|
+
) -> list[tuple[Documenter, bool]]:
|
|
857
981
|
"""Sort the given member list."""
|
|
858
982
|
if order == 'groupwise':
|
|
859
983
|
# sort by group; alphabetically within groups
|
|
@@ -868,6 +992,7 @@ class Documenter:
|
|
|
868
992
|
def keyfunc(entry: tuple[Documenter, bool]) -> int:
|
|
869
993
|
fullname = entry[0].name.split('::')[1]
|
|
870
994
|
return tagorder.get(fullname, len(tagorder))
|
|
995
|
+
|
|
871
996
|
documenters.sort(key=keyfunc)
|
|
872
997
|
else: # alphabetical
|
|
873
998
|
documenters.sort(key=lambda e: e[0].name)
|
|
@@ -892,16 +1017,29 @@ class Documenter:
|
|
|
892
1017
|
if not self.parse_name():
|
|
893
1018
|
# need a module to import
|
|
894
1019
|
logger.warning(
|
|
895
|
-
__(
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1020
|
+
__(
|
|
1021
|
+
"don't know which module to import for autodocumenting "
|
|
1022
|
+
'%r (try placing a "module" or "currentmodule" directive '
|
|
1023
|
+
'in the document, or giving an explicit module name)'
|
|
1024
|
+
),
|
|
1025
|
+
self.name,
|
|
1026
|
+
type='autodoc',
|
|
1027
|
+
)
|
|
899
1028
|
return
|
|
900
1029
|
|
|
901
1030
|
# now, import the module and get object to document
|
|
902
1031
|
if not self.import_object():
|
|
903
1032
|
return
|
|
904
1033
|
|
|
1034
|
+
self._generate(more_content, real_modname, check_module, all_members)
|
|
1035
|
+
|
|
1036
|
+
def _generate(
|
|
1037
|
+
self,
|
|
1038
|
+
more_content: StringList | None = None,
|
|
1039
|
+
real_modname: str | None = None,
|
|
1040
|
+
check_module: bool = False,
|
|
1041
|
+
all_members: bool = False,
|
|
1042
|
+
) -> None:
|
|
905
1043
|
# If there is no real module defined, figure out which to use.
|
|
906
1044
|
# The real module is used in the module analyzer to look up the module
|
|
907
1045
|
# where the attribute documentation would actually be found in.
|
|
@@ -934,10 +1072,16 @@ class Documenter:
|
|
|
934
1072
|
except PycodeError:
|
|
935
1073
|
pass
|
|
936
1074
|
|
|
937
|
-
docstrings: list[str] = functools.reduce(
|
|
1075
|
+
docstrings: list[str] = functools.reduce(
|
|
1076
|
+
operator.iadd, self.get_doc() or [], []
|
|
1077
|
+
)
|
|
938
1078
|
if ismock(self.object) and not docstrings:
|
|
939
|
-
logger.warning(
|
|
940
|
-
|
|
1079
|
+
logger.warning(
|
|
1080
|
+
__('A mocked object is detected: %r'),
|
|
1081
|
+
self.name,
|
|
1082
|
+
type='autodoc',
|
|
1083
|
+
subtype='mocked_object',
|
|
1084
|
+
)
|
|
941
1085
|
|
|
942
1086
|
# check __module__ of object (for members not given explicitly)
|
|
943
1087
|
if check_module:
|
|
@@ -955,8 +1099,12 @@ class Documenter:
|
|
|
955
1099
|
try:
|
|
956
1100
|
sig = self.format_signature()
|
|
957
1101
|
except Exception as exc:
|
|
958
|
-
logger.warning(
|
|
959
|
-
|
|
1102
|
+
logger.warning(
|
|
1103
|
+
__('error while formatting signature for %s: %s'),
|
|
1104
|
+
self.fullname,
|
|
1105
|
+
exc,
|
|
1106
|
+
type='autodoc',
|
|
1107
|
+
)
|
|
960
1108
|
return
|
|
961
1109
|
|
|
962
1110
|
# generate the directive header and options, if applicable
|
|
@@ -974,22 +1122,28 @@ class Documenter:
|
|
|
974
1122
|
|
|
975
1123
|
|
|
976
1124
|
class ModuleDocumenter(Documenter):
|
|
977
|
-
"""
|
|
978
|
-
Specialized Documenter subclass for modules.
|
|
979
|
-
"""
|
|
1125
|
+
"""Specialized Documenter subclass for modules."""
|
|
980
1126
|
|
|
981
1127
|
objtype = 'module'
|
|
982
1128
|
content_indent = ''
|
|
983
1129
|
_extra_indent = ' '
|
|
984
1130
|
|
|
985
1131
|
option_spec: ClassVar[OptionSpec] = {
|
|
986
|
-
'members': members_option,
|
|
987
|
-
'
|
|
988
|
-
'
|
|
989
|
-
'
|
|
990
|
-
'
|
|
991
|
-
'
|
|
992
|
-
'
|
|
1132
|
+
'members': members_option,
|
|
1133
|
+
'undoc-members': bool_option,
|
|
1134
|
+
'no-index': bool_option,
|
|
1135
|
+
'no-index-entry': bool_option,
|
|
1136
|
+
'inherited-members': inherited_members_option,
|
|
1137
|
+
'show-inheritance': bool_option,
|
|
1138
|
+
'synopsis': identity,
|
|
1139
|
+
'platform': identity,
|
|
1140
|
+
'deprecated': bool_option,
|
|
1141
|
+
'member-order': member_order_option,
|
|
1142
|
+
'exclude-members': exclude_members_option,
|
|
1143
|
+
'private-members': members_option,
|
|
1144
|
+
'special-members': members_option,
|
|
1145
|
+
'imported-members': bool_option,
|
|
1146
|
+
'ignore-module-all': bool_option,
|
|
993
1147
|
'no-value': bool_option,
|
|
994
1148
|
'noindex': bool_option,
|
|
995
1149
|
}
|
|
@@ -1010,24 +1164,28 @@ class ModuleDocumenter(Documenter):
|
|
|
1010
1164
|
|
|
1011
1165
|
@classmethod
|
|
1012
1166
|
def can_document_member(
|
|
1013
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1167
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1014
1168
|
) -> bool:
|
|
1015
1169
|
# don't document submodules automatically
|
|
1016
1170
|
return False
|
|
1017
1171
|
|
|
1018
|
-
def resolve_name(
|
|
1019
|
-
|
|
1172
|
+
def resolve_name(
|
|
1173
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1174
|
+
) -> tuple[str | None, list[str]]:
|
|
1020
1175
|
if modname is not None:
|
|
1021
|
-
logger.warning(
|
|
1022
|
-
|
|
1176
|
+
logger.warning(
|
|
1177
|
+
__('"::" in automodule name doesn\'t make sense'), type='autodoc'
|
|
1178
|
+
)
|
|
1023
1179
|
return (path or '') + base, []
|
|
1024
1180
|
|
|
1025
1181
|
def parse_name(self) -> bool:
|
|
1026
1182
|
ret = super().parse_name()
|
|
1027
1183
|
if self.args or self.retann:
|
|
1028
|
-
logger.warning(
|
|
1029
|
-
|
|
1030
|
-
|
|
1184
|
+
logger.warning(
|
|
1185
|
+
__('signature arguments or return annotation given for automodule %s'),
|
|
1186
|
+
self.fullname,
|
|
1187
|
+
type='autodoc',
|
|
1188
|
+
)
|
|
1031
1189
|
return ret
|
|
1032
1190
|
|
|
1033
1191
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -1038,9 +1196,15 @@ class ModuleDocumenter(Documenter):
|
|
|
1038
1196
|
self.__all__ = inspect.getall(self.object)
|
|
1039
1197
|
except ValueError as exc:
|
|
1040
1198
|
# invalid __all__ found.
|
|
1041
|
-
logger.warning(
|
|
1042
|
-
|
|
1043
|
-
|
|
1199
|
+
logger.warning(
|
|
1200
|
+
__(
|
|
1201
|
+
'__all__ should be a list of strings, not %r '
|
|
1202
|
+
'(in module %s) -- ignoring __all__'
|
|
1203
|
+
),
|
|
1204
|
+
exc.args[0],
|
|
1205
|
+
self.fullname,
|
|
1206
|
+
type='autodoc',
|
|
1207
|
+
)
|
|
1044
1208
|
|
|
1045
1209
|
return ret
|
|
1046
1210
|
|
|
@@ -1056,6 +1220,8 @@ class ModuleDocumenter(Documenter):
|
|
|
1056
1220
|
self.add_line(' :platform: ' + self.options.platform, sourcename)
|
|
1057
1221
|
if self.options.deprecated:
|
|
1058
1222
|
self.add_line(' :deprecated:', sourcename)
|
|
1223
|
+
if self.options.no_index_entry:
|
|
1224
|
+
self.add_line(' :no-index-entry:', sourcename)
|
|
1059
1225
|
|
|
1060
1226
|
def get_module_members(self) -> dict[str, ObjectMember]:
|
|
1061
1227
|
"""Get members of target module."""
|
|
@@ -1071,7 +1237,9 @@ class ModuleDocumenter(Documenter):
|
|
|
1071
1237
|
if ismock(value):
|
|
1072
1238
|
value = undecorate(value)
|
|
1073
1239
|
docstring = attr_docs.get(('', name), [])
|
|
1074
|
-
members[name] = ObjectMember(
|
|
1240
|
+
members[name] = ObjectMember(
|
|
1241
|
+
name, value, docstring='\n'.join(docstring)
|
|
1242
|
+
)
|
|
1075
1243
|
except AttributeError:
|
|
1076
1244
|
continue
|
|
1077
1245
|
|
|
@@ -1079,8 +1247,9 @@ class ModuleDocumenter(Documenter):
|
|
|
1079
1247
|
for name in inspect.getannotations(self.object):
|
|
1080
1248
|
if name not in members:
|
|
1081
1249
|
docstring = attr_docs.get(('', name), [])
|
|
1082
|
-
members[name] = ObjectMember(
|
|
1083
|
-
|
|
1250
|
+
members[name] = ObjectMember(
|
|
1251
|
+
name, INSTANCEATTR, docstring='\n'.join(docstring)
|
|
1252
|
+
)
|
|
1084
1253
|
|
|
1085
1254
|
return members
|
|
1086
1255
|
|
|
@@ -1104,15 +1273,20 @@ class ModuleDocumenter(Documenter):
|
|
|
1104
1273
|
if name in members:
|
|
1105
1274
|
ret.append(members[name])
|
|
1106
1275
|
else:
|
|
1107
|
-
logger.warning(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1276
|
+
logger.warning(
|
|
1277
|
+
__(
|
|
1278
|
+
'missing attribute mentioned in :members: option: '
|
|
1279
|
+
'module %s, attribute %s'
|
|
1280
|
+
),
|
|
1281
|
+
safe_getattr(self.object, '__name__', '???'),
|
|
1282
|
+
name,
|
|
1283
|
+
type='autodoc',
|
|
1284
|
+
)
|
|
1112
1285
|
return False, ret
|
|
1113
1286
|
|
|
1114
|
-
def sort_members(
|
|
1115
|
-
|
|
1287
|
+
def sort_members(
|
|
1288
|
+
self, documenters: list[tuple[Documenter, bool]], order: str
|
|
1289
|
+
) -> list[tuple[Documenter, bool]]:
|
|
1116
1290
|
if order == 'bysource' and self.__all__:
|
|
1117
1291
|
assert self.__all__ is not None
|
|
1118
1292
|
module_all = self.__all__
|
|
@@ -1129,6 +1303,7 @@ class ModuleDocumenter(Documenter):
|
|
|
1129
1303
|
return module_all.index(name)
|
|
1130
1304
|
else:
|
|
1131
1305
|
return module_all_len
|
|
1306
|
+
|
|
1132
1307
|
documenters.sort(key=keyfunc)
|
|
1133
1308
|
|
|
1134
1309
|
return documenters
|
|
@@ -1137,13 +1312,13 @@ class ModuleDocumenter(Documenter):
|
|
|
1137
1312
|
|
|
1138
1313
|
|
|
1139
1314
|
class ModuleLevelDocumenter(Documenter):
|
|
1140
|
-
"""
|
|
1141
|
-
Specialized Documenter subclass for objects on module level (functions,
|
|
1315
|
+
"""Specialized Documenter subclass for objects on module level (functions,
|
|
1142
1316
|
classes, data/constants).
|
|
1143
1317
|
"""
|
|
1144
1318
|
|
|
1145
|
-
def resolve_name(
|
|
1146
|
-
|
|
1319
|
+
def resolve_name(
|
|
1320
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1321
|
+
) -> tuple[str | None, list[str]]:
|
|
1147
1322
|
if modname is not None:
|
|
1148
1323
|
return modname, [*parents, base]
|
|
1149
1324
|
if path:
|
|
@@ -1152,7 +1327,7 @@ class ModuleLevelDocumenter(Documenter):
|
|
|
1152
1327
|
|
|
1153
1328
|
# if documenting a toplevel object without explicit module,
|
|
1154
1329
|
# it can be contained in another auto directive ...
|
|
1155
|
-
modname = self.
|
|
1330
|
+
modname = self._current_document.autodoc_module
|
|
1156
1331
|
# ... or in the scope of a module directive
|
|
1157
1332
|
if not modname:
|
|
1158
1333
|
modname = self.env.ref_context.get('py:module')
|
|
@@ -1161,13 +1336,13 @@ class ModuleLevelDocumenter(Documenter):
|
|
|
1161
1336
|
|
|
1162
1337
|
|
|
1163
1338
|
class ClassLevelDocumenter(Documenter):
|
|
1164
|
-
"""
|
|
1165
|
-
Specialized Documenter subclass for objects on class level (methods,
|
|
1339
|
+
"""Specialized Documenter subclass for objects on class level (methods,
|
|
1166
1340
|
attributes).
|
|
1167
1341
|
"""
|
|
1168
1342
|
|
|
1169
|
-
def resolve_name(
|
|
1170
|
-
|
|
1343
|
+
def resolve_name(
|
|
1344
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1345
|
+
) -> tuple[str | None, list[str]]:
|
|
1171
1346
|
if modname is not None:
|
|
1172
1347
|
return modname, [*parents, base]
|
|
1173
1348
|
|
|
@@ -1177,19 +1352,18 @@ class ClassLevelDocumenter(Documenter):
|
|
|
1177
1352
|
# if documenting a class-level object without path,
|
|
1178
1353
|
# there must be a current class, either from a parent
|
|
1179
1354
|
# auto directive ...
|
|
1180
|
-
|
|
1355
|
+
mod_cls = self._current_document.autodoc_class
|
|
1181
1356
|
# ... or from a class directive
|
|
1182
|
-
if
|
|
1183
|
-
|
|
1184
|
-
# ... if still
|
|
1185
|
-
if
|
|
1357
|
+
if not mod_cls:
|
|
1358
|
+
mod_cls = self.env.ref_context.get('py:class', '')
|
|
1359
|
+
# ... if still falsy, there's no way to know
|
|
1360
|
+
if not mod_cls:
|
|
1186
1361
|
return None, []
|
|
1187
|
-
mod_cls = mod_cls_
|
|
1188
1362
|
modname, sep, cls = mod_cls.rpartition('.')
|
|
1189
1363
|
parents = [cls]
|
|
1190
1364
|
# if the module name is still missing, get it like above
|
|
1191
1365
|
if not modname:
|
|
1192
|
-
modname = self.
|
|
1366
|
+
modname = self._current_document.autodoc_module
|
|
1193
1367
|
if not modname:
|
|
1194
1368
|
modname = self.env.ref_context.get('py:module')
|
|
1195
1369
|
# ... else, it stays None, which means invalid
|
|
@@ -1197,8 +1371,7 @@ class ClassLevelDocumenter(Documenter):
|
|
|
1197
1371
|
|
|
1198
1372
|
|
|
1199
1373
|
class DocstringSignatureMixin:
|
|
1200
|
-
"""
|
|
1201
|
-
Mixin for FunctionDocumenter and MethodDocumenter to provide the
|
|
1374
|
+
"""Mixin for FunctionDocumenter and MethodDocumenter to provide the
|
|
1202
1375
|
feature of reading the signature from the docstring.
|
|
1203
1376
|
"""
|
|
1204
1377
|
|
|
@@ -1241,15 +1414,16 @@ class DocstringSignatureMixin:
|
|
|
1241
1414
|
# re-prepare docstring to ignore more leading indentation
|
|
1242
1415
|
directive = self.directive # type: ignore[attr-defined]
|
|
1243
1416
|
tab_width = directive.state.document.settings.tab_width
|
|
1244
|
-
self._new_docstrings[i] = prepare_docstring(
|
|
1245
|
-
|
|
1417
|
+
self._new_docstrings[i] = prepare_docstring(
|
|
1418
|
+
'\n'.join(doclines[j + 1 :]), tab_width
|
|
1419
|
+
)
|
|
1246
1420
|
|
|
1247
1421
|
if result is None:
|
|
1248
1422
|
# first signature
|
|
1249
1423
|
result = args, retann
|
|
1250
1424
|
else:
|
|
1251
1425
|
# subsequent signatures
|
|
1252
|
-
self._signatures.append(f
|
|
1426
|
+
self._signatures.append(f'({args}) -> {retann}')
|
|
1253
1427
|
|
|
1254
1428
|
if result is not None:
|
|
1255
1429
|
# finish the loop when signature found
|
|
@@ -1264,8 +1438,7 @@ class DocstringSignatureMixin:
|
|
|
1264
1438
|
|
|
1265
1439
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1266
1440
|
self.args: str | None
|
|
1267
|
-
if
|
|
1268
|
-
and self.config.autodoc_docstring_signature): # type: ignore[attr-defined]
|
|
1441
|
+
if self.args is None and self.config.autodoc_docstring_signature: # type: ignore[attr-defined]
|
|
1269
1442
|
# only act if a signature is not explicitly given already, and if
|
|
1270
1443
|
# the feature is enabled
|
|
1271
1444
|
result = self._find_signature()
|
|
@@ -1273,22 +1446,18 @@ class DocstringSignatureMixin:
|
|
|
1273
1446
|
self.args, self.retann = result
|
|
1274
1447
|
sig = super().format_signature(**kwargs) # type: ignore[misc]
|
|
1275
1448
|
if self._signatures:
|
|
1276
|
-
return
|
|
1449
|
+
return '\n'.join((sig, *self._signatures))
|
|
1277
1450
|
else:
|
|
1278
1451
|
return sig
|
|
1279
1452
|
|
|
1280
1453
|
|
|
1281
1454
|
class DocstringStripSignatureMixin(DocstringSignatureMixin):
|
|
1282
|
-
"""
|
|
1283
|
-
Mixin for AttributeDocumenter to provide the
|
|
1455
|
+
"""Mixin for AttributeDocumenter to provide the
|
|
1284
1456
|
feature of stripping any function signature from the docstring.
|
|
1285
1457
|
"""
|
|
1286
1458
|
|
|
1287
1459
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1288
|
-
if
|
|
1289
|
-
self.args is None
|
|
1290
|
-
and self.config.autodoc_docstring_signature # type: ignore[attr-defined]
|
|
1291
|
-
):
|
|
1460
|
+
if self.args is None and self.config.autodoc_docstring_signature: # type: ignore[attr-defined]
|
|
1292
1461
|
# only act if a signature is not explicitly given already, and if
|
|
1293
1462
|
# the feature is enabled
|
|
1294
1463
|
result = self._find_signature()
|
|
@@ -1301,34 +1470,40 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin):
|
|
|
1301
1470
|
|
|
1302
1471
|
|
|
1303
1472
|
class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc]
|
|
1304
|
-
"""
|
|
1305
|
-
Specialized Documenter subclass for functions.
|
|
1306
|
-
"""
|
|
1473
|
+
"""Specialized Documenter subclass for functions."""
|
|
1307
1474
|
|
|
1308
1475
|
objtype = 'function'
|
|
1309
1476
|
member_order = 30
|
|
1310
1477
|
|
|
1311
1478
|
@classmethod
|
|
1312
1479
|
def can_document_member(
|
|
1313
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1480
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1314
1481
|
) -> bool:
|
|
1315
1482
|
# supports functions, builtins and bound methods exported at the module level
|
|
1316
|
-
return (
|
|
1317
|
-
|
|
1483
|
+
return (
|
|
1484
|
+
inspect.isfunction(member)
|
|
1485
|
+
or inspect.isbuiltin(member)
|
|
1486
|
+
or (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))
|
|
1487
|
+
)
|
|
1318
1488
|
|
|
1319
1489
|
def format_args(self, **kwargs: Any) -> str:
|
|
1320
|
-
if self.config.autodoc_typehints in
|
|
1490
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
1321
1491
|
kwargs.setdefault('show_annotation', False)
|
|
1322
|
-
if self.config.autodoc_typehints_format ==
|
|
1492
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1323
1493
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1494
|
+
if self.config.python_display_short_literal_types:
|
|
1495
|
+
kwargs.setdefault('short_literals', True)
|
|
1324
1496
|
|
|
1325
1497
|
try:
|
|
1326
|
-
self.
|
|
1327
|
-
sig = inspect.signature(
|
|
1498
|
+
self._events.emit('autodoc-before-process-signature', self.object, False)
|
|
1499
|
+
sig = inspect.signature(
|
|
1500
|
+
self.object, type_aliases=self.config.autodoc_type_aliases
|
|
1501
|
+
)
|
|
1328
1502
|
args = stringify_signature(sig, **kwargs)
|
|
1329
1503
|
except TypeError as exc:
|
|
1330
|
-
logger.warning(
|
|
1331
|
-
|
|
1504
|
+
logger.warning(
|
|
1505
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
1506
|
+
)
|
|
1332
1507
|
return ''
|
|
1333
1508
|
except ValueError:
|
|
1334
1509
|
args = ''
|
|
@@ -1345,17 +1520,23 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1345
1520
|
sourcename = self.get_sourcename()
|
|
1346
1521
|
super().add_directive_header(sig)
|
|
1347
1522
|
|
|
1348
|
-
|
|
1523
|
+
is_coro = inspect.iscoroutinefunction(self.object)
|
|
1524
|
+
is_acoro = inspect.isasyncgenfunction(self.object)
|
|
1525
|
+
if is_coro or is_acoro:
|
|
1349
1526
|
self.add_line(' :async:', sourcename)
|
|
1350
1527
|
|
|
1351
1528
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1352
|
-
if self.config.autodoc_typehints_format ==
|
|
1529
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1353
1530
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1531
|
+
if self.config.python_display_short_literal_types:
|
|
1532
|
+
kwargs.setdefault('short_literals', True)
|
|
1354
1533
|
|
|
1355
1534
|
sigs = []
|
|
1356
|
-
if (
|
|
1357
|
-
|
|
1358
|
-
|
|
1535
|
+
if (
|
|
1536
|
+
self.analyzer
|
|
1537
|
+
and '.'.join(self.objpath) in self.analyzer.overloads
|
|
1538
|
+
and self.config.autodoc_typehints != 'none'
|
|
1539
|
+
):
|
|
1359
1540
|
# Use signatures for overloaded functions instead of the implementation function.
|
|
1360
1541
|
overloaded = True
|
|
1361
1542
|
else:
|
|
@@ -1376,18 +1557,20 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1376
1557
|
documenter.objpath = ['']
|
|
1377
1558
|
sigs.append(documenter.format_signature())
|
|
1378
1559
|
if overloaded and self.analyzer is not None:
|
|
1379
|
-
actual = inspect.signature(
|
|
1380
|
-
|
|
1560
|
+
actual = inspect.signature(
|
|
1561
|
+
self.object, type_aliases=self.config.autodoc_type_aliases
|
|
1562
|
+
)
|
|
1381
1563
|
__globals__ = safe_getattr(self.object, '__globals__', {})
|
|
1382
1564
|
for overload in self.analyzer.overloads['.'.join(self.objpath)]:
|
|
1383
1565
|
overload = self.merge_default_value(actual, overload)
|
|
1384
|
-
overload = evaluate_signature(
|
|
1385
|
-
|
|
1566
|
+
overload = evaluate_signature(
|
|
1567
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
1568
|
+
)
|
|
1386
1569
|
|
|
1387
1570
|
sig = stringify_signature(overload, **kwargs)
|
|
1388
1571
|
sigs.append(sig)
|
|
1389
1572
|
|
|
1390
|
-
return
|
|
1573
|
+
return '\n'.join(sigs)
|
|
1391
1574
|
|
|
1392
1575
|
def merge_default_value(self, actual: Signature, overload: Signature) -> Signature:
|
|
1393
1576
|
"""Merge default values of actual implementation to the overload variants."""
|
|
@@ -1399,13 +1582,16 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1399
1582
|
|
|
1400
1583
|
return overload.replace(parameters=parameters)
|
|
1401
1584
|
|
|
1402
|
-
def annotate_to_first_argument(
|
|
1585
|
+
def annotate_to_first_argument(
|
|
1586
|
+
self, func: Callable[..., Any], typ: type
|
|
1587
|
+
) -> Callable[..., Any] | None:
|
|
1403
1588
|
"""Annotate type hint to the first argument of function if needed."""
|
|
1404
1589
|
try:
|
|
1405
1590
|
sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
|
|
1406
1591
|
except TypeError as exc:
|
|
1407
|
-
logger.warning(
|
|
1408
|
-
|
|
1592
|
+
logger.warning(
|
|
1593
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
1594
|
+
)
|
|
1409
1595
|
return None
|
|
1410
1596
|
except ValueError:
|
|
1411
1597
|
return None
|
|
@@ -1420,8 +1606,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1420
1606
|
if params[0].annotation is Parameter.empty:
|
|
1421
1607
|
params[0] = params[0].replace(annotation=typ)
|
|
1422
1608
|
try:
|
|
1423
|
-
dummy.__signature__ = sig.replace( # type: ignore[attr-defined]
|
|
1424
|
-
parameters=params)
|
|
1609
|
+
dummy.__signature__ = sig.replace(parameters=params) # type: ignore[attr-defined]
|
|
1425
1610
|
return dummy
|
|
1426
1611
|
except (AttributeError, TypeError):
|
|
1427
1612
|
# failed to update signature (ex. built-in or extension types)
|
|
@@ -1431,9 +1616,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1431
1616
|
|
|
1432
1617
|
|
|
1433
1618
|
class DecoratorDocumenter(FunctionDocumenter):
|
|
1434
|
-
"""
|
|
1435
|
-
Specialized Documenter subclass for decorator functions.
|
|
1436
|
-
"""
|
|
1619
|
+
"""Specialized Documenter subclass for decorator functions."""
|
|
1437
1620
|
|
|
1438
1621
|
objtype = 'decorator'
|
|
1439
1622
|
|
|
@@ -1451,30 +1634,33 @@ class DecoratorDocumenter(FunctionDocumenter):
|
|
|
1451
1634
|
# Types which have confusing metaclass signatures it would be best not to show.
|
|
1452
1635
|
# These are listed by name, rather than storing the objects themselves, to avoid
|
|
1453
1636
|
# needing to import the modules.
|
|
1454
|
-
_METACLASS_CALL_BLACKLIST =
|
|
1455
|
-
'enum.
|
|
1456
|
-
|
|
1637
|
+
_METACLASS_CALL_BLACKLIST = frozenset({
|
|
1638
|
+
'enum.EnumType.__call__',
|
|
1639
|
+
})
|
|
1457
1640
|
|
|
1458
1641
|
|
|
1459
1642
|
# Types whose __new__ signature is a pass-through.
|
|
1460
|
-
_CLASS_NEW_BLACKLIST =
|
|
1643
|
+
_CLASS_NEW_BLACKLIST = frozenset({
|
|
1461
1644
|
'typing.Generic.__new__',
|
|
1462
|
-
|
|
1645
|
+
})
|
|
1463
1646
|
|
|
1464
1647
|
|
|
1465
1648
|
class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc]
|
|
1466
|
-
"""
|
|
1467
|
-
Specialized Documenter subclass for classes.
|
|
1468
|
-
"""
|
|
1649
|
+
"""Specialized Documenter subclass for classes."""
|
|
1469
1650
|
|
|
1470
1651
|
objtype = 'class'
|
|
1471
1652
|
member_order = 20
|
|
1472
1653
|
option_spec: ClassVar[OptionSpec] = {
|
|
1473
|
-
'members': members_option,
|
|
1474
|
-
'
|
|
1475
|
-
'
|
|
1654
|
+
'members': members_option,
|
|
1655
|
+
'undoc-members': bool_option,
|
|
1656
|
+
'no-index': bool_option,
|
|
1657
|
+
'no-index-entry': bool_option,
|
|
1658
|
+
'inherited-members': inherited_members_option,
|
|
1659
|
+
'show-inheritance': bool_option,
|
|
1660
|
+
'member-order': member_order_option,
|
|
1476
1661
|
'exclude-members': exclude_members_option,
|
|
1477
|
-
'private-members': members_option,
|
|
1662
|
+
'private-members': members_option,
|
|
1663
|
+
'special-members': members_option,
|
|
1478
1664
|
'class-doc-from': class_doc_from_option,
|
|
1479
1665
|
'noindex': bool_option,
|
|
1480
1666
|
}
|
|
@@ -1504,10 +1690,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1504
1690
|
|
|
1505
1691
|
@classmethod
|
|
1506
1692
|
def can_document_member(
|
|
1507
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1693
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1508
1694
|
) -> bool:
|
|
1509
1695
|
return isinstance(member, type) or (
|
|
1510
|
-
isattr and isinstance(member, NewType | TypeVar)
|
|
1696
|
+
isattr and isinstance(member, NewType | TypeVar)
|
|
1697
|
+
)
|
|
1511
1698
|
|
|
1512
1699
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
1513
1700
|
ret = super().import_object(raiseerror)
|
|
@@ -1515,13 +1702,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1515
1702
|
# as data/attribute
|
|
1516
1703
|
if ret:
|
|
1517
1704
|
if hasattr(self.object, '__name__'):
|
|
1518
|
-
self.doc_as_attr =
|
|
1705
|
+
self.doc_as_attr = self.objpath[-1] != self.object.__name__
|
|
1519
1706
|
else:
|
|
1520
1707
|
self.doc_as_attr = True
|
|
1521
1708
|
if isinstance(self.object, NewType | TypeVar):
|
|
1522
1709
|
modname = getattr(self.object, '__module__', self.modname)
|
|
1523
1710
|
if modname != self.modname and self.modname.startswith(modname):
|
|
1524
|
-
bases = self.modname[len(modname):].strip('.').split('.')
|
|
1711
|
+
bases = self.modname[len(modname) :].strip('.').split('.')
|
|
1525
1712
|
self.objpath = bases + self.objpath
|
|
1526
1713
|
self.modname = modname
|
|
1527
1714
|
return ret
|
|
@@ -1543,24 +1730,32 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1543
1730
|
# This sequence is copied from inspect._signature_from_callable.
|
|
1544
1731
|
# ValueError means that no signature could be found, so we keep going.
|
|
1545
1732
|
|
|
1546
|
-
# First, we check
|
|
1547
|
-
if
|
|
1548
|
-
|
|
1549
|
-
|
|
1733
|
+
# First, we check if obj has a __signature__ attribute
|
|
1734
|
+
if hasattr(self.object, '__signature__'):
|
|
1735
|
+
object_sig = self.object.__signature__
|
|
1736
|
+
if isinstance(object_sig, Signature):
|
|
1737
|
+
return None, None, object_sig
|
|
1738
|
+
if sys.version_info[:2] in {(3, 12), (3, 13)} and callable(object_sig):
|
|
1739
|
+
# Support for enum.Enum.__signature__ in Python 3.12
|
|
1740
|
+
if isinstance(object_sig_str := object_sig(), str):
|
|
1741
|
+
return None, None, inspect.signature_from_str(object_sig_str)
|
|
1550
1742
|
|
|
1551
1743
|
# Next, let's see if it has an overloaded __call__ defined
|
|
1552
1744
|
# in its metaclass
|
|
1553
1745
|
call = get_user_defined_function_or_method(type(self.object), '__call__')
|
|
1554
1746
|
|
|
1555
1747
|
if call is not None:
|
|
1556
|
-
if f
|
|
1748
|
+
if f'{call.__module__}.{call.__qualname__}' in _METACLASS_CALL_BLACKLIST:
|
|
1557
1749
|
call = None
|
|
1558
1750
|
|
|
1559
1751
|
if call is not None:
|
|
1560
|
-
self.
|
|
1752
|
+
self._events.emit('autodoc-before-process-signature', call, True)
|
|
1561
1753
|
try:
|
|
1562
|
-
sig = inspect.signature(
|
|
1563
|
-
|
|
1754
|
+
sig = inspect.signature(
|
|
1755
|
+
call,
|
|
1756
|
+
bound_method=True,
|
|
1757
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1758
|
+
)
|
|
1564
1759
|
return type(self.object), '__call__', sig
|
|
1565
1760
|
except ValueError:
|
|
1566
1761
|
pass
|
|
@@ -1569,14 +1764,17 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1569
1764
|
new = get_user_defined_function_or_method(self.object, '__new__')
|
|
1570
1765
|
|
|
1571
1766
|
if new is not None:
|
|
1572
|
-
if f
|
|
1767
|
+
if f'{new.__module__}.{new.__qualname__}' in _CLASS_NEW_BLACKLIST:
|
|
1573
1768
|
new = None
|
|
1574
1769
|
|
|
1575
1770
|
if new is not None:
|
|
1576
|
-
self.
|
|
1771
|
+
self._events.emit('autodoc-before-process-signature', new, True)
|
|
1577
1772
|
try:
|
|
1578
|
-
sig = inspect.signature(
|
|
1579
|
-
|
|
1773
|
+
sig = inspect.signature(
|
|
1774
|
+
new,
|
|
1775
|
+
bound_method=True,
|
|
1776
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1777
|
+
)
|
|
1580
1778
|
return self.object, '__new__', sig
|
|
1581
1779
|
except ValueError:
|
|
1582
1780
|
pass
|
|
@@ -1584,10 +1782,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1584
1782
|
# Finally, we should have at least __init__ implemented
|
|
1585
1783
|
init = get_user_defined_function_or_method(self.object, '__init__')
|
|
1586
1784
|
if init is not None:
|
|
1587
|
-
self.
|
|
1785
|
+
self._events.emit('autodoc-before-process-signature', init, True)
|
|
1588
1786
|
try:
|
|
1589
|
-
sig = inspect.signature(
|
|
1590
|
-
|
|
1787
|
+
sig = inspect.signature(
|
|
1788
|
+
init,
|
|
1789
|
+
bound_method=True,
|
|
1790
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1791
|
+
)
|
|
1591
1792
|
return self.object, '__init__', sig
|
|
1592
1793
|
except ValueError:
|
|
1593
1794
|
pass
|
|
@@ -1596,10 +1797,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1596
1797
|
# handle it.
|
|
1597
1798
|
# We don't know the exact method that inspect.signature will read
|
|
1598
1799
|
# the signature from, so just pass the object itself to our hook.
|
|
1599
|
-
self.
|
|
1800
|
+
self._events.emit('autodoc-before-process-signature', self.object, False)
|
|
1600
1801
|
try:
|
|
1601
|
-
sig = inspect.signature(
|
|
1602
|
-
|
|
1802
|
+
sig = inspect.signature(
|
|
1803
|
+
self.object,
|
|
1804
|
+
bound_method=False,
|
|
1805
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1806
|
+
)
|
|
1603
1807
|
return None, None, sig
|
|
1604
1808
|
except ValueError:
|
|
1605
1809
|
pass
|
|
@@ -1609,17 +1813,22 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1609
1813
|
return None, None, None
|
|
1610
1814
|
|
|
1611
1815
|
def format_args(self, **kwargs: Any) -> str:
|
|
1612
|
-
if self.config.autodoc_typehints in
|
|
1816
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
1613
1817
|
kwargs.setdefault('show_annotation', False)
|
|
1614
|
-
if self.config.autodoc_typehints_format ==
|
|
1818
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1615
1819
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1820
|
+
if self.config.python_display_short_literal_types:
|
|
1821
|
+
kwargs.setdefault('short_literals', True)
|
|
1616
1822
|
|
|
1617
1823
|
try:
|
|
1618
1824
|
self._signature_class, _signature_method_name, sig = self._get_signature()
|
|
1619
1825
|
except TypeError as exc:
|
|
1620
1826
|
# __signature__ attribute contained junk
|
|
1621
|
-
logger.warning(
|
|
1622
|
-
|
|
1827
|
+
logger.warning(
|
|
1828
|
+
__('Failed to get a constructor signature for %s: %s'),
|
|
1829
|
+
self.fullname,
|
|
1830
|
+
exc,
|
|
1831
|
+
)
|
|
1623
1832
|
return ''
|
|
1624
1833
|
self._signature_method_name = _signature_method_name or ''
|
|
1625
1834
|
|
|
@@ -1649,8 +1858,10 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1649
1858
|
# do not show signatures
|
|
1650
1859
|
return ''
|
|
1651
1860
|
|
|
1652
|
-
if self.config.autodoc_typehints_format ==
|
|
1861
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1653
1862
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1863
|
+
if self.config.python_display_short_literal_types:
|
|
1864
|
+
kwargs.setdefault('short_literals', True)
|
|
1654
1865
|
|
|
1655
1866
|
sig = super().format_signature()
|
|
1656
1867
|
sigs = []
|
|
@@ -1658,21 +1869,25 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1658
1869
|
overloads = self.get_overloaded_signatures()
|
|
1659
1870
|
if overloads and self.config.autodoc_typehints != 'none':
|
|
1660
1871
|
# Use signatures for overloaded methods instead of the implementation method.
|
|
1661
|
-
method = safe_getattr(
|
|
1872
|
+
method = safe_getattr(
|
|
1873
|
+
self._signature_class, self._signature_method_name, None
|
|
1874
|
+
)
|
|
1662
1875
|
__globals__ = safe_getattr(method, '__globals__', {})
|
|
1663
1876
|
for overload in overloads:
|
|
1664
|
-
overload = evaluate_signature(
|
|
1665
|
-
|
|
1877
|
+
overload = evaluate_signature(
|
|
1878
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
1879
|
+
)
|
|
1666
1880
|
|
|
1667
1881
|
parameters = list(overload.parameters.values())
|
|
1668
|
-
overload = overload.replace(
|
|
1669
|
-
|
|
1882
|
+
overload = overload.replace(
|
|
1883
|
+
parameters=parameters[1:], return_annotation=Parameter.empty
|
|
1884
|
+
)
|
|
1670
1885
|
sig = stringify_signature(overload, **kwargs)
|
|
1671
1886
|
sigs.append(sig)
|
|
1672
1887
|
else:
|
|
1673
1888
|
sigs.append(sig)
|
|
1674
1889
|
|
|
1675
|
-
return
|
|
1890
|
+
return '\n'.join(sigs)
|
|
1676
1891
|
|
|
1677
1892
|
def get_overloaded_signatures(self) -> list[Signature]:
|
|
1678
1893
|
if self._signature_class and self._signature_method_name:
|
|
@@ -1719,8 +1934,12 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1719
1934
|
self.add_line(' :final:', sourcename)
|
|
1720
1935
|
|
|
1721
1936
|
canonical_fullname = self.get_canonical_fullname()
|
|
1722
|
-
if (
|
|
1723
|
-
|
|
1937
|
+
if (
|
|
1938
|
+
not self.doc_as_attr
|
|
1939
|
+
and not isinstance(self.object, NewType)
|
|
1940
|
+
and canonical_fullname
|
|
1941
|
+
and self.fullname != canonical_fullname
|
|
1942
|
+
):
|
|
1724
1943
|
self.add_line(' :canonical: %s' % canonical_fullname, sourcename)
|
|
1725
1944
|
|
|
1726
1945
|
# add inheritance info, if wanted
|
|
@@ -1735,21 +1954,24 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1735
1954
|
else:
|
|
1736
1955
|
bases = []
|
|
1737
1956
|
|
|
1738
|
-
self.
|
|
1739
|
-
|
|
1957
|
+
self._events.emit(
|
|
1958
|
+
'autodoc-process-bases', self.fullname, self.object, self.options, bases
|
|
1959
|
+
)
|
|
1740
1960
|
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
else:
|
|
1744
|
-
base_classes = [restify(cls) for cls in bases]
|
|
1961
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
1962
|
+
base_classes = [restify(cls, mode=mode) for cls in bases]
|
|
1745
1963
|
|
|
1746
1964
|
sourcename = self.get_sourcename()
|
|
1747
1965
|
self.add_line('', sourcename)
|
|
1748
1966
|
self.add_line(' ' + _('Bases: %s') % ', '.join(base_classes), sourcename)
|
|
1749
1967
|
|
|
1750
1968
|
def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]:
|
|
1751
|
-
members = get_class_members(
|
|
1752
|
-
|
|
1969
|
+
members = get_class_members(
|
|
1970
|
+
self.object,
|
|
1971
|
+
self.objpath,
|
|
1972
|
+
self.get_attr,
|
|
1973
|
+
self.config.autodoc_inherit_docstrings,
|
|
1974
|
+
)
|
|
1753
1975
|
if not want_all:
|
|
1754
1976
|
if not self.options.members:
|
|
1755
1977
|
return False, []
|
|
@@ -1759,8 +1981,12 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1759
1981
|
if name in members:
|
|
1760
1982
|
selected.append(members[name])
|
|
1761
1983
|
else:
|
|
1762
|
-
logger.warning(
|
|
1763
|
-
|
|
1984
|
+
logger.warning(
|
|
1985
|
+
__('missing attribute %s in object %s'),
|
|
1986
|
+
name,
|
|
1987
|
+
self.fullname,
|
|
1988
|
+
type='autodoc',
|
|
1989
|
+
)
|
|
1764
1990
|
return False, selected
|
|
1765
1991
|
elif self.options.inherited_members:
|
|
1766
1992
|
return False, list(members.values())
|
|
@@ -1782,7 +2008,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1782
2008
|
if lines is not None:
|
|
1783
2009
|
return lines
|
|
1784
2010
|
|
|
1785
|
-
classdoc_from = self.options.get(
|
|
2011
|
+
classdoc_from = self.options.get(
|
|
2012
|
+
'class-doc-from', self.config.autoclass_content
|
|
2013
|
+
)
|
|
1786
2014
|
|
|
1787
2015
|
docstrings = []
|
|
1788
2016
|
attrdocstring = getdoc(self.object, self.get_attr)
|
|
@@ -1791,26 +2019,36 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1791
2019
|
|
|
1792
2020
|
# for classes, what the "docstring" is can be controlled via a
|
|
1793
2021
|
# config value; the default is only the class docstring
|
|
1794
|
-
if classdoc_from in
|
|
2022
|
+
if classdoc_from in {'both', 'init'}:
|
|
1795
2023
|
__init__ = self.get_attr(self.object, '__init__', None)
|
|
1796
|
-
initdocstring = getdoc(
|
|
1797
|
-
|
|
1798
|
-
|
|
2024
|
+
initdocstring = getdoc(
|
|
2025
|
+
__init__,
|
|
2026
|
+
self.get_attr,
|
|
2027
|
+
self.config.autodoc_inherit_docstrings,
|
|
2028
|
+
self.object,
|
|
2029
|
+
'__init__',
|
|
2030
|
+
)
|
|
1799
2031
|
# for new-style classes, no __init__ means default __init__
|
|
1800
|
-
if
|
|
1801
|
-
|
|
1802
|
-
|
|
2032
|
+
if initdocstring is not None and (
|
|
2033
|
+
initdocstring == object.__init__.__doc__ # for pypy
|
|
2034
|
+
or initdocstring.strip() == object.__init__.__doc__ # for !pypy
|
|
2035
|
+
):
|
|
1803
2036
|
initdocstring = None
|
|
1804
2037
|
if not initdocstring:
|
|
1805
2038
|
# try __new__
|
|
1806
2039
|
__new__ = self.get_attr(self.object, '__new__', None)
|
|
1807
|
-
initdocstring = getdoc(
|
|
1808
|
-
|
|
1809
|
-
|
|
2040
|
+
initdocstring = getdoc(
|
|
2041
|
+
__new__,
|
|
2042
|
+
self.get_attr,
|
|
2043
|
+
self.config.autodoc_inherit_docstrings,
|
|
2044
|
+
self.object,
|
|
2045
|
+
'__new__',
|
|
2046
|
+
)
|
|
1810
2047
|
# for new-style classes, no __new__ means default __new__
|
|
1811
|
-
if
|
|
1812
|
-
|
|
1813
|
-
|
|
2048
|
+
if initdocstring is not None and (
|
|
2049
|
+
initdocstring == object.__new__.__doc__ # for pypy
|
|
2050
|
+
or initdocstring.strip() == object.__new__.__doc__ # for !pypy
|
|
2051
|
+
):
|
|
1814
2052
|
initdocstring = None
|
|
1815
2053
|
if initdocstring:
|
|
1816
2054
|
if classdoc_from == 'init':
|
|
@@ -1834,34 +2072,29 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1834
2072
|
return None
|
|
1835
2073
|
|
|
1836
2074
|
def add_content(self, more_content: StringList | None) -> None:
|
|
2075
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
2076
|
+
short_literals = self.config.python_display_short_literal_types
|
|
2077
|
+
|
|
1837
2078
|
if isinstance(self.object, NewType):
|
|
1838
|
-
|
|
1839
|
-
supertype = restify(self.object.__supertype__, "smart")
|
|
1840
|
-
else:
|
|
1841
|
-
supertype = restify(self.object.__supertype__)
|
|
2079
|
+
supertype = restify(self.object.__supertype__, mode=mode)
|
|
1842
2080
|
|
|
1843
2081
|
more_content = StringList([_('alias of %s') % supertype, ''], source='')
|
|
1844
2082
|
if isinstance(self.object, TypeVar):
|
|
1845
2083
|
attrs = [repr(self.object.__name__)]
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
attrs.append(stringify_annotation(constraint))
|
|
2084
|
+
attrs.extend(
|
|
2085
|
+
stringify_annotation(constraint, mode, short_literals=short_literals)
|
|
2086
|
+
for constraint in self.object.__constraints__
|
|
2087
|
+
)
|
|
1851
2088
|
if self.object.__bound__:
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
else:
|
|
1855
|
-
bound = restify(self.object.__bound__)
|
|
1856
|
-
attrs.append(r"bound=\ " + bound)
|
|
2089
|
+
bound = restify(self.object.__bound__, mode=mode)
|
|
2090
|
+
attrs.append(r'bound=\ ' + bound)
|
|
1857
2091
|
if self.object.__covariant__:
|
|
1858
|
-
attrs.append(
|
|
2092
|
+
attrs.append('covariant=True')
|
|
1859
2093
|
if self.object.__contravariant__:
|
|
1860
|
-
attrs.append(
|
|
2094
|
+
attrs.append('contravariant=True')
|
|
1861
2095
|
|
|
1862
2096
|
more_content = StringList(
|
|
1863
|
-
[_('alias of TypeVar(%s)') %
|
|
1864
|
-
source='',
|
|
2097
|
+
[_('alias of TypeVar(%s)') % ', '.join(attrs), ''], source=''
|
|
1865
2098
|
)
|
|
1866
2099
|
if self.doc_as_attr and self.modname != self.get_real_modname():
|
|
1867
2100
|
try:
|
|
@@ -1873,10 +2106,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1873
2106
|
|
|
1874
2107
|
if self.doc_as_attr and not self.get_variable_comment():
|
|
1875
2108
|
try:
|
|
1876
|
-
|
|
1877
|
-
alias = restify(self.object, "smart")
|
|
1878
|
-
else:
|
|
1879
|
-
alias = restify(self.object)
|
|
2109
|
+
alias = restify(self.object, mode=mode)
|
|
1880
2110
|
more_content = StringList([_('alias of %s') % alias], source='')
|
|
1881
2111
|
except AttributeError:
|
|
1882
2112
|
pass # Invalid class object is passed.
|
|
@@ -1900,15 +2130,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1900
2130
|
# If a class gets imported into the module real_modname
|
|
1901
2131
|
# the analyzer won't find the source of the class, if
|
|
1902
2132
|
# it looks in real_modname.
|
|
1903
|
-
return super().generate(
|
|
1904
|
-
|
|
1905
|
-
|
|
2133
|
+
return super().generate(
|
|
2134
|
+
more_content=more_content,
|
|
2135
|
+
check_module=check_module,
|
|
2136
|
+
all_members=all_members,
|
|
2137
|
+
)
|
|
1906
2138
|
|
|
1907
2139
|
|
|
1908
2140
|
class ExceptionDocumenter(ClassDocumenter):
|
|
1909
|
-
"""
|
|
1910
|
-
Specialized ClassDocumenter subclass for exceptions.
|
|
1911
|
-
"""
|
|
2141
|
+
"""Specialized ClassDocumenter subclass for exceptions."""
|
|
1912
2142
|
|
|
1913
2143
|
objtype = 'exception'
|
|
1914
2144
|
member_order = 10
|
|
@@ -1918,7 +2148,7 @@ class ExceptionDocumenter(ClassDocumenter):
|
|
|
1918
2148
|
|
|
1919
2149
|
@classmethod
|
|
1920
2150
|
def can_document_member(
|
|
1921
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2151
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1922
2152
|
) -> bool:
|
|
1923
2153
|
try:
|
|
1924
2154
|
return isinstance(member, type) and issubclass(member, BaseException)
|
|
@@ -1956,21 +2186,20 @@ class DataDocumenterMixinBase:
|
|
|
1956
2186
|
|
|
1957
2187
|
|
|
1958
2188
|
class GenericAliasMixin(DataDocumenterMixinBase):
|
|
1959
|
-
"""
|
|
1960
|
-
Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
|
|
2189
|
+
"""Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
|
|
1961
2190
|
supporting GenericAliases.
|
|
1962
2191
|
"""
|
|
1963
2192
|
|
|
1964
2193
|
def should_suppress_directive_header(self) -> bool:
|
|
1965
|
-
return (
|
|
1966
|
-
|
|
2194
|
+
return (
|
|
2195
|
+
inspect.isgenericalias(self.object)
|
|
2196
|
+
or super().should_suppress_directive_header()
|
|
2197
|
+
)
|
|
1967
2198
|
|
|
1968
2199
|
def update_content(self, more_content: StringList) -> None:
|
|
1969
2200
|
if inspect.isgenericalias(self.object):
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
else:
|
|
1973
|
-
alias = restify(self.object)
|
|
2201
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
2202
|
+
alias = restify(self.object, mode=mode)
|
|
1974
2203
|
|
|
1975
2204
|
more_content.append(_('alias of %s') % alias, '')
|
|
1976
2205
|
more_content.append('', '')
|
|
@@ -1979,8 +2208,7 @@ class GenericAliasMixin(DataDocumenterMixinBase):
|
|
|
1979
2208
|
|
|
1980
2209
|
|
|
1981
2210
|
class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
1982
|
-
"""
|
|
1983
|
-
Mixin for DataDocumenter to provide the feature for supporting uninitialized
|
|
2211
|
+
"""Mixin for DataDocumenter to provide the feature for supporting uninitialized
|
|
1984
2212
|
(type annotation only) global variables.
|
|
1985
2213
|
"""
|
|
1986
2214
|
|
|
@@ -1992,9 +2220,12 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
1992
2220
|
try:
|
|
1993
2221
|
with mock(self.config.autodoc_mock_imports):
|
|
1994
2222
|
parent = import_module(self.modname)
|
|
1995
|
-
annotations = get_type_hints(
|
|
1996
|
-
|
|
1997
|
-
|
|
2223
|
+
annotations = get_type_hints(
|
|
2224
|
+
parent,
|
|
2225
|
+
None,
|
|
2226
|
+
self.config.autodoc_type_aliases,
|
|
2227
|
+
include_extras=True,
|
|
2228
|
+
)
|
|
1998
2229
|
if self.objpath[-1] in annotations:
|
|
1999
2230
|
self.object = UNINITIALIZED_ATTR
|
|
2000
2231
|
self.parent = parent
|
|
@@ -2009,8 +2240,9 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
2009
2240
|
return False
|
|
2010
2241
|
|
|
2011
2242
|
def should_suppress_value_header(self) -> bool:
|
|
2012
|
-
return (
|
|
2013
|
-
|
|
2243
|
+
return (
|
|
2244
|
+
self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header()
|
|
2245
|
+
)
|
|
2014
2246
|
|
|
2015
2247
|
def get_doc(self) -> list[list[str]] | None:
|
|
2016
2248
|
if self.object is UNINITIALIZED_ATTR:
|
|
@@ -2019,22 +2251,21 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
2019
2251
|
return super().get_doc() # type: ignore[misc]
|
|
2020
2252
|
|
|
2021
2253
|
|
|
2022
|
-
class DataDocumenter(
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
Specialized Documenter subclass for data items.
|
|
2026
|
-
"""
|
|
2254
|
+
class DataDocumenter(
|
|
2255
|
+
GenericAliasMixin, UninitializedGlobalVariableMixin, ModuleLevelDocumenter
|
|
2256
|
+
):
|
|
2257
|
+
"""Specialized Documenter subclass for data items."""
|
|
2027
2258
|
|
|
2028
2259
|
objtype = 'data'
|
|
2029
2260
|
member_order = 40
|
|
2030
2261
|
priority = -10
|
|
2031
2262
|
option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec)
|
|
2032
|
-
option_spec[
|
|
2033
|
-
option_spec[
|
|
2263
|
+
option_spec['annotation'] = annotation_option
|
|
2264
|
+
option_spec['no-value'] = bool_option
|
|
2034
2265
|
|
|
2035
2266
|
@classmethod
|
|
2036
2267
|
def can_document_member(
|
|
2037
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2268
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2038
2269
|
) -> bool:
|
|
2039
2270
|
return isinstance(parent, ModuleDocumenter) and isattr
|
|
2040
2271
|
|
|
@@ -2047,7 +2278,7 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2047
2278
|
analyzer = ModuleAnalyzer.for_module(self.modname)
|
|
2048
2279
|
analyzer.analyze()
|
|
2049
2280
|
for (classname, attrname), annotation in analyzer.annotations.items():
|
|
2050
|
-
if classname
|
|
2281
|
+
if not classname and attrname not in annotations:
|
|
2051
2282
|
annotations[attrname] = annotation
|
|
2052
2283
|
except PycodeError:
|
|
2053
2284
|
pass
|
|
@@ -2065,7 +2296,8 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2065
2296
|
else:
|
|
2066
2297
|
doc = self.get_doc() or []
|
|
2067
2298
|
docstring, metadata = separate_metadata(
|
|
2068
|
-
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2299
|
+
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2300
|
+
)
|
|
2069
2301
|
if 'hide-value' in metadata:
|
|
2070
2302
|
return True
|
|
2071
2303
|
|
|
@@ -2074,29 +2306,38 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2074
2306
|
def add_directive_header(self, sig: str) -> None:
|
|
2075
2307
|
super().add_directive_header(sig)
|
|
2076
2308
|
sourcename = self.get_sourcename()
|
|
2077
|
-
if
|
|
2309
|
+
if (
|
|
2310
|
+
self.options.annotation is SUPPRESS
|
|
2311
|
+
or self.should_suppress_directive_header()
|
|
2312
|
+
):
|
|
2078
2313
|
pass
|
|
2079
2314
|
elif self.options.annotation:
|
|
2080
|
-
self.add_line(' :annotation: %s' % self.options.annotation,
|
|
2081
|
-
sourcename)
|
|
2315
|
+
self.add_line(' :annotation: %s' % self.options.annotation, sourcename)
|
|
2082
2316
|
else:
|
|
2083
2317
|
if self.config.autodoc_typehints != 'none':
|
|
2084
2318
|
# obtain annotation for this data
|
|
2085
|
-
annotations = get_type_hints(
|
|
2086
|
-
|
|
2087
|
-
|
|
2319
|
+
annotations = get_type_hints(
|
|
2320
|
+
self.parent,
|
|
2321
|
+
None,
|
|
2322
|
+
self.config.autodoc_type_aliases,
|
|
2323
|
+
include_extras=True,
|
|
2324
|
+
)
|
|
2088
2325
|
if self.objpath[-1] in annotations:
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2326
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
2327
|
+
short_literals = self.config.python_display_short_literal_types
|
|
2328
|
+
objrepr = stringify_annotation(
|
|
2329
|
+
annotations.get(self.objpath[-1]),
|
|
2330
|
+
mode,
|
|
2331
|
+
short_literals=short_literals,
|
|
2332
|
+
)
|
|
2095
2333
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2096
2334
|
|
|
2097
2335
|
try:
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
2336
|
+
if (
|
|
2337
|
+
self.options.no_value
|
|
2338
|
+
or self.should_suppress_value_header()
|
|
2339
|
+
or ismock(self.object)
|
|
2340
|
+
):
|
|
2100
2341
|
pass
|
|
2101
2342
|
else:
|
|
2102
2343
|
objrepr = object_description(self.object)
|
|
@@ -2144,9 +2385,7 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2144
2385
|
|
|
2145
2386
|
|
|
2146
2387
|
class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: ignore[misc]
|
|
2147
|
-
"""
|
|
2148
|
-
Specialized Documenter subclass for methods (normal, static and class).
|
|
2149
|
-
"""
|
|
2388
|
+
"""Specialized Documenter subclass for methods (normal, static and class)."""
|
|
2150
2389
|
|
|
2151
2390
|
objtype = 'method'
|
|
2152
2391
|
directivetype = 'method'
|
|
@@ -2155,7 +2394,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2155
2394
|
|
|
2156
2395
|
@classmethod
|
|
2157
2396
|
def can_document_member(
|
|
2158
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2397
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2159
2398
|
) -> bool:
|
|
2160
2399
|
return inspect.isroutine(member) and not isinstance(parent, ModuleDocumenter)
|
|
2161
2400
|
|
|
@@ -2165,22 +2404,23 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2165
2404
|
return ret
|
|
2166
2405
|
|
|
2167
2406
|
# to distinguish classmethod/staticmethod
|
|
2168
|
-
obj = self.parent.__dict__.get(self.object_name)
|
|
2169
|
-
if obj
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
#
|
|
2175
|
-
self.member_order
|
|
2176
|
-
|
|
2407
|
+
obj = self.parent.__dict__.get(self.object_name, self.object)
|
|
2408
|
+
if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name):
|
|
2409
|
+
# document static members before regular methods
|
|
2410
|
+
self.member_order -= 1
|
|
2411
|
+
elif inspect.isclassmethod(obj):
|
|
2412
|
+
# document class methods before static methods as
|
|
2413
|
+
# they usually behave as alternative constructors
|
|
2414
|
+
self.member_order -= 2
|
|
2177
2415
|
return ret
|
|
2178
2416
|
|
|
2179
2417
|
def format_args(self, **kwargs: Any) -> str:
|
|
2180
|
-
if self.config.autodoc_typehints in
|
|
2418
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
2181
2419
|
kwargs.setdefault('show_annotation', False)
|
|
2182
|
-
if self.config.autodoc_typehints_format ==
|
|
2420
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
2183
2421
|
kwargs.setdefault('unqualified_typehints', True)
|
|
2422
|
+
if self.config.python_display_short_literal_types:
|
|
2423
|
+
kwargs.setdefault('short_literals', True)
|
|
2184
2424
|
|
|
2185
2425
|
try:
|
|
2186
2426
|
if self.object == object.__init__ and self.parent != object: # NoQA: E721
|
|
@@ -2190,18 +2430,31 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2190
2430
|
# But it makes users confused.
|
|
2191
2431
|
args = '()'
|
|
2192
2432
|
else:
|
|
2193
|
-
if inspect.isstaticmethod(
|
|
2194
|
-
self.
|
|
2195
|
-
|
|
2196
|
-
|
|
2433
|
+
if inspect.isstaticmethod(
|
|
2434
|
+
self.object, cls=self.parent, name=self.object_name
|
|
2435
|
+
):
|
|
2436
|
+
self._events.emit(
|
|
2437
|
+
'autodoc-before-process-signature', self.object, False
|
|
2438
|
+
)
|
|
2439
|
+
sig = inspect.signature(
|
|
2440
|
+
self.object,
|
|
2441
|
+
bound_method=False,
|
|
2442
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
2443
|
+
)
|
|
2197
2444
|
else:
|
|
2198
|
-
self.
|
|
2199
|
-
|
|
2200
|
-
|
|
2445
|
+
self._events.emit(
|
|
2446
|
+
'autodoc-before-process-signature', self.object, True
|
|
2447
|
+
)
|
|
2448
|
+
sig = inspect.signature(
|
|
2449
|
+
self.object,
|
|
2450
|
+
bound_method=True,
|
|
2451
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
2452
|
+
)
|
|
2201
2453
|
args = stringify_signature(sig, **kwargs)
|
|
2202
2454
|
except TypeError as exc:
|
|
2203
|
-
logger.warning(
|
|
2204
|
-
|
|
2455
|
+
logger.warning(
|
|
2456
|
+
__('Failed to get a method signature for %s: %s'), self.fullname, exc
|
|
2457
|
+
)
|
|
2205
2458
|
return ''
|
|
2206
2459
|
except ValueError:
|
|
2207
2460
|
args = ''
|
|
@@ -2220,8 +2473,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2220
2473
|
self.add_line(' :abstractmethod:', sourcename)
|
|
2221
2474
|
if inspect.iscoroutinefunction(obj) or inspect.isasyncgenfunction(obj):
|
|
2222
2475
|
self.add_line(' :async:', sourcename)
|
|
2223
|
-
if (
|
|
2224
|
-
|
|
2476
|
+
if (
|
|
2477
|
+
inspect.is_classmethod_like(obj)
|
|
2478
|
+
or inspect.is_singledispatch_method(obj)
|
|
2479
|
+
and inspect.is_classmethod_like(obj.func)
|
|
2480
|
+
):
|
|
2225
2481
|
self.add_line(' :classmethod:', sourcename)
|
|
2226
2482
|
if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name):
|
|
2227
2483
|
self.add_line(' :staticmethod:', sourcename)
|
|
@@ -2232,13 +2488,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2232
2488
|
pass
|
|
2233
2489
|
|
|
2234
2490
|
def format_signature(self, **kwargs: Any) -> str:
|
|
2235
|
-
if self.config.autodoc_typehints_format ==
|
|
2491
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
2236
2492
|
kwargs.setdefault('unqualified_typehints', True)
|
|
2493
|
+
if self.config.python_display_short_literal_types:
|
|
2494
|
+
kwargs.setdefault('short_literals', True)
|
|
2237
2495
|
|
|
2238
2496
|
sigs = []
|
|
2239
|
-
if (
|
|
2240
|
-
|
|
2241
|
-
|
|
2497
|
+
if (
|
|
2498
|
+
self.analyzer
|
|
2499
|
+
and '.'.join(self.objpath) in self.analyzer.overloads
|
|
2500
|
+
and self.config.autodoc_typehints != 'none'
|
|
2501
|
+
):
|
|
2242
2502
|
# Use signatures for overloaded methods instead of the implementation method.
|
|
2243
2503
|
overloaded = True
|
|
2244
2504
|
else:
|
|
@@ -2263,27 +2523,37 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2263
2523
|
documenter.objpath = ['']
|
|
2264
2524
|
sigs.append(documenter.format_signature())
|
|
2265
2525
|
if overloaded and self.analyzer is not None:
|
|
2266
|
-
if inspect.isstaticmethod(
|
|
2267
|
-
|
|
2268
|
-
|
|
2526
|
+
if inspect.isstaticmethod(
|
|
2527
|
+
self.object, cls=self.parent, name=self.object_name
|
|
2528
|
+
):
|
|
2529
|
+
actual = inspect.signature(
|
|
2530
|
+
self.object,
|
|
2531
|
+
bound_method=False,
|
|
2532
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
2533
|
+
)
|
|
2269
2534
|
else:
|
|
2270
|
-
actual = inspect.signature(
|
|
2271
|
-
|
|
2535
|
+
actual = inspect.signature(
|
|
2536
|
+
self.object,
|
|
2537
|
+
bound_method=True,
|
|
2538
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
2539
|
+
)
|
|
2272
2540
|
|
|
2273
2541
|
__globals__ = safe_getattr(self.object, '__globals__', {})
|
|
2274
2542
|
for overload in self.analyzer.overloads['.'.join(self.objpath)]:
|
|
2275
2543
|
overload = self.merge_default_value(actual, overload)
|
|
2276
|
-
overload = evaluate_signature(
|
|
2277
|
-
|
|
2544
|
+
overload = evaluate_signature(
|
|
2545
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
2546
|
+
)
|
|
2278
2547
|
|
|
2279
|
-
if not inspect.isstaticmethod(
|
|
2280
|
-
|
|
2548
|
+
if not inspect.isstaticmethod(
|
|
2549
|
+
self.object, cls=self.parent, name=self.object_name
|
|
2550
|
+
):
|
|
2281
2551
|
parameters = list(overload.parameters.values())
|
|
2282
2552
|
overload = overload.replace(parameters=parameters[1:])
|
|
2283
2553
|
sig = stringify_signature(overload, **kwargs)
|
|
2284
2554
|
sigs.append(sig)
|
|
2285
2555
|
|
|
2286
|
-
return
|
|
2556
|
+
return '\n'.join(sigs)
|
|
2287
2557
|
|
|
2288
2558
|
def merge_default_value(self, actual: Signature, overload: Signature) -> Signature:
|
|
2289
2559
|
"""Merge default values of actual implementation to the overload variants."""
|
|
@@ -2295,13 +2565,16 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2295
2565
|
|
|
2296
2566
|
return overload.replace(parameters=parameters)
|
|
2297
2567
|
|
|
2298
|
-
def annotate_to_first_argument(
|
|
2568
|
+
def annotate_to_first_argument(
|
|
2569
|
+
self, func: Callable[..., Any], typ: type
|
|
2570
|
+
) -> Callable[..., Any] | None:
|
|
2299
2571
|
"""Annotate type hint to the first argument of function if needed."""
|
|
2300
2572
|
try:
|
|
2301
2573
|
sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
|
|
2302
2574
|
except TypeError as exc:
|
|
2303
|
-
logger.warning(
|
|
2304
|
-
|
|
2575
|
+
logger.warning(
|
|
2576
|
+
__('Failed to get a method signature for %s: %s'), self.fullname, exc
|
|
2577
|
+
)
|
|
2305
2578
|
return None
|
|
2306
2579
|
except ValueError:
|
|
2307
2580
|
return None
|
|
@@ -2317,7 +2590,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2317
2590
|
params[1] = params[1].replace(annotation=typ)
|
|
2318
2591
|
try:
|
|
2319
2592
|
dummy.__signature__ = sig.replace( # type: ignore[attr-defined]
|
|
2320
|
-
parameters=params
|
|
2593
|
+
parameters=params
|
|
2594
|
+
)
|
|
2321
2595
|
return dummy
|
|
2322
2596
|
except (AttributeError, TypeError):
|
|
2323
2597
|
# failed to update signature (ex. built-in or extension types)
|
|
@@ -2333,12 +2607,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2333
2607
|
# `DocstringSignatureMixin`.
|
|
2334
2608
|
return self._new_docstrings
|
|
2335
2609
|
if self.objpath[-1] == '__init__':
|
|
2336
|
-
docstring = getdoc(
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2610
|
+
docstring = getdoc(
|
|
2611
|
+
self.object,
|
|
2612
|
+
self.get_attr,
|
|
2613
|
+
self.config.autodoc_inherit_docstrings,
|
|
2614
|
+
self.parent,
|
|
2615
|
+
self.object_name,
|
|
2616
|
+
)
|
|
2617
|
+
if docstring is not None and (
|
|
2618
|
+
docstring == object.__init__.__doc__ # for pypy
|
|
2619
|
+
or docstring.strip() == object.__init__.__doc__ # for !pypy
|
|
2620
|
+
):
|
|
2342
2621
|
docstring = None
|
|
2343
2622
|
if docstring:
|
|
2344
2623
|
tab_width = self.directive.state.document.settings.tab_width
|
|
@@ -2346,12 +2625,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2346
2625
|
else:
|
|
2347
2626
|
return []
|
|
2348
2627
|
elif self.objpath[-1] == '__new__':
|
|
2349
|
-
docstring = getdoc(
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2628
|
+
docstring = getdoc(
|
|
2629
|
+
self.object,
|
|
2630
|
+
self.get_attr,
|
|
2631
|
+
self.config.autodoc_inherit_docstrings,
|
|
2632
|
+
self.parent,
|
|
2633
|
+
self.object_name,
|
|
2634
|
+
)
|
|
2635
|
+
if docstring is not None and (
|
|
2636
|
+
docstring == object.__new__.__doc__ # for pypy
|
|
2637
|
+
or docstring.strip() == object.__new__.__doc__ # for !pypy
|
|
2638
|
+
):
|
|
2355
2639
|
docstring = None
|
|
2356
2640
|
if docstring:
|
|
2357
2641
|
tab_width = self.directive.state.document.settings.tab_width
|
|
@@ -2363,8 +2647,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2363
2647
|
|
|
2364
2648
|
|
|
2365
2649
|
class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
2366
|
-
"""
|
|
2367
|
-
Mixin for AttributeDocumenter to provide the feature for supporting non
|
|
2650
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting non
|
|
2368
2651
|
data-descriptors.
|
|
2369
2652
|
|
|
2370
2653
|
.. note:: This mix-in must be inherited after other mix-ins. Otherwise, docstring
|
|
@@ -2381,8 +2664,10 @@ class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
|
2381
2664
|
return ret
|
|
2382
2665
|
|
|
2383
2666
|
def should_suppress_value_header(self) -> bool:
|
|
2384
|
-
return (
|
|
2385
|
-
|
|
2667
|
+
return (
|
|
2668
|
+
not getattr(self, 'non_data_descriptor', False)
|
|
2669
|
+
or super().should_suppress_directive_header()
|
|
2670
|
+
)
|
|
2386
2671
|
|
|
2387
2672
|
def get_doc(self) -> list[list[str]] | None:
|
|
2388
2673
|
if getattr(self, 'non_data_descriptor', False):
|
|
@@ -2394,9 +2679,7 @@ class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
|
2394
2679
|
|
|
2395
2680
|
|
|
2396
2681
|
class SlotsMixin(DataDocumenterMixinBase):
|
|
2397
|
-
"""
|
|
2398
|
-
Mixin for AttributeDocumenter to provide the feature for supporting __slots__.
|
|
2399
|
-
"""
|
|
2682
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting __slots__."""
|
|
2400
2683
|
|
|
2401
2684
|
def isslotsattribute(self) -> bool:
|
|
2402
2685
|
"""Check the subject is an attribute in __slots__."""
|
|
@@ -2425,25 +2708,29 @@ class SlotsMixin(DataDocumenterMixinBase):
|
|
|
2425
2708
|
if self.object is SLOTSATTR:
|
|
2426
2709
|
try:
|
|
2427
2710
|
parent___slots__ = inspect.getslots(self.parent)
|
|
2428
|
-
if parent___slots__ and (
|
|
2711
|
+
if parent___slots__ and (
|
|
2712
|
+
docstring := parent___slots__.get(self.objpath[-1])
|
|
2713
|
+
):
|
|
2429
2714
|
docstring = prepare_docstring(docstring)
|
|
2430
2715
|
return [docstring]
|
|
2431
2716
|
else:
|
|
2432
2717
|
return []
|
|
2433
2718
|
except ValueError as exc:
|
|
2434
|
-
logger.warning(
|
|
2435
|
-
|
|
2719
|
+
logger.warning(
|
|
2720
|
+
__('Invalid __slots__ found on %s. Ignored.'),
|
|
2721
|
+
(self.parent.__qualname__, exc),
|
|
2722
|
+
type='autodoc',
|
|
2723
|
+
)
|
|
2436
2724
|
return []
|
|
2437
2725
|
else:
|
|
2438
2726
|
return super().get_doc() # type: ignore[misc]
|
|
2439
2727
|
|
|
2440
2728
|
|
|
2441
2729
|
class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
2442
|
-
"""
|
|
2443
|
-
Mixin for AttributeDocumenter to provide the feature for supporting runtime
|
|
2730
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting runtime
|
|
2444
2731
|
instance attributes (that are defined in __init__() methods with doc-comments).
|
|
2445
2732
|
|
|
2446
|
-
Example
|
|
2733
|
+
Example::
|
|
2447
2734
|
|
|
2448
2735
|
class Foo:
|
|
2449
2736
|
def __init__(self):
|
|
@@ -2487,7 +2774,9 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2487
2774
|
try:
|
|
2488
2775
|
with mock(self.config.autodoc_mock_imports):
|
|
2489
2776
|
ret = import_object(
|
|
2490
|
-
self.modname,
|
|
2777
|
+
self.modname,
|
|
2778
|
+
self.objpath[:-1],
|
|
2779
|
+
'class',
|
|
2491
2780
|
attrgetter=self.get_attr, # type: ignore[attr-defined]
|
|
2492
2781
|
)
|
|
2493
2782
|
parent = ret[3]
|
|
@@ -2505,23 +2794,26 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2505
2794
|
return False
|
|
2506
2795
|
|
|
2507
2796
|
def should_suppress_value_header(self) -> bool:
|
|
2508
|
-
return (
|
|
2509
|
-
|
|
2797
|
+
return (
|
|
2798
|
+
self.object is self.RUNTIME_INSTANCE_ATTRIBUTE
|
|
2799
|
+
or super().should_suppress_value_header()
|
|
2800
|
+
)
|
|
2510
2801
|
|
|
2511
2802
|
def get_doc(self) -> list[list[str]] | None:
|
|
2512
|
-
if (
|
|
2513
|
-
|
|
2803
|
+
if (
|
|
2804
|
+
self.object is self.RUNTIME_INSTANCE_ATTRIBUTE
|
|
2805
|
+
and self.is_runtime_instance_attribute_not_commented(self.parent)
|
|
2806
|
+
):
|
|
2514
2807
|
return None
|
|
2515
2808
|
else:
|
|
2516
2809
|
return super().get_doc() # type: ignore[misc]
|
|
2517
2810
|
|
|
2518
2811
|
|
|
2519
2812
|
class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
2520
|
-
"""
|
|
2521
|
-
Mixin for AttributeDocumenter to provide the feature for supporting uninitialized
|
|
2813
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting uninitialized
|
|
2522
2814
|
instance attributes (PEP-526 styled, annotation only attributes).
|
|
2523
2815
|
|
|
2524
|
-
Example
|
|
2816
|
+
Example::
|
|
2525
2817
|
|
|
2526
2818
|
class Foo:
|
|
2527
2819
|
attr: int #: This is a target of this mix-in.
|
|
@@ -2529,8 +2821,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2529
2821
|
|
|
2530
2822
|
def is_uninitialized_instance_attribute(self, parent: Any) -> bool:
|
|
2531
2823
|
"""Check the subject is an annotation only attribute."""
|
|
2532
|
-
annotations = get_type_hints(
|
|
2533
|
-
|
|
2824
|
+
annotations = get_type_hints(
|
|
2825
|
+
parent, None, self.config.autodoc_type_aliases, include_extras=True
|
|
2826
|
+
)
|
|
2534
2827
|
return self.objpath[-1] in annotations
|
|
2535
2828
|
|
|
2536
2829
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -2542,7 +2835,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2542
2835
|
except ImportError as exc:
|
|
2543
2836
|
try:
|
|
2544
2837
|
ret = import_object(
|
|
2545
|
-
self.modname,
|
|
2838
|
+
self.modname,
|
|
2839
|
+
self.objpath[:-1],
|
|
2840
|
+
'class',
|
|
2546
2841
|
attrgetter=self.get_attr, # type: ignore[attr-defined]
|
|
2547
2842
|
)
|
|
2548
2843
|
parent = ret[3]
|
|
@@ -2560,8 +2855,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2560
2855
|
return False
|
|
2561
2856
|
|
|
2562
2857
|
def should_suppress_value_header(self) -> bool:
|
|
2563
|
-
return (
|
|
2564
|
-
|
|
2858
|
+
return (
|
|
2859
|
+
self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header()
|
|
2860
|
+
)
|
|
2565
2861
|
|
|
2566
2862
|
def get_doc(self) -> list[list[str]] | None:
|
|
2567
2863
|
if self.object is UNINITIALIZED_ATTR:
|
|
@@ -2569,19 +2865,22 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2569
2865
|
return super().get_doc() # type: ignore[misc]
|
|
2570
2866
|
|
|
2571
2867
|
|
|
2572
|
-
class AttributeDocumenter(
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2868
|
+
class AttributeDocumenter( # type: ignore[misc]
|
|
2869
|
+
GenericAliasMixin,
|
|
2870
|
+
SlotsMixin,
|
|
2871
|
+
RuntimeInstanceAttributeMixin,
|
|
2872
|
+
UninitializedInstanceAttributeMixin,
|
|
2873
|
+
NonDataDescriptorMixin,
|
|
2874
|
+
DocstringStripSignatureMixin,
|
|
2875
|
+
ClassLevelDocumenter,
|
|
2876
|
+
):
|
|
2877
|
+
"""Specialized Documenter subclass for attributes."""
|
|
2579
2878
|
|
|
2580
2879
|
objtype = 'attribute'
|
|
2581
2880
|
member_order = 60
|
|
2582
2881
|
option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec)
|
|
2583
|
-
option_spec[
|
|
2584
|
-
option_spec[
|
|
2882
|
+
option_spec['annotation'] = annotation_option
|
|
2883
|
+
option_spec['no-value'] = bool_option
|
|
2585
2884
|
|
|
2586
2885
|
# must be higher than the MethodDocumenter, else it will recognize
|
|
2587
2886
|
# some non-data descriptors as methods
|
|
@@ -2589,11 +2888,13 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2589
2888
|
|
|
2590
2889
|
@staticmethod
|
|
2591
2890
|
def is_function_or_method(obj: Any) -> bool:
|
|
2592
|
-
return
|
|
2891
|
+
return (
|
|
2892
|
+
inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj)
|
|
2893
|
+
)
|
|
2593
2894
|
|
|
2594
2895
|
@classmethod
|
|
2595
2896
|
def can_document_member(
|
|
2596
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2897
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2597
2898
|
) -> bool:
|
|
2598
2899
|
if isinstance(parent, ModuleDocumenter):
|
|
2599
2900
|
return False
|
|
@@ -2617,7 +2918,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2617
2918
|
|
|
2618
2919
|
analyzer = ModuleAnalyzer.for_module(module)
|
|
2619
2920
|
analyzer.analyze()
|
|
2620
|
-
|
|
2921
|
+
anns = analyzer.annotations
|
|
2922
|
+
for (classname, attrname), annotation in anns.items():
|
|
2621
2923
|
if classname == qualname and attrname not in annotations:
|
|
2622
2924
|
annotations[attrname] = annotation
|
|
2623
2925
|
except (AttributeError, PycodeError):
|
|
@@ -2646,7 +2948,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2646
2948
|
doc = self.get_doc()
|
|
2647
2949
|
if doc:
|
|
2648
2950
|
docstring, metadata = separate_metadata(
|
|
2649
|
-
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2951
|
+
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2952
|
+
)
|
|
2650
2953
|
if 'hide-value' in metadata:
|
|
2651
2954
|
return True
|
|
2652
2955
|
|
|
@@ -2655,28 +2958,38 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2655
2958
|
def add_directive_header(self, sig: str) -> None:
|
|
2656
2959
|
super().add_directive_header(sig)
|
|
2657
2960
|
sourcename = self.get_sourcename()
|
|
2658
|
-
if
|
|
2961
|
+
if (
|
|
2962
|
+
self.options.annotation is SUPPRESS
|
|
2963
|
+
or self.should_suppress_directive_header()
|
|
2964
|
+
):
|
|
2659
2965
|
pass
|
|
2660
2966
|
elif self.options.annotation:
|
|
2661
2967
|
self.add_line(' :annotation: %s' % self.options.annotation, sourcename)
|
|
2662
2968
|
else:
|
|
2663
2969
|
if self.config.autodoc_typehints != 'none':
|
|
2664
2970
|
# obtain type annotation for this attribute
|
|
2665
|
-
annotations = get_type_hints(
|
|
2666
|
-
|
|
2667
|
-
|
|
2971
|
+
annotations = get_type_hints(
|
|
2972
|
+
self.parent,
|
|
2973
|
+
None,
|
|
2974
|
+
self.config.autodoc_type_aliases,
|
|
2975
|
+
include_extras=True,
|
|
2976
|
+
)
|
|
2668
2977
|
if self.objpath[-1] in annotations:
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2978
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
2979
|
+
short_literals = self.config.python_display_short_literal_types
|
|
2980
|
+
objrepr = stringify_annotation(
|
|
2981
|
+
annotations.get(self.objpath[-1]),
|
|
2982
|
+
mode,
|
|
2983
|
+
short_literals=short_literals,
|
|
2984
|
+
)
|
|
2675
2985
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2676
2986
|
|
|
2677
2987
|
try:
|
|
2678
|
-
if (
|
|
2679
|
-
|
|
2988
|
+
if (
|
|
2989
|
+
self.options.no_value
|
|
2990
|
+
or self.should_suppress_value_header()
|
|
2991
|
+
or ismock(self.object)
|
|
2992
|
+
):
|
|
2680
2993
|
pass
|
|
2681
2994
|
else:
|
|
2682
2995
|
objrepr = object_description(self.object)
|
|
@@ -2710,7 +3023,7 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2710
3023
|
try:
|
|
2711
3024
|
# Disable `autodoc_inherit_docstring` temporarily to avoid to obtain
|
|
2712
3025
|
# a docstring from the value which descriptor returns unexpectedly.
|
|
2713
|
-
#
|
|
3026
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/7805
|
|
2714
3027
|
orig = self.config.autodoc_inherit_docstrings
|
|
2715
3028
|
self.config.autodoc_inherit_docstrings = False
|
|
2716
3029
|
return super().get_doc()
|
|
@@ -2728,11 +3041,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2728
3041
|
super().add_content(more_content)
|
|
2729
3042
|
|
|
2730
3043
|
|
|
2731
|
-
class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
2732
|
-
|
|
2733
|
-
"""
|
|
2734
|
-
Specialized Documenter subclass for properties.
|
|
2735
|
-
"""
|
|
3044
|
+
class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore[misc]
|
|
3045
|
+
"""Specialized Documenter subclass for properties."""
|
|
2736
3046
|
|
|
2737
3047
|
objtype = 'property'
|
|
2738
3048
|
member_order = 60
|
|
@@ -2742,7 +3052,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2742
3052
|
|
|
2743
3053
|
@classmethod
|
|
2744
3054
|
def can_document_member(
|
|
2745
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
3055
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2746
3056
|
) -> bool:
|
|
2747
3057
|
if isinstance(parent, ClassDocumenter):
|
|
2748
3058
|
if inspect.isproperty(member):
|
|
@@ -2778,7 +3088,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2778
3088
|
return ''
|
|
2779
3089
|
|
|
2780
3090
|
# update the annotations of the property getter
|
|
2781
|
-
self.
|
|
3091
|
+
self._events.emit('autodoc-before-process-signature', func, False)
|
|
2782
3092
|
# correctly format the arguments for a property
|
|
2783
3093
|
return super().format_args(**kwargs)
|
|
2784
3094
|
|
|
@@ -2802,23 +3112,25 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2802
3112
|
return
|
|
2803
3113
|
|
|
2804
3114
|
try:
|
|
2805
|
-
signature = inspect.signature(
|
|
2806
|
-
|
|
3115
|
+
signature = inspect.signature(
|
|
3116
|
+
func, type_aliases=self.config.autodoc_type_aliases
|
|
3117
|
+
)
|
|
2807
3118
|
if signature.return_annotation is not Parameter.empty:
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
3119
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
3120
|
+
short_literals = self.config.python_display_short_literal_types
|
|
3121
|
+
objrepr = stringify_annotation(
|
|
3122
|
+
signature.return_annotation, mode, short_literals=short_literals
|
|
3123
|
+
)
|
|
2813
3124
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2814
3125
|
except TypeError as exc:
|
|
2815
|
-
logger.warning(
|
|
2816
|
-
|
|
3126
|
+
logger.warning(
|
|
3127
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
3128
|
+
)
|
|
2817
3129
|
pass
|
|
2818
3130
|
except ValueError:
|
|
2819
3131
|
pass
|
|
2820
3132
|
|
|
2821
|
-
def _get_property_getter(self) -> Callable | None:
|
|
3133
|
+
def _get_property_getter(self) -> Callable[..., Any] | None:
|
|
2822
3134
|
if safe_getattr(self.object, 'fget', None): # property
|
|
2823
3135
|
return self.object.fget
|
|
2824
3136
|
if safe_getattr(self.object, 'func', None): # cached_property
|
|
@@ -2826,9 +3138,11 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2826
3138
|
return None
|
|
2827
3139
|
|
|
2828
3140
|
|
|
2829
|
-
def autodoc_attrgetter(
|
|
3141
|
+
def autodoc_attrgetter(
|
|
3142
|
+
registry: SphinxComponentRegistry, obj: Any, name: str, *defargs: Any
|
|
3143
|
+
) -> Any:
|
|
2830
3144
|
"""Alternative getattr() for types"""
|
|
2831
|
-
for typ, func in
|
|
3145
|
+
for typ, func in registry.autodoc_attrgetters.items():
|
|
2832
3146
|
if isinstance(obj, typ):
|
|
2833
3147
|
return func(obj, name, *defargs)
|
|
2834
3148
|
|
|
@@ -2846,22 +3160,54 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
2846
3160
|
app.add_autodocumenter(AttributeDocumenter)
|
|
2847
3161
|
app.add_autodocumenter(PropertyDocumenter)
|
|
2848
3162
|
|
|
2849
|
-
app.add_config_value(
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
app.add_config_value(
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
app.add_config_value(
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
3163
|
+
app.add_config_value(
|
|
3164
|
+
'autoclass_content',
|
|
3165
|
+
'class',
|
|
3166
|
+
'env',
|
|
3167
|
+
types=ENUM('both', 'class', 'init'),
|
|
3168
|
+
)
|
|
3169
|
+
app.add_config_value(
|
|
3170
|
+
'autodoc_member_order',
|
|
3171
|
+
'alphabetical',
|
|
3172
|
+
'env',
|
|
3173
|
+
types=ENUM('alphabetical', 'bysource', 'groupwise'),
|
|
3174
|
+
)
|
|
3175
|
+
app.add_config_value(
|
|
3176
|
+
'autodoc_class_signature',
|
|
3177
|
+
'mixed',
|
|
3178
|
+
'env',
|
|
3179
|
+
types=ENUM('mixed', 'separated'),
|
|
3180
|
+
)
|
|
3181
|
+
app.add_config_value('autodoc_default_options', {}, 'env', types=frozenset({dict}))
|
|
3182
|
+
app.add_config_value(
|
|
3183
|
+
'autodoc_docstring_signature', True, 'env', types=frozenset({bool})
|
|
3184
|
+
)
|
|
3185
|
+
app.add_config_value(
|
|
3186
|
+
'autodoc_mock_imports', [], 'env', types=frozenset({list, tuple})
|
|
3187
|
+
)
|
|
3188
|
+
app.add_config_value(
|
|
3189
|
+
'autodoc_typehints',
|
|
3190
|
+
'signature',
|
|
3191
|
+
'env',
|
|
3192
|
+
types=ENUM('signature', 'description', 'none', 'both'),
|
|
3193
|
+
)
|
|
3194
|
+
app.add_config_value(
|
|
3195
|
+
'autodoc_typehints_description_target',
|
|
3196
|
+
'all',
|
|
3197
|
+
'env',
|
|
3198
|
+
types=ENUM('all', 'documented', 'documented_params'),
|
|
3199
|
+
)
|
|
3200
|
+
app.add_config_value('autodoc_type_aliases', {}, 'env', types=frozenset({dict}))
|
|
3201
|
+
app.add_config_value(
|
|
3202
|
+
'autodoc_typehints_format',
|
|
3203
|
+
'short',
|
|
3204
|
+
'env',
|
|
3205
|
+
types=ENUM('fully-qualified', 'short'),
|
|
3206
|
+
)
|
|
3207
|
+
app.add_config_value('autodoc_warningiserror', True, 'env', types=frozenset({bool}))
|
|
3208
|
+
app.add_config_value(
|
|
3209
|
+
'autodoc_inherit_docstrings', True, 'env', types=frozenset({bool})
|
|
3210
|
+
)
|
|
2865
3211
|
app.add_event('autodoc-before-process-signature')
|
|
2866
3212
|
app.add_event('autodoc-process-docstring')
|
|
2867
3213
|
app.add_event('autodoc-process-signature')
|
|
@@ -2872,4 +3218,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
2872
3218
|
app.setup_extension('sphinx.ext.autodoc.type_comment')
|
|
2873
3219
|
app.setup_extension('sphinx.ext.autodoc.typehints')
|
|
2874
3220
|
|
|
2875
|
-
return {
|
|
3221
|
+
return {
|
|
3222
|
+
'version': sphinx.__display_version__,
|
|
3223
|
+
'parallel_read_safe': True,
|
|
3224
|
+
}
|