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
4042from __future__ import annotations
4446import sys
4547import re
4648from inspect import Parameter , Signature
47- from typing import TYPE_CHECKING , Any , ClassVar , NewType , TypeVar
49+ from typing import TYPE_CHECKING , Any , NewType , TypeVar
4850
4951from docutils .statemachine import StringList
5052
@@ -86,11 +88,19 @@ def getdoc(obj, *args, **kwargs):
8688if 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+
94104logger = 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
29923025def 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