Skip to content

Commit de745a9

Browse files
authored
Consolidate option spec processing into _directive_options.py (#14009)
1 parent 7993a8b commit de745a9

File tree

14 files changed

+99
-270
lines changed

14 files changed

+99
-270
lines changed

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
('py:class', 'pygments.lexer.Lexer'),
236236
('py:class', 'sphinx.directives.ObjDescT'),
237237
('py:class', 'sphinx.domains.IndexEntry'),
238+
# sphinx.application.Sphinx.add_autodocumenter
238239
('py:class', 'sphinx.ext.autodoc.Documenter'),
239240
('py:class', 'sphinx.errors.NoUri'),
240241
('py:class', 'sphinx.roles.XRefRole'),

sphinx/application.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,8 +1629,9 @@ def add_autodocumenter(self, cls: type[Documenter], override: bool = False) -> N
16291629
logger.debug('[app] adding autodocumenter: %r', cls)
16301630
from sphinx.ext.autodoc.directive import AutodocDirective
16311631

1632-
self.registry.add_documenter(cls.objtype, cls)
1633-
self.add_directive('auto' + cls.objtype, AutodocDirective, override=override)
1632+
objtype = cls.objtype # type: ignore[attr-defined]
1633+
self.registry.add_documenter(objtype, cls)
1634+
self.add_directive('auto' + objtype, AutodocDirective, override=override)
16341635

16351636
def add_autodoc_attrgetter(
16361637
self, typ: type, getter: Callable[[Any, str, Any], Any]

sphinx/ext/autodoc/__init__.py

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,6 @@
2323
members_option,
2424
merge_members_option,
2525
)
26-
from sphinx.ext.autodoc._documenters import (
27-
AttributeDocumenter,
28-
ClassDocumenter,
29-
DataDocumenter,
30-
DecoratorDocumenter,
31-
Documenter,
32-
ExceptionDocumenter,
33-
FunctionDocumenter,
34-
MethodDocumenter,
35-
ModuleDocumenter,
36-
PropertyDocumenter,
37-
TypeAliasDocumenter,
38-
)
3926
from sphinx.ext.autodoc._event_listeners import between, cut_lines
4027
from sphinx.ext.autodoc._member_finder import ObjectMember, special_member_re
4128
from sphinx.ext.autodoc._sentinels import ALL, EMPTY, SUPPRESS, UNINITIALIZED_ATTR
@@ -45,26 +32,18 @@
4532
from sphinx.ext.autodoc._sentinels import (
4633
SLOTS_ATTR as SLOTSATTR,
4734
)
35+
from sphinx.ext.autodoc.directive import AutodocDirective
4836
from sphinx.ext.autodoc.importer import py_ext_sig_re
4937

5038
if TYPE_CHECKING:
5139
from sphinx.application import Sphinx
40+
from sphinx.ext.autodoc._property_types import _AutodocObjType
5241
from sphinx.util.typing import ExtensionMetadata
5342

5443
__all__ = (
5544
# Useful event listener factories for autodoc-process-docstring
5645
'cut_lines',
5746
'between',
58-
# Documenters
59-
'AttributeDocumenter',
60-
'ClassDocumenter',
61-
'DataDocumenter',
62-
'DecoratorDocumenter',
63-
'ExceptionDocumenter',
64-
'FunctionDocumenter',
65-
'MethodDocumenter',
66-
'ModuleDocumenter',
67-
'PropertyDocumenter',
6847
# This class is only used in ``sphinx.ext.autodoc.directive``,
6948
# but we export it here for compatibility.
7049
# See: https://github.com/sphinx-doc/sphinx/issues/4538
@@ -93,21 +72,25 @@
9372
'ObjectMember',
9473
'py_ext_sig_re',
9574
'special_member_re',
96-
'Documenter',
9775
)
9876

9977

10078
def setup(app: Sphinx) -> ExtensionMetadata:
101-
app.add_autodocumenter(ModuleDocumenter)
102-
app.add_autodocumenter(ClassDocumenter)
103-
app.add_autodocumenter(ExceptionDocumenter)
104-
app.add_autodocumenter(DataDocumenter)
105-
app.add_autodocumenter(FunctionDocumenter)
106-
app.add_autodocumenter(DecoratorDocumenter)
107-
app.add_autodocumenter(MethodDocumenter)
108-
app.add_autodocumenter(AttributeDocumenter)
109-
app.add_autodocumenter(PropertyDocumenter)
110-
app.add_autodocumenter(TypeAliasDocumenter)
79+
obj_type: _AutodocObjType
80+
for obj_type in (
81+
'module',
82+
'class',
83+
'exception',
84+
'function',
85+
'decorator',
86+
'method',
87+
'property',
88+
'attribute',
89+
'data',
90+
'type',
91+
):
92+
# register the automodule, autoclass, etc. directives
93+
app.add_directive(f'auto{obj_type}', AutodocDirective)
11194

11295
app.add_config_value(
11396
'autoclass_content',

sphinx/ext/autodoc/_directive_options.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
if TYPE_CHECKING:
1111
from collections.abc import Mapping, Set
12-
from typing import Any, Literal, Self
12+
from typing import Any, Final, Literal, Self
1313

14+
from sphinx.ext.autodoc._property_types import _AutodocObjType
1415
from sphinx.ext.autodoc._sentinels import ALL_T, EMPTY_T, SUPPRESS_T
1516
from sphinx.util.typing import OptionSpec
1617

@@ -184,13 +185,67 @@ def __getattr__(self, name: str) -> Any:
184185
return None
185186

186187

188+
_OPTION_SPEC_COMMON: Final[OptionSpec] = {
189+
'no-index': bool_option,
190+
'no-index-entry': bool_option,
191+
}
192+
_OPTION_SPEC_HAS_MEMBERS: Final[OptionSpec] = _OPTION_SPEC_COMMON | {
193+
'members': members_option,
194+
'exclude-members': exclude_members_option,
195+
'undoc-members': bool_option,
196+
'private-members': members_option,
197+
'special-members': members_option,
198+
'member-order': member_order_option,
199+
'show-inheritance': bool_option,
200+
}
201+
_OPTION_SPEC_MODULE_SPECIFIC: Final[OptionSpec] = {
202+
'ignore-module-all': bool_option,
203+
'imported-members': bool_option,
204+
'deprecated': bool_option,
205+
'platform': identity,
206+
'synopsis': identity,
207+
}
208+
_OPTION_SPEC_CLASS_SPECIFIC: Final[OptionSpec] = {
209+
'class-doc-from': class_doc_from_option,
210+
'inherited-members': inherited_members_option,
211+
}
212+
_OPTION_SPEC_ASSIGNMENT: Final[OptionSpec] = _OPTION_SPEC_COMMON | {
213+
'annotation': annotation_option,
214+
'no-value': bool_option,
215+
}
216+
_OPTION_SPEC_DEPRECATED: Final[OptionSpec] = {
217+
'noindex': bool_option,
218+
}
219+
_OPTION_SPEC_FUNCTION_DEF: Final = _OPTION_SPEC_COMMON | _OPTION_SPEC_DEPRECATED
220+
_OPTION_SPECS: Final[Mapping[_AutodocObjType, OptionSpec]] = {
221+
'module': _OPTION_SPEC_HAS_MEMBERS
222+
| _OPTION_SPEC_MODULE_SPECIFIC
223+
| {'inherited-members': inherited_members_option} # special case
224+
| _OPTION_SPEC_DEPRECATED,
225+
'class': _OPTION_SPEC_HAS_MEMBERS
226+
| _OPTION_SPEC_CLASS_SPECIFIC
227+
| _OPTION_SPEC_DEPRECATED,
228+
'exception': _OPTION_SPEC_HAS_MEMBERS
229+
| _OPTION_SPEC_CLASS_SPECIFIC
230+
| _OPTION_SPEC_DEPRECATED,
231+
'function': _OPTION_SPEC_FUNCTION_DEF,
232+
'decorator': _OPTION_SPEC_FUNCTION_DEF,
233+
'method': _OPTION_SPEC_FUNCTION_DEF,
234+
'property': _OPTION_SPEC_FUNCTION_DEF,
235+
'attribute': _OPTION_SPEC_ASSIGNMENT | _OPTION_SPEC_DEPRECATED,
236+
'data': _OPTION_SPEC_ASSIGNMENT | _OPTION_SPEC_DEPRECATED,
237+
'type': _OPTION_SPEC_ASSIGNMENT,
238+
}
239+
240+
187241
def _process_documenter_options(
188242
*,
189-
option_spec: OptionSpec,
243+
obj_type: _AutodocObjType,
190244
default_options: dict[str, str | bool],
191245
options: dict[str, str | None],
192-
) -> dict[str, object]:
193-
"""Recognize options of Documenter from user input."""
246+
) -> _AutoDocumenterOptions:
247+
"""Recognize options of object type from user input."""
248+
option_spec = _OPTION_SPECS[obj_type]
194249
for name in AUTODOC_DEFAULT_OPTIONS:
195250
if name not in option_spec:
196251
continue
@@ -210,4 +265,5 @@ def _process_documenter_options(
210265
# remove '+' from option argument if there's nothing to merge it with
211266
options[name] = opt_value.removeprefix('+')
212267

213-
return assemble_option_dict(options.items(), option_spec) # type: ignore[arg-type]
268+
opts = assemble_option_dict(options.items(), option_spec) # type: ignore[arg-type]
269+
return _AutoDocumenterOptions.from_directive_options(opts)

sphinx/ext/autodoc/_docstrings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def _get_doc(
297297

298298
if props.obj_type not in {'module', 'data'} and _new_docstrings is not None:
299299
# docstring already returned previously, then modified due to
300-
# ``Documenter._find_signature()``. Just return the
300+
# ``_extract_signatures_from_docstring()``. Just return the
301301
# previously-computed result, so that we don't lose the processing.
302302
return _new_docstrings
303303

sphinx/ext/autodoc/_documenters.py

Lines changed: 0 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,5 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING
4-
5-
from sphinx.ext.autodoc._directive_options import (
6-
annotation_option,
7-
bool_option,
8-
class_doc_from_option,
9-
exclude_members_option,
10-
identity,
11-
inherited_members_option,
12-
member_order_option,
13-
members_option,
14-
)
15-
16-
if TYPE_CHECKING:
17-
from typing import ClassVar
18-
19-
from sphinx.ext.autodoc._property_types import (
20-
_AssignStatementProperties,
21-
_ClassDefProperties,
22-
_FunctionDefProperties,
23-
_ItemProperties,
24-
_ModuleProperties,
25-
_TypeStatementProperties,
26-
)
27-
from sphinx.util.typing import OptionSpec
28-
293

304
class Documenter:
315
"""A Documenter knows how to autodocument a single object type. When
@@ -41,144 +15,3 @@ class Documenter:
4115
in fact, it will be used to parse an auto directive's options that matches
4216
the Documenter.
4317
"""
44-
45-
props: _ItemProperties
46-
47-
#: name by which the directive is called (auto...) and the default
48-
#: generated directive name
49-
objtype: ClassVar = 'object'
50-
#: true if the generated content may contain titles
51-
titles_allowed: ClassVar = True
52-
53-
option_spec: ClassVar[OptionSpec] = {
54-
'no-index': bool_option,
55-
'no-index-entry': bool_option,
56-
'noindex': bool_option,
57-
}
58-
59-
60-
class ModuleDocumenter(Documenter):
61-
"""Specialized Documenter subclass for modules."""
62-
63-
props: _ModuleProperties
64-
65-
objtype = 'module'
66-
67-
option_spec: ClassVar[OptionSpec] = {
68-
'members': members_option,
69-
'undoc-members': bool_option,
70-
'no-index': bool_option,
71-
'no-index-entry': bool_option,
72-
'inherited-members': inherited_members_option,
73-
'show-inheritance': bool_option,
74-
'synopsis': identity,
75-
'platform': identity,
76-
'deprecated': bool_option,
77-
'member-order': member_order_option,
78-
'exclude-members': exclude_members_option,
79-
'private-members': members_option,
80-
'special-members': members_option,
81-
'imported-members': bool_option,
82-
'ignore-module-all': bool_option,
83-
'no-value': bool_option,
84-
'noindex': bool_option,
85-
}
86-
87-
88-
class FunctionDocumenter(Documenter):
89-
"""Specialized Documenter subclass for functions."""
90-
91-
props: _FunctionDefProperties
92-
93-
objtype = 'function'
94-
95-
96-
class DecoratorDocumenter(FunctionDocumenter):
97-
"""Specialized Documenter subclass for decorator functions."""
98-
99-
props: _FunctionDefProperties
100-
101-
objtype = 'decorator'
102-
103-
104-
class ClassDocumenter(Documenter):
105-
"""Specialized Documenter subclass for classes."""
106-
107-
props: _ClassDefProperties
108-
109-
objtype = 'class'
110-
option_spec: ClassVar[OptionSpec] = {
111-
'members': members_option,
112-
'undoc-members': bool_option,
113-
'no-index': bool_option,
114-
'no-index-entry': bool_option,
115-
'inherited-members': inherited_members_option,
116-
'show-inheritance': bool_option,
117-
'member-order': member_order_option,
118-
'exclude-members': exclude_members_option,
119-
'private-members': members_option,
120-
'special-members': members_option,
121-
'class-doc-from': class_doc_from_option,
122-
'noindex': bool_option,
123-
}
124-
125-
126-
class ExceptionDocumenter(ClassDocumenter):
127-
"""Specialized ClassDocumenter subclass for exceptions."""
128-
129-
props: _ClassDefProperties
130-
131-
objtype = 'exception'
132-
133-
134-
class DataDocumenter(Documenter):
135-
"""Specialized Documenter subclass for data items."""
136-
137-
props: _AssignStatementProperties
138-
139-
objtype = 'data'
140-
option_spec: ClassVar[OptionSpec] = dict(Documenter.option_spec)
141-
option_spec['annotation'] = annotation_option
142-
option_spec['no-value'] = bool_option
143-
144-
145-
class MethodDocumenter(Documenter):
146-
"""Specialized Documenter subclass for methods (normal, static and class)."""
147-
148-
props: _FunctionDefProperties
149-
150-
objtype = 'method'
151-
directivetype = 'method'
152-
153-
154-
class AttributeDocumenter(Documenter):
155-
"""Specialized Documenter subclass for attributes."""
156-
157-
props: _AssignStatementProperties
158-
159-
objtype = 'attribute'
160-
option_spec: ClassVar[OptionSpec] = dict(Documenter.option_spec)
161-
option_spec['annotation'] = annotation_option
162-
option_spec['no-value'] = bool_option
163-
164-
165-
class PropertyDocumenter(Documenter):
166-
"""Specialized Documenter subclass for properties."""
167-
168-
props: _FunctionDefProperties
169-
170-
objtype = 'property'
171-
172-
173-
class TypeAliasDocumenter(Documenter):
174-
"""Specialized Documenter subclass for type aliases."""
175-
176-
props: _TypeStatementProperties
177-
178-
objtype = 'type'
179-
option_spec: ClassVar[OptionSpec] = {
180-
'no-index': bool_option,
181-
'no-index-entry': bool_option,
182-
'annotation': annotation_option,
183-
'no-value': bool_option,
184-
}

sphinx/ext/autodoc/_member_finder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
class ObjectMember:
5353
"""A member of object.
5454
55-
This is used for the result of `Documenter.get_module_members()` to
55+
This is used for the result of `_get_members_to_document()` to
5656
represent each member of the object.
5757
"""
5858

@@ -152,7 +152,7 @@ def _gather_members(
152152
# document non-skipped members
153153
member_documenters: list[tuple[_ItemProperties, bool, str]] = []
154154
for member_name, member, is_attr in filtered_members:
155-
# prefer the documenter with the highest priority
155+
# prefer the object type with the highest priority
156156
obj_type = _best_object_type_for_member(
157157
member=member,
158158
member_name=member_name,

0 commit comments

Comments
 (0)