Skip to content

Commit e281d26

Browse files
authored
Merge remaining special cases into Documenter (#13959)
1 parent 4c89a82 commit e281d26

File tree

2 files changed

+40
-79
lines changed

2 files changed

+40
-79
lines changed

sphinx/ext/autodoc/_documenters.py

Lines changed: 39 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from sphinx.util.typing import AnyTypeAliasType, restify, stringify_annotation
2828

2929
if TYPE_CHECKING:
30-
from collections.abc import Iterator, Sequence
30+
from collections.abc import Iterator
3131
from types import ModuleType
3232
from typing import Any, ClassVar, Literal
3333

@@ -135,6 +135,16 @@ def __init__(
135135

136136
self._load_object_has_been_called = False
137137

138+
if isinstance(self, ModuleDocumenter):
139+
self.options = self.options.merge_member_options()
140+
elif isinstance(self, ClassDocumenter):
141+
if self.config.autodoc_class_signature == 'separated':
142+
# show __init__() method
143+
if self.options.special_members is None:
144+
self.options.special_members = []
145+
self.options.special_members += ['__new__', '__init__']
146+
self.options = self.options.merge_member_options()
147+
138148
@property
139149
def documenters(self) -> dict[str, type[Documenter]]:
140150
"""Returns registered Documenter classes"""
@@ -501,17 +511,33 @@ def sort_members(
501511
# sort by group; alphabetically within groups
502512
documenters.sort(key=lambda e: (e[0].member_order, e[0].name))
503513
elif order == 'bysource':
514+
if (
515+
isinstance(self, ModuleDocumenter)
516+
and not self.options.ignore_module_all
517+
and (module_all := self.props.all)
518+
):
519+
# Sort by __all__
520+
module_all_idx = {name: idx for idx, name in enumerate(module_all)}
521+
module_all_len = len(module_all)
522+
523+
def key_func(entry: tuple[Documenter, bool]) -> int:
524+
fullname = entry[0].name.split('::')[1]
525+
return module_all_idx.get(fullname, module_all_len)
526+
527+
documenters.sort(key=key_func)
528+
504529
# By default, member discovery order matches source order,
505530
# as dicts are insertion-ordered from Python 3.7.
506-
if self.analyzer:
531+
elif self.analyzer is not None:
507532
# sort by source order, by virtue of the module analyzer
508533
tagorder = self.analyzer.tagorder
534+
tagorder_len = len(tagorder)
509535

510-
def keyfunc(entry: tuple[Documenter, bool]) -> int:
536+
def key_func(entry: tuple[Documenter, bool]) -> int:
511537
fullname = entry[0].name.split('::')[1]
512-
return tagorder.get(fullname, len(tagorder))
538+
return tagorder.get(fullname, tagorder_len)
513539

514-
documenters.sort(key=keyfunc)
540+
documenters.sort(key=key_func)
515541
else: # alphabetical
516542
documenters.sort(key=lambda e: e[0].name)
517543

@@ -532,6 +558,14 @@ def generate(
532558
True, only generate if the object is defined in the module name it is
533559
imported from. If *all_members* is True, document all members.
534560
"""
561+
if isinstance(self, ClassDocumenter):
562+
# Do not pass real_modname and use the name from the __module__
563+
# attribute of the class.
564+
# If a class gets imported into the module real_modname
565+
# the analyzer won't find the source of the class, if
566+
# it looks in real_modname.
567+
real_modname = None
568+
535569
if self._load_object_by_name() is None:
536570
return
537571

@@ -759,53 +793,13 @@ class ModuleDocumenter(Documenter):
759793
'noindex': bool_option,
760794
}
761795

762-
def __init__(self, *args: Any) -> None:
763-
super().__init__(*args)
764-
self.options = self.options.merge_member_options()
765-
self.__all__: Sequence[str] | None = None
766-
767796
@classmethod
768797
def can_document_member(
769798
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
770799
) -> bool:
771800
# don't document submodules automatically
772801
return False
773802

774-
def _module_all(self) -> Sequence[str] | None:
775-
if self.__all__ is None and not self.options.ignore_module_all:
776-
self.__all__ = self.props.all
777-
return self.__all__
778-
779-
def sort_members(
780-
self, documenters: list[tuple[Documenter, bool]], order: str
781-
) -> list[tuple[Documenter, bool]]:
782-
module_all = self.props.all
783-
if (
784-
order == 'bysource'
785-
and not self.options.ignore_module_all
786-
and module_all is not None
787-
):
788-
assert module_all is not None
789-
module_all_set = frozenset(module_all)
790-
module_all_len = len(module_all)
791-
792-
# Sort alphabetically first (for members not listed on the __all__)
793-
documenters.sort(key=lambda e: e[0].name)
794-
795-
# Sort by __all__
796-
def keyfunc(entry: tuple[Documenter, bool]) -> int:
797-
name = entry[0].name.split('::')[1]
798-
if name in module_all_set:
799-
return module_all.index(name)
800-
else:
801-
return module_all_len
802-
803-
documenters.sort(key=keyfunc)
804-
805-
return documenters
806-
else:
807-
return super().sort_members(documenters, order)
808-
809803

810804
class FunctionDocumenter(Documenter):
811805
"""Specialized Documenter subclass for functions."""
@@ -865,21 +859,6 @@ class ClassDocumenter(Documenter):
865859
# after Python 3.10.
866860
priority = 15
867861

868-
def __init__(self, *args: Any) -> None:
869-
super().__init__(*args)
870-
871-
if self.config.autodoc_class_signature == 'separated':
872-
self.options = self.options.copy()
873-
874-
# show __init__() method
875-
if self.options.special_members is None:
876-
self.options.special_members = ['__new__', '__init__']
877-
else:
878-
self.options.special_members.append('__new__')
879-
self.options.special_members.append('__init__')
880-
881-
self.options = self.options.merge_member_options()
882-
883862
@classmethod
884863
def can_document_member(
885864
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any
@@ -904,24 +883,6 @@ def get_canonical_fullname(self) -> str | None:
904883
else:
905884
return None
906885

907-
def generate(
908-
self,
909-
more_content: StringList | None = None,
910-
real_modname: str | None = None,
911-
check_module: bool = False,
912-
all_members: bool = False,
913-
) -> None:
914-
# Do not pass real_modname and use the name from the __module__
915-
# attribute of the class.
916-
# If a class gets imported into the module real_modname
917-
# the analyzer won't find the source of the class, if
918-
# it looks in real_modname.
919-
return super().generate(
920-
more_content=more_content,
921-
check_module=check_module,
922-
all_members=all_members,
923-
)
924-
925886

926887
class ExceptionDocumenter(ClassDocumenter):
927888
"""Specialized ClassDocumenter subclass for exceptions."""

sphinx/ext/autodoc/_sentinels.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class _AllTC(enum.Enum):
6464
ALL = enum.auto()
6565

6666
def __contains__(self, item: object) -> Literal[True]: return True
67-
def append(self, item: object) -> None: pass
67+
def __add__(self, other: object) -> Self: pass
6868
ALL_T: TypeAlias = Literal[_AllTC.ALL]
6969
ALL: Final[ALL_T] = _AllTC.ALL
7070

0 commit comments

Comments
 (0)