Skip to content

Commit 183ea89

Browse files
committed
rebase sage_autodoc to sphinx 8.1.3
1 parent 209ae4c commit 183ea89

File tree

1 file changed

+60
-27
lines changed

1 file changed

+60
-27
lines changed

src/sage_docbuild/ext/sage_autodoc.py

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
- François Bissey (2024-08-24): rebased on Sphinx 8.0.2
3636
3737
- François Bissey (2024-09-10): Tweaks to support python 3.9 (and older sphinx) as well
38+
39+
- François Bissey (2024-11-12): rebased on Sphinx 8.1.3 (while trying to keep python 3.9 compatibility)
3840
"""
3941

4042
from __future__ import annotations
@@ -44,7 +46,7 @@
4446
import sys
4547
import re
4648
from inspect import Parameter, Signature
47-
from typing import TYPE_CHECKING, Any, ClassVar, NewType, TypeVar
49+
from typing import TYPE_CHECKING, Any, NewType, TypeVar
4850

4951
from docutils.statemachine import StringList
5052

@@ -86,11 +88,19 @@ def getdoc(obj, *args, **kwargs):
8688
if TYPE_CHECKING:
8789
from collections.abc import Callable, Iterator, Sequence
8890
from types import ModuleType
91+
from typing import ClassVar, Literal, TypeAlias
8992

9093
from sphinx.application import Sphinx
9194
from sphinx.environment import BuildEnvironment
9295
from sphinx.ext.autodoc.directive import DocumenterBridge
9396

97+
_AutodocObjType = Literal[
98+
'module', 'class', 'exception', 'function', 'method', 'attribute'
99+
]
100+
_AutodocProcessDocstringListener: TypeAlias = Callable[
101+
[Sphinx, _AutodocObjType, str, Any, dict[str, bool], list[str]], None
102+
]
103+
94104
logger = logging.getLogger(__name__)
95105

96106

@@ -225,15 +235,17 @@ def merge_members_option(options: dict) -> None:
225235

226236
# Some useful event listener factories for autodoc-process-docstring.
227237

228-
def cut_lines(pre: int, post: int = 0, what: str | None = None) -> Callable:
238+
def cut_lines(
239+
pre: int, post: int = 0, what: Sequence[str] | None = None
240+
) -> _AutodocProcessDocstringListener:
229241
"""Return a listener that removes the first *pre* and last *post*
230242
lines of every docstring. If *what* is a sequence of strings,
231243
only docstrings of a type in *what* will be processed.
232244
233245
Use like this (e.g. in the ``setup()`` function of :file:`conf.py`)::
234246
235247
from sphinx.ext.autodoc import cut_lines
236-
app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
248+
app.connect('autodoc-process-docstring', cut_lines(4, what={'module'}))
237249
238250
This can (and should) be used in place of ``automodule_skip_lines``.
239251
"""
@@ -250,9 +262,22 @@ def cut_lines(pre: int, post: int = 0, what: str | None = None) -> Callable:
250262
#
251263
# ... in place of ``automodule_skip_lines``.
252264
# -------------------------------------------------------------------------
253-
def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: list[str],
254-
) -> None:
255-
if what and what_ not in what:
265+
if not what:
266+
what_unique: frozenset[str] = frozenset()
267+
elif isinstance(what, str): # strongly discouraged
268+
what_unique = frozenset({what})
269+
else:
270+
what_unique = frozenset(what)
271+
272+
def process(
273+
app: Sphinx,
274+
what_: _AutodocObjType,
275+
name: str,
276+
obj: Any,
277+
options: dict[str, bool],
278+
lines: list[str],
279+
) -> None:
280+
if what_unique and what_ not in what_unique:
256281
return
257282
del lines[:pre]
258283
if post:
@@ -271,7 +296,7 @@ def between(
271296
what: Sequence[str] | None = None,
272297
keepempty: bool = False,
273298
exclude: bool = False,
274-
) -> Callable:
299+
) -> _AutodocProcessDocstringListener:
275300
"""Return a listener that either keeps, or if *exclude* is True excludes,
276301
lines between lines that match the *marker* regular expression. If no line
277302
matches, the resulting docstring would be empty, so no change will be made
@@ -282,8 +307,14 @@ def between(
282307
"""
283308
marker_re = re.compile(marker)
284309

285-
def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: list[str],
286-
) -> None:
310+
def process(
311+
app: Sphinx,
312+
what_: _AutodocObjType,
313+
name: str,
314+
obj: Any,
315+
options: dict[str, bool],
316+
lines: list[str],
317+
) -> None:
287318
if what and what_ not in what:
288319
return
289320
deleted = 0
@@ -308,7 +339,7 @@ def process(app: Sphinx, what_: str, name: str, obj: Any, options: Any, lines: l
308339

309340
# This class is used only in ``sphinx.ext.autodoc.directive``,
310341
# But we define this class here to keep compatibility (see #4538)
311-
class Options(dict):
342+
class Options(dict[str, Any]):
312343
"""A dict/attribute hybrid that returns None on nonexisting keys."""
313344

314345
def copy(self) -> Options:
@@ -476,9 +507,10 @@ def import_object(self, raiseerror: bool = False) -> bool:
476507
"""
477508
with mock(self.config.autodoc_mock_imports):
478509
try:
479-
ret = import_object(self.modname, self.objpath, self.objtype,
480-
attrgetter=self.get_attr,
481-
warningiserror=self.config.autodoc_warningiserror)
510+
ret = import_object(
511+
self.modname, self.objpath, self.objtype,
512+
attrgetter=self.get_attr,
513+
)
482514
self.module, self.parent, self.object_name, self.object = ret
483515
if ismock(self.object):
484516
self.object = undecorate(self.object)
@@ -1145,7 +1177,8 @@ def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]:
11451177
else:
11461178
logger.warning(__('missing attribute mentioned in :members: option: '
11471179
'module %s, attribute %s'),
1148-
safe_getattr(self.object, '__name__', '???', name),
1180+
safe_getattr(self.object, '__name__', '???'),
1181+
name,
11491182
type='autodoc')
11501183
return False, ret
11511184

@@ -2179,7 +2212,7 @@ def import_object(self, raiseerror: bool = False) -> bool:
21792212
# annotation only instance variable (PEP-526)
21802213
try:
21812214
with mock(self.config.autodoc_mock_imports):
2182-
parent = import_module(self.modname, self.config.autodoc_warningiserror)
2215+
parent = import_module(self.modname)
21832216
annotations = get_type_hints(parent, None,
21842217
self.config.autodoc_type_aliases,
21852218
include_extras=True)
@@ -2629,9 +2662,10 @@ def import_object(self, raiseerror: bool = False) -> bool:
26292662
except ImportError as exc:
26302663
try:
26312664
with mock(self.config.autodoc_mock_imports):
2632-
ret = import_object(self.modname, self.objpath[:-1], 'class',
2633-
attrgetter=self.get_attr, # type: ignore[attr-defined]
2634-
warningiserror=self.config.autodoc_warningiserror)
2665+
ret = import_object(
2666+
self.modname, self.objpath[:-1], 'class',
2667+
attrgetter=self.get_attr, # type: ignore[attr-defined]
2668+
)
26352669
parent = ret[3]
26362670
if self.is_runtime_instance_attribute(parent):
26372671
self.object = self.RUNTIME_INSTANCE_ATTRIBUTE
@@ -2676,16 +2710,17 @@ def is_uninitialized_instance_attribute(self, parent: Any) -> bool:
26762710
return self.objpath[-1] in annotations
26772711

26782712
def import_object(self, raiseerror: bool = False) -> bool:
2679-
"""Check the exisitence of uninitialized instance attribute when failed to import
2713+
"""Check the existence of uninitialized instance attribute when failed to import
26802714
the attribute.
26812715
"""
26822716
try:
26832717
return super().import_object(raiseerror=True) # type: ignore[misc]
26842718
except ImportError as exc:
26852719
try:
2686-
ret = import_object(self.modname, self.objpath[:-1], 'class',
2687-
attrgetter=self.get_attr, # type: ignore[attr-defined]
2688-
warningiserror=self.config.autodoc_warningiserror)
2720+
ret = import_object(
2721+
self.modname, self.objpath[:-1], 'class',
2722+
attrgetter=self.get_attr, # type: ignore[attr-defined]
2723+
)
26892724
parent = ret[3]
26902725
if self.is_uninitialized_instance_attribute(parent):
26912726
self.object = UNINITIALIZED_ATTR
@@ -2760,9 +2795,7 @@ def can_document_member(
27602795
if isinstance(type(member), ClasscallMetaclass):
27612796
return True
27622797
# ---------------------------------------------------------------------
2763-
if not inspect.isroutine(member) and not isinstance(member, type):
2764-
return True
2765-
return False
2798+
return not inspect.isroutine(member) and not isinstance(member, type)
27662799

27672800
def document_members(self, all_members: bool = False) -> None:
27682801
pass
@@ -2918,7 +2951,7 @@ def can_document_member(
29182951
return False
29192952

29202953
def import_object(self, raiseerror: bool = False) -> bool:
2921-
"""Check the exisitence of uninitialized instance attribute when failed to import
2954+
"""Check the existence of uninitialized instance attribute when failed to import
29222955
the attribute.
29232956
"""
29242957
ret = super().import_object(raiseerror)
@@ -2991,7 +3024,7 @@ def _get_property_getter(self) -> Callable | None:
29913024

29923025
def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any:
29933026
"""Alternative getattr() for types"""
2994-
for typ, func in app.registry.autodoc_attrgettrs.items():
3027+
for typ, func in app.registry.autodoc_attrgetters.items():
29953028
if isinstance(obj, typ):
29963029
return func(obj, name, *defargs)
29973030

0 commit comments

Comments
 (0)