Sphinx 8.1.2__py3-none-any.whl → 8.2.0__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 +50 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +134 -61
- sphinx/domains/python/_object.py +155 -68
- 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 +66 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +99 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- 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 +281 -142
- 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/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/sphinx.pot +2069 -1964
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
- 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 +63 -52
- sphinx/writers/latex.py +83 -67
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +47 -47
- sphinx/writers/text.py +50 -32
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
- sphinx-8.2.0.dist-info/RECORD +606 -0
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.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.2.dist-info/RECORD +0 -598
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.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,16 +186,18 @@ 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
|
-
pre: int, post: int = 0, what:
|
|
200
|
+
pre: int, post: int = 0, what: Sequence[str] | None = None
|
|
190
201
|
) -> _AutodocProcessDocstringListener:
|
|
191
202
|
"""Return a listener that removes the first *pre* and last *post*
|
|
192
203
|
lines of every docstring. If *what* is a sequence of strings,
|
|
@@ -195,11 +206,17 @@ 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`.
|
|
201
213
|
"""
|
|
202
|
-
|
|
214
|
+
if not what:
|
|
215
|
+
what_unique: frozenset[str] = frozenset()
|
|
216
|
+
elif isinstance(what, str): # strongly discouraged
|
|
217
|
+
what_unique = frozenset({what})
|
|
218
|
+
else:
|
|
219
|
+
what_unique = frozenset(what)
|
|
203
220
|
|
|
204
221
|
def process(
|
|
205
222
|
app: Sphinx,
|
|
@@ -209,7 +226,7 @@ def cut_lines(
|
|
|
209
226
|
options: dict[str, bool],
|
|
210
227
|
lines: list[str],
|
|
211
228
|
) -> None:
|
|
212
|
-
if what_ not in what_unique:
|
|
229
|
+
if what_unique and what_ not in what_unique:
|
|
213
230
|
return
|
|
214
231
|
del lines[:pre]
|
|
215
232
|
if post:
|
|
@@ -220,6 +237,7 @@ def cut_lines(
|
|
|
220
237
|
# make sure there is a blank line at the end
|
|
221
238
|
if lines and lines[-1]:
|
|
222
239
|
lines.append('')
|
|
240
|
+
|
|
223
241
|
return process
|
|
224
242
|
|
|
225
243
|
|
|
@@ -266,11 +284,13 @@ def between(
|
|
|
266
284
|
# make sure there is a blank line at the end
|
|
267
285
|
if lines and lines[-1]:
|
|
268
286
|
lines.append('')
|
|
287
|
+
|
|
269
288
|
return process
|
|
270
289
|
|
|
271
290
|
|
|
272
291
|
# This class is used only in ``sphinx.ext.autodoc.directive``,
|
|
273
|
-
# 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
|
|
274
294
|
class Options(dict[str, Any]):
|
|
275
295
|
"""A dict/attribute hybrid that returns None on nonexisting keys."""
|
|
276
296
|
|
|
@@ -291,18 +311,43 @@ class ObjectMember:
|
|
|
291
311
|
represent each member of the object.
|
|
292
312
|
"""
|
|
293
313
|
|
|
294
|
-
|
|
295
|
-
|
|
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:
|
|
296
331
|
self.__name__ = name
|
|
297
332
|
self.object = obj
|
|
298
333
|
self.docstring = docstring
|
|
299
|
-
self.skipped = skipped
|
|
300
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
|
+
)
|
|
301
347
|
|
|
302
348
|
|
|
303
349
|
class Documenter:
|
|
304
|
-
"""
|
|
305
|
-
A Documenter knows how to autodocument a single object type. When
|
|
350
|
+
"""A Documenter knows how to autodocument a single object type. When
|
|
306
351
|
registered with the AutoDirective, it will be used to document objects
|
|
307
352
|
of that type when needed by autodoc.
|
|
308
353
|
|
|
@@ -330,25 +375,30 @@ class Documenter:
|
|
|
330
375
|
|
|
331
376
|
option_spec: ClassVar[OptionSpec] = {
|
|
332
377
|
'no-index': bool_option,
|
|
378
|
+
'no-index-entry': bool_option,
|
|
333
379
|
'noindex': bool_option,
|
|
334
380
|
}
|
|
335
381
|
|
|
336
382
|
def get_attr(self, obj: Any, name: str, *defargs: Any) -> Any:
|
|
337
383
|
"""getattr() override for types such as Zope interfaces."""
|
|
338
|
-
return autodoc_attrgetter(
|
|
384
|
+
return autodoc_attrgetter(obj, name, *defargs, registry=self.env._registry)
|
|
339
385
|
|
|
340
386
|
@classmethod
|
|
341
387
|
def can_document_member(
|
|
342
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
388
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
343
389
|
) -> bool:
|
|
344
390
|
"""Called to see if a member can be documented by this Documenter."""
|
|
345
391
|
msg = 'must be implemented in subclasses'
|
|
346
392
|
raise NotImplementedError(msg)
|
|
347
393
|
|
|
348
|
-
def __init__(
|
|
394
|
+
def __init__(
|
|
395
|
+
self, directive: DocumenterBridge, name: str, indent: str = ''
|
|
396
|
+
) -> None:
|
|
349
397
|
self.directive = directive
|
|
350
398
|
self.config: Config = directive.env.config
|
|
351
399
|
self.env: BuildEnvironment = directive.env
|
|
400
|
+
self._current_document: _CurrentDocument = directive.env.current_document
|
|
401
|
+
self._events: EventManager = directive.env.events
|
|
352
402
|
self.options = directive.genopt
|
|
353
403
|
self.name = name
|
|
354
404
|
self.indent = indent
|
|
@@ -373,7 +423,7 @@ class Documenter:
|
|
|
373
423
|
@property
|
|
374
424
|
def documenters(self) -> dict[str, type[Documenter]]:
|
|
375
425
|
"""Returns registered Documenter classes"""
|
|
376
|
-
return self.env.
|
|
426
|
+
return self.env._registry.documenters
|
|
377
427
|
|
|
378
428
|
def add_line(self, line: str, source: str, *lineno: int) -> None:
|
|
379
429
|
"""Append one line of generated reST to the output."""
|
|
@@ -382,8 +432,9 @@ class Documenter:
|
|
|
382
432
|
else:
|
|
383
433
|
self.directive.result.append('', source, *lineno)
|
|
384
434
|
|
|
385
|
-
def resolve_name(
|
|
386
|
-
|
|
435
|
+
def resolve_name(
|
|
436
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
437
|
+
) -> tuple[str | None, list[str]]:
|
|
387
438
|
"""Resolve the module and name of the object to document given by the
|
|
388
439
|
arguments and the current module/class.
|
|
389
440
|
|
|
@@ -405,8 +456,12 @@ class Documenter:
|
|
|
405
456
|
# an autogenerated one
|
|
406
457
|
matched = py_ext_sig_re.match(self.name)
|
|
407
458
|
if matched is None:
|
|
408
|
-
logger.warning(
|
|
409
|
-
|
|
459
|
+
logger.warning(
|
|
460
|
+
__('invalid signature for auto%s (%r)'),
|
|
461
|
+
self.objtype,
|
|
462
|
+
self.name,
|
|
463
|
+
type='autodoc',
|
|
464
|
+
)
|
|
410
465
|
return False
|
|
411
466
|
explicit_modname, path, base, tp_list, args, retann = matched.groups()
|
|
412
467
|
|
|
@@ -427,8 +482,7 @@ class Documenter:
|
|
|
427
482
|
self.modname = modname
|
|
428
483
|
self.args = args
|
|
429
484
|
self.retann = retann
|
|
430
|
-
self.fullname = ((self.modname or '')
|
|
431
|
-
('.' + '.'.join(self.objpath) if self.objpath else ''))
|
|
485
|
+
self.fullname = '.'.join((self.modname or '', *self.objpath))
|
|
432
486
|
return True
|
|
433
487
|
|
|
434
488
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -440,8 +494,7 @@ class Documenter:
|
|
|
440
494
|
with mock(self.config.autodoc_mock_imports):
|
|
441
495
|
try:
|
|
442
496
|
ret = import_object(
|
|
443
|
-
self.modname, self.objpath, self.objtype,
|
|
444
|
-
attrgetter=self.get_attr,
|
|
497
|
+
self.modname, self.objpath, self.objtype, attrgetter=self.get_attr
|
|
445
498
|
)
|
|
446
499
|
self.module, self.parent, self.object_name, self.object = ret
|
|
447
500
|
if ismock(self.object):
|
|
@@ -509,7 +562,7 @@ class Documenter:
|
|
|
509
562
|
"""
|
|
510
563
|
if self.args is not None:
|
|
511
564
|
# signature given explicitly
|
|
512
|
-
args =
|
|
565
|
+
args = f'({self.args})'
|
|
513
566
|
retann = self.retann
|
|
514
567
|
else:
|
|
515
568
|
# try to introspect the signature
|
|
@@ -522,13 +575,23 @@ class Documenter:
|
|
|
522
575
|
args = matched.group(1)
|
|
523
576
|
retann = matched.group(2)
|
|
524
577
|
except Exception as exc:
|
|
525
|
-
logger.warning(
|
|
526
|
-
|
|
578
|
+
logger.warning(
|
|
579
|
+
__('error while formatting arguments for %s: %s'),
|
|
580
|
+
self.fullname,
|
|
581
|
+
exc,
|
|
582
|
+
type='autodoc',
|
|
583
|
+
)
|
|
527
584
|
args = None
|
|
528
585
|
|
|
529
|
-
result = self.
|
|
530
|
-
|
|
531
|
-
|
|
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
|
+
)
|
|
532
595
|
if result:
|
|
533
596
|
args, retann = result
|
|
534
597
|
|
|
@@ -546,14 +609,15 @@ class Documenter:
|
|
|
546
609
|
|
|
547
610
|
# one signature per line, indented by column
|
|
548
611
|
prefix = f'.. {domain}:{directive}:: '
|
|
549
|
-
for i, sig_line in enumerate(sig.split(
|
|
550
|
-
self.add_line(f'{prefix}{name}{sig_line}',
|
|
551
|
-
sourcename)
|
|
612
|
+
for i, sig_line in enumerate(sig.split('\n')):
|
|
613
|
+
self.add_line(f'{prefix}{name}{sig_line}', sourcename)
|
|
552
614
|
if i == 0:
|
|
553
|
-
prefix =
|
|
615
|
+
prefix = ' ' * len(prefix)
|
|
554
616
|
|
|
555
617
|
if self.options.no_index or self.options.noindex:
|
|
556
618
|
self.add_line(' :no-index:', sourcename)
|
|
619
|
+
if self.options.no_index_entry:
|
|
620
|
+
self.add_line(' :no-index-entry:', sourcename)
|
|
557
621
|
if self.objpath:
|
|
558
622
|
# Be explicit about the module, this is necessary since .. class::
|
|
559
623
|
# etc. don't support a prepended module name
|
|
@@ -565,8 +629,13 @@ class Documenter:
|
|
|
565
629
|
When it returns None, autodoc-process-docstring will not be called for this
|
|
566
630
|
object.
|
|
567
631
|
"""
|
|
568
|
-
docstring = getdoc(
|
|
569
|
-
|
|
632
|
+
docstring = getdoc(
|
|
633
|
+
self.object,
|
|
634
|
+
self.get_attr,
|
|
635
|
+
self.config.autodoc_inherit_docstrings,
|
|
636
|
+
self.parent,
|
|
637
|
+
self.object_name,
|
|
638
|
+
)
|
|
570
639
|
if docstring:
|
|
571
640
|
tab_width = self.directive.state.document.settings.tab_width
|
|
572
641
|
return [prepare_docstring(docstring, tab_width)]
|
|
@@ -575,21 +644,27 @@ class Documenter:
|
|
|
575
644
|
def process_doc(self, docstrings: list[list[str]]) -> Iterator[str]:
|
|
576
645
|
"""Let the user process the docstrings before adding them."""
|
|
577
646
|
for docstringlines in docstrings:
|
|
578
|
-
if self.
|
|
647
|
+
if self._events is not None:
|
|
579
648
|
# let extensions preprocess docstrings
|
|
580
|
-
self.
|
|
581
|
-
|
|
582
|
-
|
|
649
|
+
self._events.emit(
|
|
650
|
+
'autodoc-process-docstring',
|
|
651
|
+
self.objtype,
|
|
652
|
+
self.fullname,
|
|
653
|
+
self.object,
|
|
654
|
+
self.options,
|
|
655
|
+
docstringlines,
|
|
656
|
+
)
|
|
583
657
|
|
|
584
|
-
if docstringlines and docstringlines[-1]
|
|
658
|
+
if docstringlines and docstringlines[-1]:
|
|
585
659
|
# append a blank line to the end of the docstring
|
|
586
660
|
docstringlines.append('')
|
|
587
661
|
|
|
588
662
|
yield from docstringlines
|
|
589
663
|
|
|
590
664
|
def get_sourcename(self) -> str:
|
|
591
|
-
|
|
592
|
-
|
|
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:
|
|
593
668
|
# Get the correct location of docstring from self.object
|
|
594
669
|
# to support inherited methods
|
|
595
670
|
fullname = f'{self.object.__module__}.{self.object.__qualname__}'
|
|
@@ -650,8 +725,9 @@ class Documenter:
|
|
|
650
725
|
msg = 'must be implemented in subclasses'
|
|
651
726
|
raise NotImplementedError(msg)
|
|
652
727
|
|
|
653
|
-
def filter_members(
|
|
654
|
-
|
|
728
|
+
def filter_members(
|
|
729
|
+
self, members: list[ObjectMember], want_all: bool
|
|
730
|
+
) -> list[tuple[str, Any, bool]]:
|
|
655
731
|
"""Filter the given member list.
|
|
656
732
|
|
|
657
733
|
Members are skipped if
|
|
@@ -665,12 +741,22 @@ class Documenter:
|
|
|
665
741
|
The user can override the skipping decision by connecting to the
|
|
666
742
|
``autodoc-skip-member`` event.
|
|
667
743
|
"""
|
|
744
|
+
|
|
668
745
|
def is_filtered_inherited_member(name: str, obj: Any) -> bool:
|
|
669
746
|
inherited_members = self.options.inherited_members or set()
|
|
747
|
+
seen = set()
|
|
670
748
|
|
|
671
749
|
if inspect.isclass(self.object):
|
|
672
750
|
for cls in self.object.__mro__:
|
|
673
|
-
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
|
+
):
|
|
674
760
|
# given member is a member of specified *super class*
|
|
675
761
|
return True
|
|
676
762
|
if name in cls.__dict__:
|
|
@@ -701,8 +787,13 @@ class Documenter:
|
|
|
701
787
|
isattr = member is INSTANCEATTR or (namespace, membername) in attr_docs
|
|
702
788
|
|
|
703
789
|
try:
|
|
704
|
-
doc = getdoc(
|
|
705
|
-
|
|
790
|
+
doc = getdoc(
|
|
791
|
+
member,
|
|
792
|
+
self.get_attr,
|
|
793
|
+
self.config.autodoc_inherit_docstrings,
|
|
794
|
+
self.object,
|
|
795
|
+
membername,
|
|
796
|
+
)
|
|
706
797
|
if not isinstance(doc, str):
|
|
707
798
|
# Ignore non-string __doc__
|
|
708
799
|
doc = None
|
|
@@ -735,14 +826,18 @@ class Documenter:
|
|
|
735
826
|
if ismock(member) and (namespace, membername) not in attr_docs:
|
|
736
827
|
# mocked module or object
|
|
737
828
|
pass
|
|
738
|
-
elif (
|
|
739
|
-
|
|
829
|
+
elif (
|
|
830
|
+
self.options.exclude_members
|
|
831
|
+
and membername in self.options.exclude_members
|
|
832
|
+
):
|
|
740
833
|
# remove members given by exclude-members
|
|
741
834
|
keep = False
|
|
742
835
|
elif want_all and special_member_re.match(membername):
|
|
743
836
|
# special __methods__
|
|
744
|
-
if (
|
|
745
|
-
|
|
837
|
+
if (
|
|
838
|
+
self.options.special_members
|
|
839
|
+
and membername in self.options.special_members
|
|
840
|
+
):
|
|
746
841
|
if membername == '__doc__': # NoQA: SIM114
|
|
747
842
|
keep = False
|
|
748
843
|
elif is_filtered_inherited_member(membername, obj):
|
|
@@ -771,8 +866,9 @@ class Documenter:
|
|
|
771
866
|
else:
|
|
772
867
|
keep = False
|
|
773
868
|
else:
|
|
774
|
-
if
|
|
775
|
-
|
|
869
|
+
if self.options.members is ALL and is_filtered_inherited_member(
|
|
870
|
+
membername, obj
|
|
871
|
+
):
|
|
776
872
|
keep = False
|
|
777
873
|
else:
|
|
778
874
|
# ignore undocumented members if :undoc-members: is not given
|
|
@@ -784,17 +880,30 @@ class Documenter:
|
|
|
784
880
|
|
|
785
881
|
# give the user a chance to decide whether this member
|
|
786
882
|
# should be skipped
|
|
787
|
-
if self.
|
|
883
|
+
if self._events is not None:
|
|
788
884
|
# let extensions preprocess docstrings
|
|
789
|
-
skip_user = self.
|
|
790
|
-
'autodoc-skip-member',
|
|
791
|
-
|
|
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
|
+
)
|
|
792
893
|
if skip_user is not None:
|
|
793
894
|
keep = not skip_user
|
|
794
895
|
except Exception as exc:
|
|
795
|
-
logger.warning(
|
|
796
|
-
|
|
797
|
-
|
|
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
|
+
)
|
|
798
907
|
keep = False
|
|
799
908
|
|
|
800
909
|
if keep:
|
|
@@ -809,21 +918,24 @@ class Documenter:
|
|
|
809
918
|
*self.options.members*.
|
|
810
919
|
"""
|
|
811
920
|
# set current namespace for finding members
|
|
812
|
-
self.
|
|
921
|
+
self._current_document.autodoc_module = self.modname
|
|
813
922
|
if self.objpath:
|
|
814
|
-
self.
|
|
923
|
+
self._current_document.autodoc_class = self.objpath[0]
|
|
815
924
|
|
|
816
|
-
want_all = (
|
|
817
|
-
|
|
818
|
-
|
|
925
|
+
want_all = (
|
|
926
|
+
all_members or self.options.inherited_members or self.options.members is ALL
|
|
927
|
+
)
|
|
819
928
|
# find out which members are documentable
|
|
820
929
|
members_check_module, members = self.get_object_members(want_all)
|
|
821
930
|
|
|
822
931
|
# document non-skipped members
|
|
823
|
-
|
|
824
|
-
for
|
|
825
|
-
classes = [
|
|
826
|
-
|
|
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
|
+
]
|
|
827
939
|
if not classes:
|
|
828
940
|
# don't know how to document this member
|
|
829
941
|
continue
|
|
@@ -833,22 +945,39 @@ class Documenter:
|
|
|
833
945
|
# of inner classes can be documented
|
|
834
946
|
full_mname = f'{self.modname}::' + '.'.join((*self.objpath, mname))
|
|
835
947
|
documenter = classes[-1](self.directive, full_mname, self.indent)
|
|
836
|
-
|
|
948
|
+
member_documenters.append((documenter, isattr))
|
|
837
949
|
|
|
838
950
|
member_order = self.options.member_order or self.config.autodoc_member_order
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
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
|
+
)
|
|
845
973
|
|
|
846
974
|
# reset current objects
|
|
847
|
-
self.
|
|
848
|
-
self.
|
|
975
|
+
self._current_document.autodoc_module = ''
|
|
976
|
+
self._current_document.autodoc_class = ''
|
|
849
977
|
|
|
850
|
-
def sort_members(
|
|
851
|
-
|
|
978
|
+
def sort_members(
|
|
979
|
+
self, documenters: list[tuple[Documenter, bool]], order: str
|
|
980
|
+
) -> list[tuple[Documenter, bool]]:
|
|
852
981
|
"""Sort the given member list."""
|
|
853
982
|
if order == 'groupwise':
|
|
854
983
|
# sort by group; alphabetically within groups
|
|
@@ -863,6 +992,7 @@ class Documenter:
|
|
|
863
992
|
def keyfunc(entry: tuple[Documenter, bool]) -> int:
|
|
864
993
|
fullname = entry[0].name.split('::')[1]
|
|
865
994
|
return tagorder.get(fullname, len(tagorder))
|
|
995
|
+
|
|
866
996
|
documenters.sort(key=keyfunc)
|
|
867
997
|
else: # alphabetical
|
|
868
998
|
documenters.sort(key=lambda e: e[0].name)
|
|
@@ -887,16 +1017,29 @@ class Documenter:
|
|
|
887
1017
|
if not self.parse_name():
|
|
888
1018
|
# need a module to import
|
|
889
1019
|
logger.warning(
|
|
890
|
-
__(
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
)
|
|
894
1028
|
return
|
|
895
1029
|
|
|
896
1030
|
# now, import the module and get object to document
|
|
897
1031
|
if not self.import_object():
|
|
898
1032
|
return
|
|
899
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:
|
|
900
1043
|
# If there is no real module defined, figure out which to use.
|
|
901
1044
|
# The real module is used in the module analyzer to look up the module
|
|
902
1045
|
# where the attribute documentation would actually be found in.
|
|
@@ -929,10 +1072,16 @@ class Documenter:
|
|
|
929
1072
|
except PycodeError:
|
|
930
1073
|
pass
|
|
931
1074
|
|
|
932
|
-
docstrings: list[str] = functools.reduce(
|
|
1075
|
+
docstrings: list[str] = functools.reduce(
|
|
1076
|
+
operator.iadd, self.get_doc() or [], []
|
|
1077
|
+
)
|
|
933
1078
|
if ismock(self.object) and not docstrings:
|
|
934
|
-
logger.warning(
|
|
935
|
-
|
|
1079
|
+
logger.warning(
|
|
1080
|
+
__('A mocked object is detected: %r'),
|
|
1081
|
+
self.name,
|
|
1082
|
+
type='autodoc',
|
|
1083
|
+
subtype='mocked_object',
|
|
1084
|
+
)
|
|
936
1085
|
|
|
937
1086
|
# check __module__ of object (for members not given explicitly)
|
|
938
1087
|
if check_module:
|
|
@@ -950,8 +1099,12 @@ class Documenter:
|
|
|
950
1099
|
try:
|
|
951
1100
|
sig = self.format_signature()
|
|
952
1101
|
except Exception as exc:
|
|
953
|
-
logger.warning(
|
|
954
|
-
|
|
1102
|
+
logger.warning(
|
|
1103
|
+
__('error while formatting signature for %s: %s'),
|
|
1104
|
+
self.fullname,
|
|
1105
|
+
exc,
|
|
1106
|
+
type='autodoc',
|
|
1107
|
+
)
|
|
955
1108
|
return
|
|
956
1109
|
|
|
957
1110
|
# generate the directive header and options, if applicable
|
|
@@ -969,22 +1122,28 @@ class Documenter:
|
|
|
969
1122
|
|
|
970
1123
|
|
|
971
1124
|
class ModuleDocumenter(Documenter):
|
|
972
|
-
"""
|
|
973
|
-
Specialized Documenter subclass for modules.
|
|
974
|
-
"""
|
|
1125
|
+
"""Specialized Documenter subclass for modules."""
|
|
975
1126
|
|
|
976
1127
|
objtype = 'module'
|
|
977
1128
|
content_indent = ''
|
|
978
1129
|
_extra_indent = ' '
|
|
979
1130
|
|
|
980
1131
|
option_spec: ClassVar[OptionSpec] = {
|
|
981
|
-
'members': members_option,
|
|
982
|
-
'
|
|
983
|
-
'
|
|
984
|
-
'
|
|
985
|
-
'
|
|
986
|
-
'
|
|
987
|
-
'
|
|
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,
|
|
988
1147
|
'no-value': bool_option,
|
|
989
1148
|
'noindex': bool_option,
|
|
990
1149
|
}
|
|
@@ -1005,24 +1164,28 @@ class ModuleDocumenter(Documenter):
|
|
|
1005
1164
|
|
|
1006
1165
|
@classmethod
|
|
1007
1166
|
def can_document_member(
|
|
1008
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1167
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1009
1168
|
) -> bool:
|
|
1010
1169
|
# don't document submodules automatically
|
|
1011
1170
|
return False
|
|
1012
1171
|
|
|
1013
|
-
def resolve_name(
|
|
1014
|
-
|
|
1172
|
+
def resolve_name(
|
|
1173
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1174
|
+
) -> tuple[str | None, list[str]]:
|
|
1015
1175
|
if modname is not None:
|
|
1016
|
-
logger.warning(
|
|
1017
|
-
|
|
1176
|
+
logger.warning(
|
|
1177
|
+
__('"::" in automodule name doesn\'t make sense'), type='autodoc'
|
|
1178
|
+
)
|
|
1018
1179
|
return (path or '') + base, []
|
|
1019
1180
|
|
|
1020
1181
|
def parse_name(self) -> bool:
|
|
1021
1182
|
ret = super().parse_name()
|
|
1022
1183
|
if self.args or self.retann:
|
|
1023
|
-
logger.warning(
|
|
1024
|
-
|
|
1025
|
-
|
|
1184
|
+
logger.warning(
|
|
1185
|
+
__('signature arguments or return annotation given for automodule %s'),
|
|
1186
|
+
self.fullname,
|
|
1187
|
+
type='autodoc',
|
|
1188
|
+
)
|
|
1026
1189
|
return ret
|
|
1027
1190
|
|
|
1028
1191
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -1033,9 +1196,15 @@ class ModuleDocumenter(Documenter):
|
|
|
1033
1196
|
self.__all__ = inspect.getall(self.object)
|
|
1034
1197
|
except ValueError as exc:
|
|
1035
1198
|
# invalid __all__ found.
|
|
1036
|
-
logger.warning(
|
|
1037
|
-
|
|
1038
|
-
|
|
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
|
+
)
|
|
1039
1208
|
|
|
1040
1209
|
return ret
|
|
1041
1210
|
|
|
@@ -1051,6 +1220,8 @@ class ModuleDocumenter(Documenter):
|
|
|
1051
1220
|
self.add_line(' :platform: ' + self.options.platform, sourcename)
|
|
1052
1221
|
if self.options.deprecated:
|
|
1053
1222
|
self.add_line(' :deprecated:', sourcename)
|
|
1223
|
+
if self.options.no_index_entry:
|
|
1224
|
+
self.add_line(' :no-index-entry:', sourcename)
|
|
1054
1225
|
|
|
1055
1226
|
def get_module_members(self) -> dict[str, ObjectMember]:
|
|
1056
1227
|
"""Get members of target module."""
|
|
@@ -1066,7 +1237,9 @@ class ModuleDocumenter(Documenter):
|
|
|
1066
1237
|
if ismock(value):
|
|
1067
1238
|
value = undecorate(value)
|
|
1068
1239
|
docstring = attr_docs.get(('', name), [])
|
|
1069
|
-
members[name] = ObjectMember(
|
|
1240
|
+
members[name] = ObjectMember(
|
|
1241
|
+
name, value, docstring='\n'.join(docstring)
|
|
1242
|
+
)
|
|
1070
1243
|
except AttributeError:
|
|
1071
1244
|
continue
|
|
1072
1245
|
|
|
@@ -1074,8 +1247,9 @@ class ModuleDocumenter(Documenter):
|
|
|
1074
1247
|
for name in inspect.getannotations(self.object):
|
|
1075
1248
|
if name not in members:
|
|
1076
1249
|
docstring = attr_docs.get(('', name), [])
|
|
1077
|
-
members[name] = ObjectMember(
|
|
1078
|
-
|
|
1250
|
+
members[name] = ObjectMember(
|
|
1251
|
+
name, INSTANCEATTR, docstring='\n'.join(docstring)
|
|
1252
|
+
)
|
|
1079
1253
|
|
|
1080
1254
|
return members
|
|
1081
1255
|
|
|
@@ -1099,15 +1273,20 @@ class ModuleDocumenter(Documenter):
|
|
|
1099
1273
|
if name in members:
|
|
1100
1274
|
ret.append(members[name])
|
|
1101
1275
|
else:
|
|
1102
|
-
logger.warning(
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
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
|
+
)
|
|
1107
1285
|
return False, ret
|
|
1108
1286
|
|
|
1109
|
-
def sort_members(
|
|
1110
|
-
|
|
1287
|
+
def sort_members(
|
|
1288
|
+
self, documenters: list[tuple[Documenter, bool]], order: str
|
|
1289
|
+
) -> list[tuple[Documenter, bool]]:
|
|
1111
1290
|
if order == 'bysource' and self.__all__:
|
|
1112
1291
|
assert self.__all__ is not None
|
|
1113
1292
|
module_all = self.__all__
|
|
@@ -1124,6 +1303,7 @@ class ModuleDocumenter(Documenter):
|
|
|
1124
1303
|
return module_all.index(name)
|
|
1125
1304
|
else:
|
|
1126
1305
|
return module_all_len
|
|
1306
|
+
|
|
1127
1307
|
documenters.sort(key=keyfunc)
|
|
1128
1308
|
|
|
1129
1309
|
return documenters
|
|
@@ -1132,13 +1312,13 @@ class ModuleDocumenter(Documenter):
|
|
|
1132
1312
|
|
|
1133
1313
|
|
|
1134
1314
|
class ModuleLevelDocumenter(Documenter):
|
|
1135
|
-
"""
|
|
1136
|
-
Specialized Documenter subclass for objects on module level (functions,
|
|
1315
|
+
"""Specialized Documenter subclass for objects on module level (functions,
|
|
1137
1316
|
classes, data/constants).
|
|
1138
1317
|
"""
|
|
1139
1318
|
|
|
1140
|
-
def resolve_name(
|
|
1141
|
-
|
|
1319
|
+
def resolve_name(
|
|
1320
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1321
|
+
) -> tuple[str | None, list[str]]:
|
|
1142
1322
|
if modname is not None:
|
|
1143
1323
|
return modname, [*parents, base]
|
|
1144
1324
|
if path:
|
|
@@ -1147,7 +1327,7 @@ class ModuleLevelDocumenter(Documenter):
|
|
|
1147
1327
|
|
|
1148
1328
|
# if documenting a toplevel object without explicit module,
|
|
1149
1329
|
# it can be contained in another auto directive ...
|
|
1150
|
-
modname = self.
|
|
1330
|
+
modname = self._current_document.autodoc_module
|
|
1151
1331
|
# ... or in the scope of a module directive
|
|
1152
1332
|
if not modname:
|
|
1153
1333
|
modname = self.env.ref_context.get('py:module')
|
|
@@ -1156,13 +1336,13 @@ class ModuleLevelDocumenter(Documenter):
|
|
|
1156
1336
|
|
|
1157
1337
|
|
|
1158
1338
|
class ClassLevelDocumenter(Documenter):
|
|
1159
|
-
"""
|
|
1160
|
-
Specialized Documenter subclass for objects on class level (methods,
|
|
1339
|
+
"""Specialized Documenter subclass for objects on class level (methods,
|
|
1161
1340
|
attributes).
|
|
1162
1341
|
"""
|
|
1163
1342
|
|
|
1164
|
-
def resolve_name(
|
|
1165
|
-
|
|
1343
|
+
def resolve_name(
|
|
1344
|
+
self, modname: str | None, parents: Any, path: str, base: str
|
|
1345
|
+
) -> tuple[str | None, list[str]]:
|
|
1166
1346
|
if modname is not None:
|
|
1167
1347
|
return modname, [*parents, base]
|
|
1168
1348
|
|
|
@@ -1172,19 +1352,18 @@ class ClassLevelDocumenter(Documenter):
|
|
|
1172
1352
|
# if documenting a class-level object without path,
|
|
1173
1353
|
# there must be a current class, either from a parent
|
|
1174
1354
|
# auto directive ...
|
|
1175
|
-
|
|
1355
|
+
mod_cls = self._current_document.autodoc_class
|
|
1176
1356
|
# ... or from a class directive
|
|
1177
|
-
if
|
|
1178
|
-
|
|
1179
|
-
# ... if still
|
|
1180
|
-
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:
|
|
1181
1361
|
return None, []
|
|
1182
|
-
mod_cls = mod_cls_
|
|
1183
1362
|
modname, sep, cls = mod_cls.rpartition('.')
|
|
1184
1363
|
parents = [cls]
|
|
1185
1364
|
# if the module name is still missing, get it like above
|
|
1186
1365
|
if not modname:
|
|
1187
|
-
modname = self.
|
|
1366
|
+
modname = self._current_document.autodoc_module
|
|
1188
1367
|
if not modname:
|
|
1189
1368
|
modname = self.env.ref_context.get('py:module')
|
|
1190
1369
|
# ... else, it stays None, which means invalid
|
|
@@ -1192,8 +1371,7 @@ class ClassLevelDocumenter(Documenter):
|
|
|
1192
1371
|
|
|
1193
1372
|
|
|
1194
1373
|
class DocstringSignatureMixin:
|
|
1195
|
-
"""
|
|
1196
|
-
Mixin for FunctionDocumenter and MethodDocumenter to provide the
|
|
1374
|
+
"""Mixin for FunctionDocumenter and MethodDocumenter to provide the
|
|
1197
1375
|
feature of reading the signature from the docstring.
|
|
1198
1376
|
"""
|
|
1199
1377
|
|
|
@@ -1236,15 +1414,16 @@ class DocstringSignatureMixin:
|
|
|
1236
1414
|
# re-prepare docstring to ignore more leading indentation
|
|
1237
1415
|
directive = self.directive # type: ignore[attr-defined]
|
|
1238
1416
|
tab_width = directive.state.document.settings.tab_width
|
|
1239
|
-
self._new_docstrings[i] = prepare_docstring(
|
|
1240
|
-
|
|
1417
|
+
self._new_docstrings[i] = prepare_docstring(
|
|
1418
|
+
'\n'.join(doclines[j + 1 :]), tab_width
|
|
1419
|
+
)
|
|
1241
1420
|
|
|
1242
1421
|
if result is None:
|
|
1243
1422
|
# first signature
|
|
1244
1423
|
result = args, retann
|
|
1245
1424
|
else:
|
|
1246
1425
|
# subsequent signatures
|
|
1247
|
-
self._signatures.append(f
|
|
1426
|
+
self._signatures.append(f'({args}) -> {retann}')
|
|
1248
1427
|
|
|
1249
1428
|
if result is not None:
|
|
1250
1429
|
# finish the loop when signature found
|
|
@@ -1259,8 +1438,7 @@ class DocstringSignatureMixin:
|
|
|
1259
1438
|
|
|
1260
1439
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1261
1440
|
self.args: str | None
|
|
1262
|
-
if
|
|
1263
|
-
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]
|
|
1264
1442
|
# only act if a signature is not explicitly given already, and if
|
|
1265
1443
|
# the feature is enabled
|
|
1266
1444
|
result = self._find_signature()
|
|
@@ -1268,22 +1446,18 @@ class DocstringSignatureMixin:
|
|
|
1268
1446
|
self.args, self.retann = result
|
|
1269
1447
|
sig = super().format_signature(**kwargs) # type: ignore[misc]
|
|
1270
1448
|
if self._signatures:
|
|
1271
|
-
return
|
|
1449
|
+
return '\n'.join((sig, *self._signatures))
|
|
1272
1450
|
else:
|
|
1273
1451
|
return sig
|
|
1274
1452
|
|
|
1275
1453
|
|
|
1276
1454
|
class DocstringStripSignatureMixin(DocstringSignatureMixin):
|
|
1277
|
-
"""
|
|
1278
|
-
Mixin for AttributeDocumenter to provide the
|
|
1455
|
+
"""Mixin for AttributeDocumenter to provide the
|
|
1279
1456
|
feature of stripping any function signature from the docstring.
|
|
1280
1457
|
"""
|
|
1281
1458
|
|
|
1282
1459
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1283
|
-
if
|
|
1284
|
-
self.args is None
|
|
1285
|
-
and self.config.autodoc_docstring_signature # type: ignore[attr-defined]
|
|
1286
|
-
):
|
|
1460
|
+
if self.args is None and self.config.autodoc_docstring_signature: # type: ignore[attr-defined]
|
|
1287
1461
|
# only act if a signature is not explicitly given already, and if
|
|
1288
1462
|
# the feature is enabled
|
|
1289
1463
|
result = self._find_signature()
|
|
@@ -1296,34 +1470,40 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin):
|
|
|
1296
1470
|
|
|
1297
1471
|
|
|
1298
1472
|
class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc]
|
|
1299
|
-
"""
|
|
1300
|
-
Specialized Documenter subclass for functions.
|
|
1301
|
-
"""
|
|
1473
|
+
"""Specialized Documenter subclass for functions."""
|
|
1302
1474
|
|
|
1303
1475
|
objtype = 'function'
|
|
1304
1476
|
member_order = 30
|
|
1305
1477
|
|
|
1306
1478
|
@classmethod
|
|
1307
1479
|
def can_document_member(
|
|
1308
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1480
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1309
1481
|
) -> bool:
|
|
1310
1482
|
# supports functions, builtins and bound methods exported at the module level
|
|
1311
|
-
return (
|
|
1312
|
-
|
|
1483
|
+
return (
|
|
1484
|
+
inspect.isfunction(member)
|
|
1485
|
+
or inspect.isbuiltin(member)
|
|
1486
|
+
or (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))
|
|
1487
|
+
)
|
|
1313
1488
|
|
|
1314
1489
|
def format_args(self, **kwargs: Any) -> str:
|
|
1315
|
-
if self.config.autodoc_typehints in
|
|
1490
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
1316
1491
|
kwargs.setdefault('show_annotation', False)
|
|
1317
|
-
if self.config.autodoc_typehints_format ==
|
|
1492
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1318
1493
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1494
|
+
if self.config.python_display_short_literal_types:
|
|
1495
|
+
kwargs.setdefault('short_literals', True)
|
|
1319
1496
|
|
|
1320
1497
|
try:
|
|
1321
|
-
self.
|
|
1322
|
-
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
|
+
)
|
|
1323
1502
|
args = stringify_signature(sig, **kwargs)
|
|
1324
1503
|
except TypeError as exc:
|
|
1325
|
-
logger.warning(
|
|
1326
|
-
|
|
1504
|
+
logger.warning(
|
|
1505
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
1506
|
+
)
|
|
1327
1507
|
return ''
|
|
1328
1508
|
except ValueError:
|
|
1329
1509
|
args = ''
|
|
@@ -1340,17 +1520,23 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1340
1520
|
sourcename = self.get_sourcename()
|
|
1341
1521
|
super().add_directive_header(sig)
|
|
1342
1522
|
|
|
1343
|
-
|
|
1523
|
+
is_coro = inspect.iscoroutinefunction(self.object)
|
|
1524
|
+
is_acoro = inspect.isasyncgenfunction(self.object)
|
|
1525
|
+
if is_coro or is_acoro:
|
|
1344
1526
|
self.add_line(' :async:', sourcename)
|
|
1345
1527
|
|
|
1346
1528
|
def format_signature(self, **kwargs: Any) -> str:
|
|
1347
|
-
if self.config.autodoc_typehints_format ==
|
|
1529
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1348
1530
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1531
|
+
if self.config.python_display_short_literal_types:
|
|
1532
|
+
kwargs.setdefault('short_literals', True)
|
|
1349
1533
|
|
|
1350
1534
|
sigs = []
|
|
1351
|
-
if (
|
|
1352
|
-
|
|
1353
|
-
|
|
1535
|
+
if (
|
|
1536
|
+
self.analyzer
|
|
1537
|
+
and '.'.join(self.objpath) in self.analyzer.overloads
|
|
1538
|
+
and self.config.autodoc_typehints != 'none'
|
|
1539
|
+
):
|
|
1354
1540
|
# Use signatures for overloaded functions instead of the implementation function.
|
|
1355
1541
|
overloaded = True
|
|
1356
1542
|
else:
|
|
@@ -1371,18 +1557,20 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1371
1557
|
documenter.objpath = ['']
|
|
1372
1558
|
sigs.append(documenter.format_signature())
|
|
1373
1559
|
if overloaded and self.analyzer is not None:
|
|
1374
|
-
actual = inspect.signature(
|
|
1375
|
-
|
|
1560
|
+
actual = inspect.signature(
|
|
1561
|
+
self.object, type_aliases=self.config.autodoc_type_aliases
|
|
1562
|
+
)
|
|
1376
1563
|
__globals__ = safe_getattr(self.object, '__globals__', {})
|
|
1377
1564
|
for overload in self.analyzer.overloads['.'.join(self.objpath)]:
|
|
1378
1565
|
overload = self.merge_default_value(actual, overload)
|
|
1379
|
-
overload = evaluate_signature(
|
|
1380
|
-
|
|
1566
|
+
overload = evaluate_signature(
|
|
1567
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
1568
|
+
)
|
|
1381
1569
|
|
|
1382
1570
|
sig = stringify_signature(overload, **kwargs)
|
|
1383
1571
|
sigs.append(sig)
|
|
1384
1572
|
|
|
1385
|
-
return
|
|
1573
|
+
return '\n'.join(sigs)
|
|
1386
1574
|
|
|
1387
1575
|
def merge_default_value(self, actual: Signature, overload: Signature) -> Signature:
|
|
1388
1576
|
"""Merge default values of actual implementation to the overload variants."""
|
|
@@ -1394,13 +1582,16 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1394
1582
|
|
|
1395
1583
|
return overload.replace(parameters=parameters)
|
|
1396
1584
|
|
|
1397
|
-
def annotate_to_first_argument(
|
|
1585
|
+
def annotate_to_first_argument(
|
|
1586
|
+
self, func: Callable[..., Any], typ: type
|
|
1587
|
+
) -> Callable[..., Any] | None:
|
|
1398
1588
|
"""Annotate type hint to the first argument of function if needed."""
|
|
1399
1589
|
try:
|
|
1400
1590
|
sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
|
|
1401
1591
|
except TypeError as exc:
|
|
1402
|
-
logger.warning(
|
|
1403
|
-
|
|
1592
|
+
logger.warning(
|
|
1593
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
1594
|
+
)
|
|
1404
1595
|
return None
|
|
1405
1596
|
except ValueError:
|
|
1406
1597
|
return None
|
|
@@ -1415,8 +1606,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1415
1606
|
if params[0].annotation is Parameter.empty:
|
|
1416
1607
|
params[0] = params[0].replace(annotation=typ)
|
|
1417
1608
|
try:
|
|
1418
|
-
dummy.__signature__ = sig.replace( # type: ignore[attr-defined]
|
|
1419
|
-
parameters=params)
|
|
1609
|
+
dummy.__signature__ = sig.replace(parameters=params) # type: ignore[attr-defined]
|
|
1420
1610
|
return dummy
|
|
1421
1611
|
except (AttributeError, TypeError):
|
|
1422
1612
|
# failed to update signature (ex. built-in or extension types)
|
|
@@ -1426,9 +1616,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|
|
1426
1616
|
|
|
1427
1617
|
|
|
1428
1618
|
class DecoratorDocumenter(FunctionDocumenter):
|
|
1429
|
-
"""
|
|
1430
|
-
Specialized Documenter subclass for decorator functions.
|
|
1431
|
-
"""
|
|
1619
|
+
"""Specialized Documenter subclass for decorator functions."""
|
|
1432
1620
|
|
|
1433
1621
|
objtype = 'decorator'
|
|
1434
1622
|
|
|
@@ -1446,30 +1634,33 @@ class DecoratorDocumenter(FunctionDocumenter):
|
|
|
1446
1634
|
# Types which have confusing metaclass signatures it would be best not to show.
|
|
1447
1635
|
# These are listed by name, rather than storing the objects themselves, to avoid
|
|
1448
1636
|
# needing to import the modules.
|
|
1449
|
-
_METACLASS_CALL_BLACKLIST =
|
|
1450
|
-
'enum.
|
|
1451
|
-
|
|
1637
|
+
_METACLASS_CALL_BLACKLIST = frozenset({
|
|
1638
|
+
'enum.EnumType.__call__',
|
|
1639
|
+
})
|
|
1452
1640
|
|
|
1453
1641
|
|
|
1454
1642
|
# Types whose __new__ signature is a pass-through.
|
|
1455
|
-
_CLASS_NEW_BLACKLIST =
|
|
1643
|
+
_CLASS_NEW_BLACKLIST = frozenset({
|
|
1456
1644
|
'typing.Generic.__new__',
|
|
1457
|
-
|
|
1645
|
+
})
|
|
1458
1646
|
|
|
1459
1647
|
|
|
1460
1648
|
class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc]
|
|
1461
|
-
"""
|
|
1462
|
-
Specialized Documenter subclass for classes.
|
|
1463
|
-
"""
|
|
1649
|
+
"""Specialized Documenter subclass for classes."""
|
|
1464
1650
|
|
|
1465
1651
|
objtype = 'class'
|
|
1466
1652
|
member_order = 20
|
|
1467
1653
|
option_spec: ClassVar[OptionSpec] = {
|
|
1468
|
-
'members': members_option,
|
|
1469
|
-
'
|
|
1470
|
-
'
|
|
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,
|
|
1471
1661
|
'exclude-members': exclude_members_option,
|
|
1472
|
-
'private-members': members_option,
|
|
1662
|
+
'private-members': members_option,
|
|
1663
|
+
'special-members': members_option,
|
|
1473
1664
|
'class-doc-from': class_doc_from_option,
|
|
1474
1665
|
'noindex': bool_option,
|
|
1475
1666
|
}
|
|
@@ -1499,10 +1690,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1499
1690
|
|
|
1500
1691
|
@classmethod
|
|
1501
1692
|
def can_document_member(
|
|
1502
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1693
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1503
1694
|
) -> bool:
|
|
1504
1695
|
return isinstance(member, type) or (
|
|
1505
|
-
isattr and isinstance(member, NewType | TypeVar)
|
|
1696
|
+
isattr and isinstance(member, NewType | TypeVar)
|
|
1697
|
+
)
|
|
1506
1698
|
|
|
1507
1699
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
1508
1700
|
ret = super().import_object(raiseerror)
|
|
@@ -1510,13 +1702,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1510
1702
|
# as data/attribute
|
|
1511
1703
|
if ret:
|
|
1512
1704
|
if hasattr(self.object, '__name__'):
|
|
1513
|
-
self.doc_as_attr =
|
|
1705
|
+
self.doc_as_attr = self.objpath[-1] != self.object.__name__
|
|
1514
1706
|
else:
|
|
1515
1707
|
self.doc_as_attr = True
|
|
1516
1708
|
if isinstance(self.object, NewType | TypeVar):
|
|
1517
1709
|
modname = getattr(self.object, '__module__', self.modname)
|
|
1518
1710
|
if modname != self.modname and self.modname.startswith(modname):
|
|
1519
|
-
bases = self.modname[len(modname):].strip('.').split('.')
|
|
1711
|
+
bases = self.modname[len(modname) :].strip('.').split('.')
|
|
1520
1712
|
self.objpath = bases + self.objpath
|
|
1521
1713
|
self.modname = modname
|
|
1522
1714
|
return ret
|
|
@@ -1538,24 +1730,32 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1538
1730
|
# This sequence is copied from inspect._signature_from_callable.
|
|
1539
1731
|
# ValueError means that no signature could be found, so we keep going.
|
|
1540
1732
|
|
|
1541
|
-
# First, we check
|
|
1542
|
-
if
|
|
1543
|
-
|
|
1544
|
-
|
|
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)
|
|
1545
1742
|
|
|
1546
1743
|
# Next, let's see if it has an overloaded __call__ defined
|
|
1547
1744
|
# in its metaclass
|
|
1548
1745
|
call = get_user_defined_function_or_method(type(self.object), '__call__')
|
|
1549
1746
|
|
|
1550
1747
|
if call is not None:
|
|
1551
|
-
if f
|
|
1748
|
+
if f'{call.__module__}.{call.__qualname__}' in _METACLASS_CALL_BLACKLIST:
|
|
1552
1749
|
call = None
|
|
1553
1750
|
|
|
1554
1751
|
if call is not None:
|
|
1555
|
-
self.
|
|
1752
|
+
self._events.emit('autodoc-before-process-signature', call, True)
|
|
1556
1753
|
try:
|
|
1557
|
-
sig = inspect.signature(
|
|
1558
|
-
|
|
1754
|
+
sig = inspect.signature(
|
|
1755
|
+
call,
|
|
1756
|
+
bound_method=True,
|
|
1757
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1758
|
+
)
|
|
1559
1759
|
return type(self.object), '__call__', sig
|
|
1560
1760
|
except ValueError:
|
|
1561
1761
|
pass
|
|
@@ -1564,14 +1764,17 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1564
1764
|
new = get_user_defined_function_or_method(self.object, '__new__')
|
|
1565
1765
|
|
|
1566
1766
|
if new is not None:
|
|
1567
|
-
if f
|
|
1767
|
+
if f'{new.__module__}.{new.__qualname__}' in _CLASS_NEW_BLACKLIST:
|
|
1568
1768
|
new = None
|
|
1569
1769
|
|
|
1570
1770
|
if new is not None:
|
|
1571
|
-
self.
|
|
1771
|
+
self._events.emit('autodoc-before-process-signature', new, True)
|
|
1572
1772
|
try:
|
|
1573
|
-
sig = inspect.signature(
|
|
1574
|
-
|
|
1773
|
+
sig = inspect.signature(
|
|
1774
|
+
new,
|
|
1775
|
+
bound_method=True,
|
|
1776
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1777
|
+
)
|
|
1575
1778
|
return self.object, '__new__', sig
|
|
1576
1779
|
except ValueError:
|
|
1577
1780
|
pass
|
|
@@ -1579,10 +1782,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1579
1782
|
# Finally, we should have at least __init__ implemented
|
|
1580
1783
|
init = get_user_defined_function_or_method(self.object, '__init__')
|
|
1581
1784
|
if init is not None:
|
|
1582
|
-
self.
|
|
1785
|
+
self._events.emit('autodoc-before-process-signature', init, True)
|
|
1583
1786
|
try:
|
|
1584
|
-
sig = inspect.signature(
|
|
1585
|
-
|
|
1787
|
+
sig = inspect.signature(
|
|
1788
|
+
init,
|
|
1789
|
+
bound_method=True,
|
|
1790
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1791
|
+
)
|
|
1586
1792
|
return self.object, '__init__', sig
|
|
1587
1793
|
except ValueError:
|
|
1588
1794
|
pass
|
|
@@ -1591,10 +1797,13 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1591
1797
|
# handle it.
|
|
1592
1798
|
# We don't know the exact method that inspect.signature will read
|
|
1593
1799
|
# the signature from, so just pass the object itself to our hook.
|
|
1594
|
-
self.
|
|
1800
|
+
self._events.emit('autodoc-before-process-signature', self.object, False)
|
|
1595
1801
|
try:
|
|
1596
|
-
sig = inspect.signature(
|
|
1597
|
-
|
|
1802
|
+
sig = inspect.signature(
|
|
1803
|
+
self.object,
|
|
1804
|
+
bound_method=False,
|
|
1805
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
1806
|
+
)
|
|
1598
1807
|
return None, None, sig
|
|
1599
1808
|
except ValueError:
|
|
1600
1809
|
pass
|
|
@@ -1604,17 +1813,22 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1604
1813
|
return None, None, None
|
|
1605
1814
|
|
|
1606
1815
|
def format_args(self, **kwargs: Any) -> str:
|
|
1607
|
-
if self.config.autodoc_typehints in
|
|
1816
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
1608
1817
|
kwargs.setdefault('show_annotation', False)
|
|
1609
|
-
if self.config.autodoc_typehints_format ==
|
|
1818
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1610
1819
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1820
|
+
if self.config.python_display_short_literal_types:
|
|
1821
|
+
kwargs.setdefault('short_literals', True)
|
|
1611
1822
|
|
|
1612
1823
|
try:
|
|
1613
1824
|
self._signature_class, _signature_method_name, sig = self._get_signature()
|
|
1614
1825
|
except TypeError as exc:
|
|
1615
1826
|
# __signature__ attribute contained junk
|
|
1616
|
-
logger.warning(
|
|
1617
|
-
|
|
1827
|
+
logger.warning(
|
|
1828
|
+
__('Failed to get a constructor signature for %s: %s'),
|
|
1829
|
+
self.fullname,
|
|
1830
|
+
exc,
|
|
1831
|
+
)
|
|
1618
1832
|
return ''
|
|
1619
1833
|
self._signature_method_name = _signature_method_name or ''
|
|
1620
1834
|
|
|
@@ -1644,8 +1858,10 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1644
1858
|
# do not show signatures
|
|
1645
1859
|
return ''
|
|
1646
1860
|
|
|
1647
|
-
if self.config.autodoc_typehints_format ==
|
|
1861
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
1648
1862
|
kwargs.setdefault('unqualified_typehints', True)
|
|
1863
|
+
if self.config.python_display_short_literal_types:
|
|
1864
|
+
kwargs.setdefault('short_literals', True)
|
|
1649
1865
|
|
|
1650
1866
|
sig = super().format_signature()
|
|
1651
1867
|
sigs = []
|
|
@@ -1653,21 +1869,25 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1653
1869
|
overloads = self.get_overloaded_signatures()
|
|
1654
1870
|
if overloads and self.config.autodoc_typehints != 'none':
|
|
1655
1871
|
# Use signatures for overloaded methods instead of the implementation method.
|
|
1656
|
-
method = safe_getattr(
|
|
1872
|
+
method = safe_getattr(
|
|
1873
|
+
self._signature_class, self._signature_method_name, None
|
|
1874
|
+
)
|
|
1657
1875
|
__globals__ = safe_getattr(method, '__globals__', {})
|
|
1658
1876
|
for overload in overloads:
|
|
1659
|
-
overload = evaluate_signature(
|
|
1660
|
-
|
|
1877
|
+
overload = evaluate_signature(
|
|
1878
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
1879
|
+
)
|
|
1661
1880
|
|
|
1662
1881
|
parameters = list(overload.parameters.values())
|
|
1663
|
-
overload = overload.replace(
|
|
1664
|
-
|
|
1882
|
+
overload = overload.replace(
|
|
1883
|
+
parameters=parameters[1:], return_annotation=Parameter.empty
|
|
1884
|
+
)
|
|
1665
1885
|
sig = stringify_signature(overload, **kwargs)
|
|
1666
1886
|
sigs.append(sig)
|
|
1667
1887
|
else:
|
|
1668
1888
|
sigs.append(sig)
|
|
1669
1889
|
|
|
1670
|
-
return
|
|
1890
|
+
return '\n'.join(sigs)
|
|
1671
1891
|
|
|
1672
1892
|
def get_overloaded_signatures(self) -> list[Signature]:
|
|
1673
1893
|
if self._signature_class and self._signature_method_name:
|
|
@@ -1714,8 +1934,12 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1714
1934
|
self.add_line(' :final:', sourcename)
|
|
1715
1935
|
|
|
1716
1936
|
canonical_fullname = self.get_canonical_fullname()
|
|
1717
|
-
if (
|
|
1718
|
-
|
|
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
|
+
):
|
|
1719
1943
|
self.add_line(' :canonical: %s' % canonical_fullname, sourcename)
|
|
1720
1944
|
|
|
1721
1945
|
# add inheritance info, if wanted
|
|
@@ -1730,21 +1954,24 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1730
1954
|
else:
|
|
1731
1955
|
bases = []
|
|
1732
1956
|
|
|
1733
|
-
self.
|
|
1734
|
-
|
|
1957
|
+
self._events.emit(
|
|
1958
|
+
'autodoc-process-bases', self.fullname, self.object, self.options, bases
|
|
1959
|
+
)
|
|
1735
1960
|
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
else:
|
|
1739
|
-
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]
|
|
1740
1963
|
|
|
1741
1964
|
sourcename = self.get_sourcename()
|
|
1742
1965
|
self.add_line('', sourcename)
|
|
1743
1966
|
self.add_line(' ' + _('Bases: %s') % ', '.join(base_classes), sourcename)
|
|
1744
1967
|
|
|
1745
1968
|
def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]:
|
|
1746
|
-
members = get_class_members(
|
|
1747
|
-
|
|
1969
|
+
members = get_class_members(
|
|
1970
|
+
self.object,
|
|
1971
|
+
self.objpath,
|
|
1972
|
+
self.get_attr,
|
|
1973
|
+
self.config.autodoc_inherit_docstrings,
|
|
1974
|
+
)
|
|
1748
1975
|
if not want_all:
|
|
1749
1976
|
if not self.options.members:
|
|
1750
1977
|
return False, []
|
|
@@ -1754,8 +1981,12 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1754
1981
|
if name in members:
|
|
1755
1982
|
selected.append(members[name])
|
|
1756
1983
|
else:
|
|
1757
|
-
logger.warning(
|
|
1758
|
-
|
|
1984
|
+
logger.warning(
|
|
1985
|
+
__('missing attribute %s in object %s'),
|
|
1986
|
+
name,
|
|
1987
|
+
self.fullname,
|
|
1988
|
+
type='autodoc',
|
|
1989
|
+
)
|
|
1759
1990
|
return False, selected
|
|
1760
1991
|
elif self.options.inherited_members:
|
|
1761
1992
|
return False, list(members.values())
|
|
@@ -1777,7 +2008,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1777
2008
|
if lines is not None:
|
|
1778
2009
|
return lines
|
|
1779
2010
|
|
|
1780
|
-
classdoc_from = self.options.get(
|
|
2011
|
+
classdoc_from = self.options.get(
|
|
2012
|
+
'class-doc-from', self.config.autoclass_content
|
|
2013
|
+
)
|
|
1781
2014
|
|
|
1782
2015
|
docstrings = []
|
|
1783
2016
|
attrdocstring = getdoc(self.object, self.get_attr)
|
|
@@ -1786,26 +2019,36 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1786
2019
|
|
|
1787
2020
|
# for classes, what the "docstring" is can be controlled via a
|
|
1788
2021
|
# config value; the default is only the class docstring
|
|
1789
|
-
if classdoc_from in
|
|
2022
|
+
if classdoc_from in {'both', 'init'}:
|
|
1790
2023
|
__init__ = self.get_attr(self.object, '__init__', None)
|
|
1791
|
-
initdocstring = getdoc(
|
|
1792
|
-
|
|
1793
|
-
|
|
2024
|
+
initdocstring = getdoc(
|
|
2025
|
+
__init__,
|
|
2026
|
+
self.get_attr,
|
|
2027
|
+
self.config.autodoc_inherit_docstrings,
|
|
2028
|
+
self.object,
|
|
2029
|
+
'__init__',
|
|
2030
|
+
)
|
|
1794
2031
|
# for new-style classes, no __init__ means default __init__
|
|
1795
|
-
if
|
|
1796
|
-
|
|
1797
|
-
|
|
2032
|
+
if initdocstring is not None and (
|
|
2033
|
+
initdocstring == object.__init__.__doc__ # for pypy
|
|
2034
|
+
or initdocstring.strip() == object.__init__.__doc__ # for !pypy
|
|
2035
|
+
):
|
|
1798
2036
|
initdocstring = None
|
|
1799
2037
|
if not initdocstring:
|
|
1800
2038
|
# try __new__
|
|
1801
2039
|
__new__ = self.get_attr(self.object, '__new__', None)
|
|
1802
|
-
initdocstring = getdoc(
|
|
1803
|
-
|
|
1804
|
-
|
|
2040
|
+
initdocstring = getdoc(
|
|
2041
|
+
__new__,
|
|
2042
|
+
self.get_attr,
|
|
2043
|
+
self.config.autodoc_inherit_docstrings,
|
|
2044
|
+
self.object,
|
|
2045
|
+
'__new__',
|
|
2046
|
+
)
|
|
1805
2047
|
# for new-style classes, no __new__ means default __new__
|
|
1806
|
-
if
|
|
1807
|
-
|
|
1808
|
-
|
|
2048
|
+
if initdocstring is not None and (
|
|
2049
|
+
initdocstring == object.__new__.__doc__ # for pypy
|
|
2050
|
+
or initdocstring.strip() == object.__new__.__doc__ # for !pypy
|
|
2051
|
+
):
|
|
1809
2052
|
initdocstring = None
|
|
1810
2053
|
if initdocstring:
|
|
1811
2054
|
if classdoc_from == 'init':
|
|
@@ -1829,34 +2072,29 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1829
2072
|
return None
|
|
1830
2073
|
|
|
1831
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
|
+
|
|
1832
2078
|
if isinstance(self.object, NewType):
|
|
1833
|
-
|
|
1834
|
-
supertype = restify(self.object.__supertype__, "smart")
|
|
1835
|
-
else:
|
|
1836
|
-
supertype = restify(self.object.__supertype__)
|
|
2079
|
+
supertype = restify(self.object.__supertype__, mode=mode)
|
|
1837
2080
|
|
|
1838
2081
|
more_content = StringList([_('alias of %s') % supertype, ''], source='')
|
|
1839
2082
|
if isinstance(self.object, TypeVar):
|
|
1840
2083
|
attrs = [repr(self.object.__name__)]
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
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
|
+
)
|
|
1846
2088
|
if self.object.__bound__:
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
else:
|
|
1850
|
-
bound = restify(self.object.__bound__)
|
|
1851
|
-
attrs.append(r"bound=\ " + bound)
|
|
2089
|
+
bound = restify(self.object.__bound__, mode=mode)
|
|
2090
|
+
attrs.append(r'bound=\ ' + bound)
|
|
1852
2091
|
if self.object.__covariant__:
|
|
1853
|
-
attrs.append(
|
|
2092
|
+
attrs.append('covariant=True')
|
|
1854
2093
|
if self.object.__contravariant__:
|
|
1855
|
-
attrs.append(
|
|
2094
|
+
attrs.append('contravariant=True')
|
|
1856
2095
|
|
|
1857
2096
|
more_content = StringList(
|
|
1858
|
-
[_('alias of TypeVar(%s)') %
|
|
1859
|
-
source='',
|
|
2097
|
+
[_('alias of TypeVar(%s)') % ', '.join(attrs), ''], source=''
|
|
1860
2098
|
)
|
|
1861
2099
|
if self.doc_as_attr and self.modname != self.get_real_modname():
|
|
1862
2100
|
try:
|
|
@@ -1868,10 +2106,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1868
2106
|
|
|
1869
2107
|
if self.doc_as_attr and not self.get_variable_comment():
|
|
1870
2108
|
try:
|
|
1871
|
-
|
|
1872
|
-
alias = restify(self.object, "smart")
|
|
1873
|
-
else:
|
|
1874
|
-
alias = restify(self.object)
|
|
2109
|
+
alias = restify(self.object, mode=mode)
|
|
1875
2110
|
more_content = StringList([_('alias of %s') % alias], source='')
|
|
1876
2111
|
except AttributeError:
|
|
1877
2112
|
pass # Invalid class object is passed.
|
|
@@ -1895,15 +2130,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|
|
1895
2130
|
# If a class gets imported into the module real_modname
|
|
1896
2131
|
# the analyzer won't find the source of the class, if
|
|
1897
2132
|
# it looks in real_modname.
|
|
1898
|
-
return super().generate(
|
|
1899
|
-
|
|
1900
|
-
|
|
2133
|
+
return super().generate(
|
|
2134
|
+
more_content=more_content,
|
|
2135
|
+
check_module=check_module,
|
|
2136
|
+
all_members=all_members,
|
|
2137
|
+
)
|
|
1901
2138
|
|
|
1902
2139
|
|
|
1903
2140
|
class ExceptionDocumenter(ClassDocumenter):
|
|
1904
|
-
"""
|
|
1905
|
-
Specialized ClassDocumenter subclass for exceptions.
|
|
1906
|
-
"""
|
|
2141
|
+
"""Specialized ClassDocumenter subclass for exceptions."""
|
|
1907
2142
|
|
|
1908
2143
|
objtype = 'exception'
|
|
1909
2144
|
member_order = 10
|
|
@@ -1913,7 +2148,7 @@ class ExceptionDocumenter(ClassDocumenter):
|
|
|
1913
2148
|
|
|
1914
2149
|
@classmethod
|
|
1915
2150
|
def can_document_member(
|
|
1916
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2151
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
1917
2152
|
) -> bool:
|
|
1918
2153
|
try:
|
|
1919
2154
|
return isinstance(member, type) and issubclass(member, BaseException)
|
|
@@ -1951,21 +2186,20 @@ class DataDocumenterMixinBase:
|
|
|
1951
2186
|
|
|
1952
2187
|
|
|
1953
2188
|
class GenericAliasMixin(DataDocumenterMixinBase):
|
|
1954
|
-
"""
|
|
1955
|
-
Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
|
|
2189
|
+
"""Mixin for DataDocumenter and AttributeDocumenter to provide the feature for
|
|
1956
2190
|
supporting GenericAliases.
|
|
1957
2191
|
"""
|
|
1958
2192
|
|
|
1959
2193
|
def should_suppress_directive_header(self) -> bool:
|
|
1960
|
-
return (
|
|
1961
|
-
|
|
2194
|
+
return (
|
|
2195
|
+
inspect.isgenericalias(self.object)
|
|
2196
|
+
or super().should_suppress_directive_header()
|
|
2197
|
+
)
|
|
1962
2198
|
|
|
1963
2199
|
def update_content(self, more_content: StringList) -> None:
|
|
1964
2200
|
if inspect.isgenericalias(self.object):
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
else:
|
|
1968
|
-
alias = restify(self.object)
|
|
2201
|
+
mode = _get_render_mode(self.config.autodoc_typehints_format)
|
|
2202
|
+
alias = restify(self.object, mode=mode)
|
|
1969
2203
|
|
|
1970
2204
|
more_content.append(_('alias of %s') % alias, '')
|
|
1971
2205
|
more_content.append('', '')
|
|
@@ -1974,8 +2208,7 @@ class GenericAliasMixin(DataDocumenterMixinBase):
|
|
|
1974
2208
|
|
|
1975
2209
|
|
|
1976
2210
|
class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
1977
|
-
"""
|
|
1978
|
-
Mixin for DataDocumenter to provide the feature for supporting uninitialized
|
|
2211
|
+
"""Mixin for DataDocumenter to provide the feature for supporting uninitialized
|
|
1979
2212
|
(type annotation only) global variables.
|
|
1980
2213
|
"""
|
|
1981
2214
|
|
|
@@ -1987,9 +2220,12 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
1987
2220
|
try:
|
|
1988
2221
|
with mock(self.config.autodoc_mock_imports):
|
|
1989
2222
|
parent = import_module(self.modname)
|
|
1990
|
-
annotations = get_type_hints(
|
|
1991
|
-
|
|
1992
|
-
|
|
2223
|
+
annotations = get_type_hints(
|
|
2224
|
+
parent,
|
|
2225
|
+
None,
|
|
2226
|
+
self.config.autodoc_type_aliases,
|
|
2227
|
+
include_extras=True,
|
|
2228
|
+
)
|
|
1993
2229
|
if self.objpath[-1] in annotations:
|
|
1994
2230
|
self.object = UNINITIALIZED_ATTR
|
|
1995
2231
|
self.parent = parent
|
|
@@ -2004,8 +2240,9 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
2004
2240
|
return False
|
|
2005
2241
|
|
|
2006
2242
|
def should_suppress_value_header(self) -> bool:
|
|
2007
|
-
return (
|
|
2008
|
-
|
|
2243
|
+
return (
|
|
2244
|
+
self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header()
|
|
2245
|
+
)
|
|
2009
2246
|
|
|
2010
2247
|
def get_doc(self) -> list[list[str]] | None:
|
|
2011
2248
|
if self.object is UNINITIALIZED_ATTR:
|
|
@@ -2014,22 +2251,21 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
|
|
2014
2251
|
return super().get_doc() # type: ignore[misc]
|
|
2015
2252
|
|
|
2016
2253
|
|
|
2017
|
-
class DataDocumenter(
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
Specialized Documenter subclass for data items.
|
|
2021
|
-
"""
|
|
2254
|
+
class DataDocumenter(
|
|
2255
|
+
GenericAliasMixin, UninitializedGlobalVariableMixin, ModuleLevelDocumenter
|
|
2256
|
+
):
|
|
2257
|
+
"""Specialized Documenter subclass for data items."""
|
|
2022
2258
|
|
|
2023
2259
|
objtype = 'data'
|
|
2024
2260
|
member_order = 40
|
|
2025
2261
|
priority = -10
|
|
2026
2262
|
option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec)
|
|
2027
|
-
option_spec[
|
|
2028
|
-
option_spec[
|
|
2263
|
+
option_spec['annotation'] = annotation_option
|
|
2264
|
+
option_spec['no-value'] = bool_option
|
|
2029
2265
|
|
|
2030
2266
|
@classmethod
|
|
2031
2267
|
def can_document_member(
|
|
2032
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2268
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2033
2269
|
) -> bool:
|
|
2034
2270
|
return isinstance(parent, ModuleDocumenter) and isattr
|
|
2035
2271
|
|
|
@@ -2042,7 +2278,7 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2042
2278
|
analyzer = ModuleAnalyzer.for_module(self.modname)
|
|
2043
2279
|
analyzer.analyze()
|
|
2044
2280
|
for (classname, attrname), annotation in analyzer.annotations.items():
|
|
2045
|
-
if classname
|
|
2281
|
+
if not classname and attrname not in annotations:
|
|
2046
2282
|
annotations[attrname] = annotation
|
|
2047
2283
|
except PycodeError:
|
|
2048
2284
|
pass
|
|
@@ -2060,7 +2296,8 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2060
2296
|
else:
|
|
2061
2297
|
doc = self.get_doc() or []
|
|
2062
2298
|
docstring, metadata = separate_metadata(
|
|
2063
|
-
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2299
|
+
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2300
|
+
)
|
|
2064
2301
|
if 'hide-value' in metadata:
|
|
2065
2302
|
return True
|
|
2066
2303
|
|
|
@@ -2069,29 +2306,38 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2069
2306
|
def add_directive_header(self, sig: str) -> None:
|
|
2070
2307
|
super().add_directive_header(sig)
|
|
2071
2308
|
sourcename = self.get_sourcename()
|
|
2072
|
-
if
|
|
2309
|
+
if (
|
|
2310
|
+
self.options.annotation is SUPPRESS
|
|
2311
|
+
or self.should_suppress_directive_header()
|
|
2312
|
+
):
|
|
2073
2313
|
pass
|
|
2074
2314
|
elif self.options.annotation:
|
|
2075
|
-
self.add_line(' :annotation: %s' % self.options.annotation,
|
|
2076
|
-
sourcename)
|
|
2315
|
+
self.add_line(' :annotation: %s' % self.options.annotation, sourcename)
|
|
2077
2316
|
else:
|
|
2078
2317
|
if self.config.autodoc_typehints != 'none':
|
|
2079
2318
|
# obtain annotation for this data
|
|
2080
|
-
annotations = get_type_hints(
|
|
2081
|
-
|
|
2082
|
-
|
|
2319
|
+
annotations = get_type_hints(
|
|
2320
|
+
self.parent,
|
|
2321
|
+
None,
|
|
2322
|
+
self.config.autodoc_type_aliases,
|
|
2323
|
+
include_extras=True,
|
|
2324
|
+
)
|
|
2083
2325
|
if self.objpath[-1] in annotations:
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
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
|
+
)
|
|
2090
2333
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2091
2334
|
|
|
2092
2335
|
try:
|
|
2093
|
-
if (
|
|
2094
|
-
|
|
2336
|
+
if (
|
|
2337
|
+
self.options.no_value
|
|
2338
|
+
or self.should_suppress_value_header()
|
|
2339
|
+
or ismock(self.object)
|
|
2340
|
+
):
|
|
2095
2341
|
pass
|
|
2096
2342
|
else:
|
|
2097
2343
|
objrepr = object_description(self.object)
|
|
@@ -2139,9 +2385,7 @@ class DataDocumenter(GenericAliasMixin,
|
|
|
2139
2385
|
|
|
2140
2386
|
|
|
2141
2387
|
class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: ignore[misc]
|
|
2142
|
-
"""
|
|
2143
|
-
Specialized Documenter subclass for methods (normal, static and class).
|
|
2144
|
-
"""
|
|
2388
|
+
"""Specialized Documenter subclass for methods (normal, static and class)."""
|
|
2145
2389
|
|
|
2146
2390
|
objtype = 'method'
|
|
2147
2391
|
directivetype = 'method'
|
|
@@ -2150,7 +2394,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2150
2394
|
|
|
2151
2395
|
@classmethod
|
|
2152
2396
|
def can_document_member(
|
|
2153
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2397
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2154
2398
|
) -> bool:
|
|
2155
2399
|
return inspect.isroutine(member) and not isinstance(parent, ModuleDocumenter)
|
|
2156
2400
|
|
|
@@ -2160,22 +2404,23 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2160
2404
|
return ret
|
|
2161
2405
|
|
|
2162
2406
|
# to distinguish classmethod/staticmethod
|
|
2163
|
-
obj = self.parent.__dict__.get(self.object_name)
|
|
2164
|
-
if obj
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
#
|
|
2170
|
-
self.member_order
|
|
2171
|
-
|
|
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
|
|
2172
2415
|
return ret
|
|
2173
2416
|
|
|
2174
2417
|
def format_args(self, **kwargs: Any) -> str:
|
|
2175
|
-
if self.config.autodoc_typehints in
|
|
2418
|
+
if self.config.autodoc_typehints in {'none', 'description'}:
|
|
2176
2419
|
kwargs.setdefault('show_annotation', False)
|
|
2177
|
-
if self.config.autodoc_typehints_format ==
|
|
2420
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
2178
2421
|
kwargs.setdefault('unqualified_typehints', True)
|
|
2422
|
+
if self.config.python_display_short_literal_types:
|
|
2423
|
+
kwargs.setdefault('short_literals', True)
|
|
2179
2424
|
|
|
2180
2425
|
try:
|
|
2181
2426
|
if self.object == object.__init__ and self.parent != object: # NoQA: E721
|
|
@@ -2185,18 +2430,31 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2185
2430
|
# But it makes users confused.
|
|
2186
2431
|
args = '()'
|
|
2187
2432
|
else:
|
|
2188
|
-
if inspect.isstaticmethod(
|
|
2189
|
-
self.
|
|
2190
|
-
|
|
2191
|
-
|
|
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
|
+
)
|
|
2192
2444
|
else:
|
|
2193
|
-
self.
|
|
2194
|
-
|
|
2195
|
-
|
|
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
|
+
)
|
|
2196
2453
|
args = stringify_signature(sig, **kwargs)
|
|
2197
2454
|
except TypeError as exc:
|
|
2198
|
-
logger.warning(
|
|
2199
|
-
|
|
2455
|
+
logger.warning(
|
|
2456
|
+
__('Failed to get a method signature for %s: %s'), self.fullname, exc
|
|
2457
|
+
)
|
|
2200
2458
|
return ''
|
|
2201
2459
|
except ValueError:
|
|
2202
2460
|
args = ''
|
|
@@ -2215,8 +2473,11 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2215
2473
|
self.add_line(' :abstractmethod:', sourcename)
|
|
2216
2474
|
if inspect.iscoroutinefunction(obj) or inspect.isasyncgenfunction(obj):
|
|
2217
2475
|
self.add_line(' :async:', sourcename)
|
|
2218
|
-
if (
|
|
2219
|
-
|
|
2476
|
+
if (
|
|
2477
|
+
inspect.is_classmethod_like(obj)
|
|
2478
|
+
or inspect.is_singledispatch_method(obj)
|
|
2479
|
+
and inspect.is_classmethod_like(obj.func)
|
|
2480
|
+
):
|
|
2220
2481
|
self.add_line(' :classmethod:', sourcename)
|
|
2221
2482
|
if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name):
|
|
2222
2483
|
self.add_line(' :staticmethod:', sourcename)
|
|
@@ -2227,13 +2488,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2227
2488
|
pass
|
|
2228
2489
|
|
|
2229
2490
|
def format_signature(self, **kwargs: Any) -> str:
|
|
2230
|
-
if self.config.autodoc_typehints_format ==
|
|
2491
|
+
if self.config.autodoc_typehints_format == 'short':
|
|
2231
2492
|
kwargs.setdefault('unqualified_typehints', True)
|
|
2493
|
+
if self.config.python_display_short_literal_types:
|
|
2494
|
+
kwargs.setdefault('short_literals', True)
|
|
2232
2495
|
|
|
2233
2496
|
sigs = []
|
|
2234
|
-
if (
|
|
2235
|
-
|
|
2236
|
-
|
|
2497
|
+
if (
|
|
2498
|
+
self.analyzer
|
|
2499
|
+
and '.'.join(self.objpath) in self.analyzer.overloads
|
|
2500
|
+
and self.config.autodoc_typehints != 'none'
|
|
2501
|
+
):
|
|
2237
2502
|
# Use signatures for overloaded methods instead of the implementation method.
|
|
2238
2503
|
overloaded = True
|
|
2239
2504
|
else:
|
|
@@ -2258,27 +2523,37 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2258
2523
|
documenter.objpath = ['']
|
|
2259
2524
|
sigs.append(documenter.format_signature())
|
|
2260
2525
|
if overloaded and self.analyzer is not None:
|
|
2261
|
-
if inspect.isstaticmethod(
|
|
2262
|
-
|
|
2263
|
-
|
|
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
|
+
)
|
|
2264
2534
|
else:
|
|
2265
|
-
actual = inspect.signature(
|
|
2266
|
-
|
|
2535
|
+
actual = inspect.signature(
|
|
2536
|
+
self.object,
|
|
2537
|
+
bound_method=True,
|
|
2538
|
+
type_aliases=self.config.autodoc_type_aliases,
|
|
2539
|
+
)
|
|
2267
2540
|
|
|
2268
2541
|
__globals__ = safe_getattr(self.object, '__globals__', {})
|
|
2269
2542
|
for overload in self.analyzer.overloads['.'.join(self.objpath)]:
|
|
2270
2543
|
overload = self.merge_default_value(actual, overload)
|
|
2271
|
-
overload = evaluate_signature(
|
|
2272
|
-
|
|
2544
|
+
overload = evaluate_signature(
|
|
2545
|
+
overload, __globals__, self.config.autodoc_type_aliases
|
|
2546
|
+
)
|
|
2273
2547
|
|
|
2274
|
-
if not inspect.isstaticmethod(
|
|
2275
|
-
|
|
2548
|
+
if not inspect.isstaticmethod(
|
|
2549
|
+
self.object, cls=self.parent, name=self.object_name
|
|
2550
|
+
):
|
|
2276
2551
|
parameters = list(overload.parameters.values())
|
|
2277
2552
|
overload = overload.replace(parameters=parameters[1:])
|
|
2278
2553
|
sig = stringify_signature(overload, **kwargs)
|
|
2279
2554
|
sigs.append(sig)
|
|
2280
2555
|
|
|
2281
|
-
return
|
|
2556
|
+
return '\n'.join(sigs)
|
|
2282
2557
|
|
|
2283
2558
|
def merge_default_value(self, actual: Signature, overload: Signature) -> Signature:
|
|
2284
2559
|
"""Merge default values of actual implementation to the overload variants."""
|
|
@@ -2290,13 +2565,16 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2290
2565
|
|
|
2291
2566
|
return overload.replace(parameters=parameters)
|
|
2292
2567
|
|
|
2293
|
-
def annotate_to_first_argument(
|
|
2568
|
+
def annotate_to_first_argument(
|
|
2569
|
+
self, func: Callable[..., Any], typ: type
|
|
2570
|
+
) -> Callable[..., Any] | None:
|
|
2294
2571
|
"""Annotate type hint to the first argument of function if needed."""
|
|
2295
2572
|
try:
|
|
2296
2573
|
sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases)
|
|
2297
2574
|
except TypeError as exc:
|
|
2298
|
-
logger.warning(
|
|
2299
|
-
|
|
2575
|
+
logger.warning(
|
|
2576
|
+
__('Failed to get a method signature for %s: %s'), self.fullname, exc
|
|
2577
|
+
)
|
|
2300
2578
|
return None
|
|
2301
2579
|
except ValueError:
|
|
2302
2580
|
return None
|
|
@@ -2312,7 +2590,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2312
2590
|
params[1] = params[1].replace(annotation=typ)
|
|
2313
2591
|
try:
|
|
2314
2592
|
dummy.__signature__ = sig.replace( # type: ignore[attr-defined]
|
|
2315
|
-
parameters=params
|
|
2593
|
+
parameters=params
|
|
2594
|
+
)
|
|
2316
2595
|
return dummy
|
|
2317
2596
|
except (AttributeError, TypeError):
|
|
2318
2597
|
# failed to update signature (ex. built-in or extension types)
|
|
@@ -2328,12 +2607,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2328
2607
|
# `DocstringSignatureMixin`.
|
|
2329
2608
|
return self._new_docstrings
|
|
2330
2609
|
if self.objpath[-1] == '__init__':
|
|
2331
|
-
docstring = getdoc(
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
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
|
+
):
|
|
2337
2621
|
docstring = None
|
|
2338
2622
|
if docstring:
|
|
2339
2623
|
tab_width = self.directive.state.document.settings.tab_width
|
|
@@ -2341,12 +2625,17 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2341
2625
|
else:
|
|
2342
2626
|
return []
|
|
2343
2627
|
elif self.objpath[-1] == '__new__':
|
|
2344
|
-
docstring = getdoc(
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
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
|
+
):
|
|
2350
2639
|
docstring = None
|
|
2351
2640
|
if docstring:
|
|
2352
2641
|
tab_width = self.directive.state.document.settings.tab_width
|
|
@@ -2358,8 +2647,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|
|
2358
2647
|
|
|
2359
2648
|
|
|
2360
2649
|
class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
2361
|
-
"""
|
|
2362
|
-
Mixin for AttributeDocumenter to provide the feature for supporting non
|
|
2650
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting non
|
|
2363
2651
|
data-descriptors.
|
|
2364
2652
|
|
|
2365
2653
|
.. note:: This mix-in must be inherited after other mix-ins. Otherwise, docstring
|
|
@@ -2376,8 +2664,10 @@ class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
|
2376
2664
|
return ret
|
|
2377
2665
|
|
|
2378
2666
|
def should_suppress_value_header(self) -> bool:
|
|
2379
|
-
return (
|
|
2380
|
-
|
|
2667
|
+
return (
|
|
2668
|
+
not getattr(self, 'non_data_descriptor', False)
|
|
2669
|
+
or super().should_suppress_directive_header()
|
|
2670
|
+
)
|
|
2381
2671
|
|
|
2382
2672
|
def get_doc(self) -> list[list[str]] | None:
|
|
2383
2673
|
if getattr(self, 'non_data_descriptor', False):
|
|
@@ -2389,9 +2679,7 @@ class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
|
|
2389
2679
|
|
|
2390
2680
|
|
|
2391
2681
|
class SlotsMixin(DataDocumenterMixinBase):
|
|
2392
|
-
"""
|
|
2393
|
-
Mixin for AttributeDocumenter to provide the feature for supporting __slots__.
|
|
2394
|
-
"""
|
|
2682
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting __slots__."""
|
|
2395
2683
|
|
|
2396
2684
|
def isslotsattribute(self) -> bool:
|
|
2397
2685
|
"""Check the subject is an attribute in __slots__."""
|
|
@@ -2420,25 +2708,29 @@ class SlotsMixin(DataDocumenterMixinBase):
|
|
|
2420
2708
|
if self.object is SLOTSATTR:
|
|
2421
2709
|
try:
|
|
2422
2710
|
parent___slots__ = inspect.getslots(self.parent)
|
|
2423
|
-
if parent___slots__ and (
|
|
2711
|
+
if parent___slots__ and (
|
|
2712
|
+
docstring := parent___slots__.get(self.objpath[-1])
|
|
2713
|
+
):
|
|
2424
2714
|
docstring = prepare_docstring(docstring)
|
|
2425
2715
|
return [docstring]
|
|
2426
2716
|
else:
|
|
2427
2717
|
return []
|
|
2428
2718
|
except ValueError as exc:
|
|
2429
|
-
logger.warning(
|
|
2430
|
-
|
|
2719
|
+
logger.warning(
|
|
2720
|
+
__('Invalid __slots__ found on %s. Ignored.'),
|
|
2721
|
+
(self.parent.__qualname__, exc),
|
|
2722
|
+
type='autodoc',
|
|
2723
|
+
)
|
|
2431
2724
|
return []
|
|
2432
2725
|
else:
|
|
2433
2726
|
return super().get_doc() # type: ignore[misc]
|
|
2434
2727
|
|
|
2435
2728
|
|
|
2436
2729
|
class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
2437
|
-
"""
|
|
2438
|
-
Mixin for AttributeDocumenter to provide the feature for supporting runtime
|
|
2730
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting runtime
|
|
2439
2731
|
instance attributes (that are defined in __init__() methods with doc-comments).
|
|
2440
2732
|
|
|
2441
|
-
Example
|
|
2733
|
+
Example::
|
|
2442
2734
|
|
|
2443
2735
|
class Foo:
|
|
2444
2736
|
def __init__(self):
|
|
@@ -2482,7 +2774,9 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2482
2774
|
try:
|
|
2483
2775
|
with mock(self.config.autodoc_mock_imports):
|
|
2484
2776
|
ret = import_object(
|
|
2485
|
-
self.modname,
|
|
2777
|
+
self.modname,
|
|
2778
|
+
self.objpath[:-1],
|
|
2779
|
+
'class',
|
|
2486
2780
|
attrgetter=self.get_attr, # type: ignore[attr-defined]
|
|
2487
2781
|
)
|
|
2488
2782
|
parent = ret[3]
|
|
@@ -2500,23 +2794,26 @@ class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2500
2794
|
return False
|
|
2501
2795
|
|
|
2502
2796
|
def should_suppress_value_header(self) -> bool:
|
|
2503
|
-
return (
|
|
2504
|
-
|
|
2797
|
+
return (
|
|
2798
|
+
self.object is self.RUNTIME_INSTANCE_ATTRIBUTE
|
|
2799
|
+
or super().should_suppress_value_header()
|
|
2800
|
+
)
|
|
2505
2801
|
|
|
2506
2802
|
def get_doc(self) -> list[list[str]] | None:
|
|
2507
|
-
if (
|
|
2508
|
-
|
|
2803
|
+
if (
|
|
2804
|
+
self.object is self.RUNTIME_INSTANCE_ATTRIBUTE
|
|
2805
|
+
and self.is_runtime_instance_attribute_not_commented(self.parent)
|
|
2806
|
+
):
|
|
2509
2807
|
return None
|
|
2510
2808
|
else:
|
|
2511
2809
|
return super().get_doc() # type: ignore[misc]
|
|
2512
2810
|
|
|
2513
2811
|
|
|
2514
2812
|
class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
2515
|
-
"""
|
|
2516
|
-
Mixin for AttributeDocumenter to provide the feature for supporting uninitialized
|
|
2813
|
+
"""Mixin for AttributeDocumenter to provide the feature for supporting uninitialized
|
|
2517
2814
|
instance attributes (PEP-526 styled, annotation only attributes).
|
|
2518
2815
|
|
|
2519
|
-
Example
|
|
2816
|
+
Example::
|
|
2520
2817
|
|
|
2521
2818
|
class Foo:
|
|
2522
2819
|
attr: int #: This is a target of this mix-in.
|
|
@@ -2524,8 +2821,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2524
2821
|
|
|
2525
2822
|
def is_uninitialized_instance_attribute(self, parent: Any) -> bool:
|
|
2526
2823
|
"""Check the subject is an annotation only attribute."""
|
|
2527
|
-
annotations = get_type_hints(
|
|
2528
|
-
|
|
2824
|
+
annotations = get_type_hints(
|
|
2825
|
+
parent, None, self.config.autodoc_type_aliases, include_extras=True
|
|
2826
|
+
)
|
|
2529
2827
|
return self.objpath[-1] in annotations
|
|
2530
2828
|
|
|
2531
2829
|
def import_object(self, raiseerror: bool = False) -> bool:
|
|
@@ -2537,7 +2835,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2537
2835
|
except ImportError as exc:
|
|
2538
2836
|
try:
|
|
2539
2837
|
ret = import_object(
|
|
2540
|
-
self.modname,
|
|
2838
|
+
self.modname,
|
|
2839
|
+
self.objpath[:-1],
|
|
2840
|
+
'class',
|
|
2541
2841
|
attrgetter=self.get_attr, # type: ignore[attr-defined]
|
|
2542
2842
|
)
|
|
2543
2843
|
parent = ret[3]
|
|
@@ -2555,8 +2855,9 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2555
2855
|
return False
|
|
2556
2856
|
|
|
2557
2857
|
def should_suppress_value_header(self) -> bool:
|
|
2558
|
-
return (
|
|
2559
|
-
|
|
2858
|
+
return (
|
|
2859
|
+
self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header()
|
|
2860
|
+
)
|
|
2560
2861
|
|
|
2561
2862
|
def get_doc(self) -> list[list[str]] | None:
|
|
2562
2863
|
if self.object is UNINITIALIZED_ATTR:
|
|
@@ -2564,19 +2865,22 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
|
|
2564
2865
|
return super().get_doc() # type: ignore[misc]
|
|
2565
2866
|
|
|
2566
2867
|
|
|
2567
|
-
class AttributeDocumenter(
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
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."""
|
|
2574
2878
|
|
|
2575
2879
|
objtype = 'attribute'
|
|
2576
2880
|
member_order = 60
|
|
2577
2881
|
option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec)
|
|
2578
|
-
option_spec[
|
|
2579
|
-
option_spec[
|
|
2882
|
+
option_spec['annotation'] = annotation_option
|
|
2883
|
+
option_spec['no-value'] = bool_option
|
|
2580
2884
|
|
|
2581
2885
|
# must be higher than the MethodDocumenter, else it will recognize
|
|
2582
2886
|
# some non-data descriptors as methods
|
|
@@ -2584,11 +2888,13 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2584
2888
|
|
|
2585
2889
|
@staticmethod
|
|
2586
2890
|
def is_function_or_method(obj: Any) -> bool:
|
|
2587
|
-
return
|
|
2891
|
+
return (
|
|
2892
|
+
inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj)
|
|
2893
|
+
)
|
|
2588
2894
|
|
|
2589
2895
|
@classmethod
|
|
2590
2896
|
def can_document_member(
|
|
2591
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2897
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2592
2898
|
) -> bool:
|
|
2593
2899
|
if isinstance(parent, ModuleDocumenter):
|
|
2594
2900
|
return False
|
|
@@ -2612,7 +2918,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2612
2918
|
|
|
2613
2919
|
analyzer = ModuleAnalyzer.for_module(module)
|
|
2614
2920
|
analyzer.analyze()
|
|
2615
|
-
|
|
2921
|
+
anns = analyzer.annotations
|
|
2922
|
+
for (classname, attrname), annotation in anns.items():
|
|
2616
2923
|
if classname == qualname and attrname not in annotations:
|
|
2617
2924
|
annotations[attrname] = annotation
|
|
2618
2925
|
except (AttributeError, PycodeError):
|
|
@@ -2641,7 +2948,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2641
2948
|
doc = self.get_doc()
|
|
2642
2949
|
if doc:
|
|
2643
2950
|
docstring, metadata = separate_metadata(
|
|
2644
|
-
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2951
|
+
'\n'.join(functools.reduce(operator.iadd, doc, []))
|
|
2952
|
+
)
|
|
2645
2953
|
if 'hide-value' in metadata:
|
|
2646
2954
|
return True
|
|
2647
2955
|
|
|
@@ -2650,28 +2958,38 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2650
2958
|
def add_directive_header(self, sig: str) -> None:
|
|
2651
2959
|
super().add_directive_header(sig)
|
|
2652
2960
|
sourcename = self.get_sourcename()
|
|
2653
|
-
if
|
|
2961
|
+
if (
|
|
2962
|
+
self.options.annotation is SUPPRESS
|
|
2963
|
+
or self.should_suppress_directive_header()
|
|
2964
|
+
):
|
|
2654
2965
|
pass
|
|
2655
2966
|
elif self.options.annotation:
|
|
2656
2967
|
self.add_line(' :annotation: %s' % self.options.annotation, sourcename)
|
|
2657
2968
|
else:
|
|
2658
2969
|
if self.config.autodoc_typehints != 'none':
|
|
2659
2970
|
# obtain type annotation for this attribute
|
|
2660
|
-
annotations = get_type_hints(
|
|
2661
|
-
|
|
2662
|
-
|
|
2971
|
+
annotations = get_type_hints(
|
|
2972
|
+
self.parent,
|
|
2973
|
+
None,
|
|
2974
|
+
self.config.autodoc_type_aliases,
|
|
2975
|
+
include_extras=True,
|
|
2976
|
+
)
|
|
2663
2977
|
if self.objpath[-1] in annotations:
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
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
|
+
)
|
|
2670
2985
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2671
2986
|
|
|
2672
2987
|
try:
|
|
2673
|
-
if (
|
|
2674
|
-
|
|
2988
|
+
if (
|
|
2989
|
+
self.options.no_value
|
|
2990
|
+
or self.should_suppress_value_header()
|
|
2991
|
+
or ismock(self.object)
|
|
2992
|
+
):
|
|
2675
2993
|
pass
|
|
2676
2994
|
else:
|
|
2677
2995
|
objrepr = object_description(self.object)
|
|
@@ -2705,7 +3023,7 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2705
3023
|
try:
|
|
2706
3024
|
# Disable `autodoc_inherit_docstring` temporarily to avoid to obtain
|
|
2707
3025
|
# a docstring from the value which descriptor returns unexpectedly.
|
|
2708
|
-
#
|
|
3026
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/7805
|
|
2709
3027
|
orig = self.config.autodoc_inherit_docstrings
|
|
2710
3028
|
self.config.autodoc_inherit_docstrings = False
|
|
2711
3029
|
return super().get_doc()
|
|
@@ -2723,11 +3041,8 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc]
|
|
|
2723
3041
|
super().add_content(more_content)
|
|
2724
3042
|
|
|
2725
3043
|
|
|
2726
|
-
class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
2727
|
-
|
|
2728
|
-
"""
|
|
2729
|
-
Specialized Documenter subclass for properties.
|
|
2730
|
-
"""
|
|
3044
|
+
class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore[misc]
|
|
3045
|
+
"""Specialized Documenter subclass for properties."""
|
|
2731
3046
|
|
|
2732
3047
|
objtype = 'property'
|
|
2733
3048
|
member_order = 60
|
|
@@ -2737,7 +3052,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2737
3052
|
|
|
2738
3053
|
@classmethod
|
|
2739
3054
|
def can_document_member(
|
|
2740
|
-
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
3055
|
+
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
|
|
2741
3056
|
) -> bool:
|
|
2742
3057
|
if isinstance(parent, ClassDocumenter):
|
|
2743
3058
|
if inspect.isproperty(member):
|
|
@@ -2773,7 +3088,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2773
3088
|
return ''
|
|
2774
3089
|
|
|
2775
3090
|
# update the annotations of the property getter
|
|
2776
|
-
self.
|
|
3091
|
+
self._events.emit('autodoc-before-process-signature', func, False)
|
|
2777
3092
|
# correctly format the arguments for a property
|
|
2778
3093
|
return super().format_args(**kwargs)
|
|
2779
3094
|
|
|
@@ -2797,23 +3112,25 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2797
3112
|
return
|
|
2798
3113
|
|
|
2799
3114
|
try:
|
|
2800
|
-
signature = inspect.signature(
|
|
2801
|
-
|
|
3115
|
+
signature = inspect.signature(
|
|
3116
|
+
func, type_aliases=self.config.autodoc_type_aliases
|
|
3117
|
+
)
|
|
2802
3118
|
if signature.return_annotation is not Parameter.empty:
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
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
|
+
)
|
|
2808
3124
|
self.add_line(' :type: ' + objrepr, sourcename)
|
|
2809
3125
|
except TypeError as exc:
|
|
2810
|
-
logger.warning(
|
|
2811
|
-
|
|
3126
|
+
logger.warning(
|
|
3127
|
+
__('Failed to get a function signature for %s: %s'), self.fullname, exc
|
|
3128
|
+
)
|
|
2812
3129
|
pass
|
|
2813
3130
|
except ValueError:
|
|
2814
3131
|
pass
|
|
2815
3132
|
|
|
2816
|
-
def _get_property_getter(self) -> Callable | None:
|
|
3133
|
+
def _get_property_getter(self) -> Callable[..., Any] | None:
|
|
2817
3134
|
if safe_getattr(self.object, 'fget', None): # property
|
|
2818
3135
|
return self.object.fget
|
|
2819
3136
|
if safe_getattr(self.object, 'func', None): # cached_property
|
|
@@ -2821,9 +3138,11 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc]
|
|
|
2821
3138
|
return None
|
|
2822
3139
|
|
|
2823
3140
|
|
|
2824
|
-
def autodoc_attrgetter(
|
|
3141
|
+
def autodoc_attrgetter(
|
|
3142
|
+
obj: Any, name: str, *defargs: Any, registry: SphinxComponentRegistry
|
|
3143
|
+
) -> Any:
|
|
2825
3144
|
"""Alternative getattr() for types"""
|
|
2826
|
-
for typ, func in
|
|
3145
|
+
for typ, func in registry.autodoc_attrgetters.items():
|
|
2827
3146
|
if isinstance(obj, typ):
|
|
2828
3147
|
return func(obj, name, *defargs)
|
|
2829
3148
|
|
|
@@ -2841,22 +3160,54 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
2841
3160
|
app.add_autodocumenter(AttributeDocumenter)
|
|
2842
3161
|
app.add_autodocumenter(PropertyDocumenter)
|
|
2843
3162
|
|
|
2844
|
-
app.add_config_value(
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
app.add_config_value(
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
app.add_config_value(
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
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
|
+
)
|
|
2860
3211
|
app.add_event('autodoc-before-process-signature')
|
|
2861
3212
|
app.add_event('autodoc-process-docstring')
|
|
2862
3213
|
app.add_event('autodoc-process-signature')
|
|
@@ -2867,4 +3218,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
|
|
2867
3218
|
app.setup_extension('sphinx.ext.autodoc.type_comment')
|
|
2868
3219
|
app.setup_extension('sphinx.ext.autodoc.typehints')
|
|
2869
3220
|
|
|
2870
|
-
return {
|
|
3221
|
+
return {
|
|
3222
|
+
'version': sphinx.__display_version__,
|
|
3223
|
+
'parallel_read_safe': True,
|
|
3224
|
+
}
|