Skip to content

Commit 2502bfc

Browse files
authored
autodoc: Improve type hints for events (#14126)
1 parent 03c66f5 commit 2502bfc

File tree

10 files changed

+118
-48
lines changed

10 files changed

+118
-48
lines changed

doc/conf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@
188188
# sphinx.application.Sphinx.connect
189189
('py:class', '_AutodocProcessDocstringListener'),
190190
# sphinx.application.Sphinx.connect
191+
('py:class', '_AutodocBeforeProcessSignatureListener'),
192+
# sphinx.application.Sphinx.connect
191193
('py:class', '_AutodocProcessSignatureListener'),
194+
('py:class', '_AutodocProcessBasesListener'), # sphinx.application.Sphinx.connect
192195
('py:class', '_AutodocSkipMemberListener'), # sphinx.application.Sphinx.connect
193196
('py:class', '_ConfigRebuild'), # sphinx.application.Sphinx.add_config_value
194197
# sphinx.application.Sphinx.add_html_math_renderer

doc/usage/extensions/autodoc.rst

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,7 @@ Docstring preprocessing
13781378

13791379
autodoc provides the following additional events:
13801380

1381-
.. event:: autodoc-process-docstring (app, what, name, obj, options, lines)
1381+
.. event:: autodoc-process-docstring (app, obj_type, name, obj, options, lines)
13821382

13831383
.. versionadded:: 0.4
13841384

@@ -1387,9 +1387,9 @@ autodoc provides the following additional events:
13871387
can modify **in place** to change what Sphinx puts into the output.
13881388

13891389
:param app: the Sphinx application object
1390-
:param what: the type of the object which the docstring belongs to (one of
1391-
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'method'``,
1392-
``'attribute'``)
1390+
:param obj_type: the type of the object which the docstring belongs to (one of
1391+
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'decorator'``,
1392+
``'method'``, ``'property'``, ``'attribute'``, ``'data'``, or ``'type'``)
13931393
:param name: the fully qualified name of the object
13941394
:param obj: the object itself
13951395
:param options: the options given to the directive: an object with attributes
@@ -1409,7 +1409,7 @@ autodoc provides the following additional events:
14091409
:param obj: the object itself
14101410
:param bound_method: a boolean indicates an object is bound method or not
14111411

1412-
.. event:: autodoc-process-signature (app, what, name, obj, options, signature, return_annotation)
1412+
.. event:: autodoc-process-signature (app, obj_type, name, obj, options, signature, return_annotation)
14131413

14141414
.. versionadded:: 0.5
14151415

@@ -1418,9 +1418,9 @@ autodoc provides the following additional events:
14181418
what Sphinx puts into the output.
14191419

14201420
:param app: the Sphinx application object
1421-
:param what: the type of the object which the docstring belongs to (one of
1422-
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'method'``,
1423-
``'attribute'``)
1421+
:param obj_type: the type of the object which the docstring belongs to (one of
1422+
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'decorator'``,
1423+
``'method'``, ``'property'``, ``'attribute'``, ``'data'``, or ``'type'``)
14241424
:param name: the fully qualified name of the object
14251425
:param obj: the object itself
14261426
:param options: the options given to the directive: an object with attributes
@@ -1439,17 +1439,17 @@ needed docstring processing in event :event:`autodoc-process-docstring`:
14391439
.. autofunction:: cut_lines
14401440
.. autofunction:: between
14411441

1442-
.. event:: autodoc-process-bases (app, name, obj, options, bases)
1442+
.. event:: autodoc-process-bases (app, name, obj, _unused, bases)
14431443

14441444
Emitted when autodoc has read and processed a class to determine the
14451445
base-classes. *bases* is a list of classes that the event handler can
14461446
modify **in place** to change what Sphinx puts into the output. It's
1447-
emitted only if ``show-inheritance`` option given.
1447+
emitted only if the ``show-inheritance`` option is given.
14481448

14491449
:param app: the Sphinx application object
14501450
:param name: the fully qualified name of the object
14511451
:param obj: the object itself
1452-
:param options: the options given to the class directive
1452+
:param _unused: unused placeholder
14531453
:param bases: the list of base classes signature. see above.
14541454

14551455
.. versionadded:: 4.1
@@ -1465,7 +1465,7 @@ Skipping members
14651465
autodoc allows the user to define a custom method for determining whether a
14661466
member should be included in the documentation by using the following event:
14671467

1468-
.. event:: autodoc-skip-member (app, what, name, obj, skip, options)
1468+
.. event:: autodoc-skip-member (app, obj_type, name, obj, skip, options)
14691469

14701470
.. versionadded:: 0.5
14711471

@@ -1479,9 +1479,9 @@ member should be included in the documentation by using the following event:
14791479
autodoc and other enabled extensions.
14801480

14811481
:param app: the Sphinx application object
1482-
:param what: the type of the object which the docstring belongs to (one of
1483-
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'method'``,
1484-
``'attribute'``)
1482+
:param obj_type: the type of the object which the docstring belongs to (one of
1483+
``'module'``, ``'class'``, ``'exception'``, ``'function'``, ``'decorator'``,
1484+
``'method'``, ``'property'``, ``'attribute'``, ``'data'``, or ``'type'``)
14851485
:param name: the fully qualified name of the object
14861486
:param obj: the object itself
14871487
:param skip: a boolean indicating if autodoc will skip this member if the

sphinx/application.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
from sphinx.domains import Domain, Index
5454
from sphinx.environment.collectors import EnvironmentCollector
5555
from sphinx.ext.autodoc._event_listeners import (
56+
_AutodocBeforeProcessSignatureListener,
57+
_AutodocProcessBasesListener,
5658
_AutodocProcessDocstringListener,
5759
_AutodocProcessSignatureListener,
5860
_AutodocSkipMemberListener,
@@ -721,7 +723,7 @@ def connect(
721723
def connect(
722724
self,
723725
event: Literal['autodoc-before-process-signature'],
724-
callback: Callable[[Sphinx, Any, bool], None],
726+
callback: _AutodocBeforeProcessSignatureListener,
725727
priority: int = 500,
726728
) -> int: ...
727729

@@ -737,7 +739,7 @@ def connect(
737739
def connect(
738740
self,
739741
event: Literal['autodoc-process-bases'],
740-
callback: Callable[[Sphinx, str, Any, dict[str, bool], list[str]], None],
742+
callback: _AutodocProcessBasesListener,
741743
priority: int = 500,
742744
) -> int: ...
743745

sphinx/events.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
from sphinx.domains import Domain
3030
from sphinx.environment import BuildEnvironment
3131
from sphinx.ext.autodoc._event_listeners import (
32+
_AutodocBeforeProcessSignatureListener,
33+
_AutodocProcessBasesListener,
3234
_AutodocProcessDocstringListener,
3335
_AutodocProcessSignatureListener,
3436
_AutodocSkipMemberListener,
@@ -293,7 +295,7 @@ def connect(
293295
def connect(
294296
self,
295297
name: Literal['autodoc-before-process-signature'],
296-
callback: Callable[[Sphinx, Any, bool], None],
298+
callback: _AutodocBeforeProcessSignatureListener,
297299
priority: int,
298300
) -> int: ...
299301

@@ -309,7 +311,7 @@ def connect(
309311
def connect(
310312
self,
311313
name: Literal['autodoc-process-bases'],
312-
callback: Callable[[Sphinx, str, Any, dict[str, bool], list[str]], None],
314+
callback: _AutodocProcessBasesListener,
313315
priority: int,
314316
) -> int: ...
315317

sphinx/ext/autodoc/_dynamic/_member_finder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,16 +485,16 @@ def _filter_members(
485485
# should be skipped
486486
if events is not None:
487487
# let extensions preprocess docstrings
488-
skip_user = events.emit_firstresult(
488+
skip_member = events.emit_firstresult(
489489
'autodoc-skip-member',
490490
props.obj_type,
491491
member_name,
492492
member_obj,
493493
not keep,
494494
options,
495495
)
496-
if skip_user is not None:
497-
keep = not skip_user
496+
if skip_member is not None:
497+
keep = not skip_member
498498

499499
if keep:
500500
# if is_attr is True, the member is documented as an attribute

sphinx/ext/autodoc/_event_listeners.py

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,75 @@
66
from typing import TYPE_CHECKING
77

88
if TYPE_CHECKING:
9-
from collections.abc import Callable, Sequence
10-
from typing import Any, TypeAlias
9+
from collections.abc import Sequence
10+
from typing import Any, Protocol
1111

1212
from sphinx.application import Sphinx
1313
from sphinx.ext.autodoc._property_types import _AutodocObjType
1414

15-
_AutodocProcessDocstringListener: TypeAlias = Callable[
16-
[Sphinx, _AutodocObjType, str, Any, dict[str, bool], list[str]], None
17-
]
18-
_AutodocProcessSignatureListener: TypeAlias = Callable[ # NoQA: PYI047
19-
[Sphinx, _AutodocObjType, str, Any, dict[str, bool], str | None, str | None],
20-
tuple[str | None, str | None] | None,
21-
]
22-
_AutodocSkipMemberListener: TypeAlias = Callable[ # NoQA: PYI047
23-
[Sphinx, _AutodocObjType, str, Any, bool, dict[str, bool]], bool
24-
]
15+
class _AutodocProcessDocstringListener(Protocol):
16+
# parameter names are non-normative
17+
def __call__(
18+
self,
19+
app: Sphinx,
20+
obj_type: _AutodocObjType,
21+
full_name: str,
22+
obj: Any,
23+
options: Any,
24+
docstring_lines: list[str],
25+
/,
26+
) -> None: ...
27+
28+
class _AutodocBeforeProcessSignatureListener(Protocol): # NoQA: PYI046
29+
# parameter names are non-normative
30+
def __call__(
31+
self,
32+
app: Sphinx,
33+
obj: Any,
34+
is_bound_method: bool,
35+
/,
36+
) -> None: ...
37+
38+
class _AutodocProcessSignatureListener(Protocol): # NoQA: PYI046
39+
# parameter names are non-normative
40+
# returns: (args, retann) | None
41+
def __call__(
42+
self,
43+
app: Sphinx,
44+
obj_type: _AutodocObjType,
45+
full_name: str,
46+
obj: Any,
47+
options: Any,
48+
args: str | None,
49+
retann: str | None,
50+
/,
51+
) -> tuple[str | None, str | None] | None: ...
52+
53+
class _AutodocProcessBasesListener(Protocol): # NoQA: PYI046
54+
# parameter names are non-normative
55+
def __call__(
56+
self,
57+
app: Sphinx,
58+
full_name: str,
59+
obj: Any,
60+
_unused: None, # previously: options
61+
obj_bases: list[type],
62+
/,
63+
) -> None: ...
64+
65+
class _AutodocSkipMemberListener(Protocol): # NoQA: PYI046
66+
# parameter names are non-normative
67+
# returns: skip_member
68+
def __call__(
69+
self,
70+
app: Sphinx,
71+
obj_type: _AutodocObjType,
72+
member_name: str,
73+
member_obj: Any,
74+
skip: bool,
75+
options: Any,
76+
/,
77+
) -> bool: ...
2578

2679

2780
def cut_lines(
@@ -51,7 +104,7 @@ def process(
51104
what_: _AutodocObjType,
52105
name: str,
53106
obj: Any,
54-
options: dict[str, bool],
107+
options: Any,
55108
lines: list[str],
56109
) -> None:
57110
if what_unique and what_ not in what_unique:
@@ -90,7 +143,7 @@ def process(
90143
what_: _AutodocObjType,
91144
name: str,
92145
obj: Any,
93-
options: dict[str, bool],
146+
options: Any,
94147
lines: list[str],
95148
) -> None:
96149
if what and what_ not in what:

sphinx/ext/napoleon/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from typing import Any
1616

1717
from sphinx.config import _ConfigRebuild
18+
from sphinx.ext.autodoc._property_types import _AutodocObjType
1819
from sphinx.util.typing import ExtensionMetadata
1920

2021

@@ -362,7 +363,12 @@ def _patch_python_domain() -> None:
362363

363364

364365
def _process_docstring(
365-
app: Sphinx, what: str, name: str, obj: Any, options: Any, lines: list[str]
366+
app: Sphinx,
367+
what: _AutodocObjType,
368+
name: str,
369+
obj: Any,
370+
options: Any,
371+
lines: list[str],
366372
) -> None:
367373
"""Process the docstring for a given python object.
368374
@@ -415,7 +421,7 @@ def _process_docstring(
415421

416422

417423
def _skip_member(
418-
app: Sphinx, what: str, name: str, obj: Any, skip: bool, options: Any
424+
app: Sphinx, what: _AutodocObjType, name: str, obj: Any, skip: bool, options: Any
419425
) -> bool | None:
420426
"""Determine if private and special class members are included in docs.
421427

sphinx/ext/napoleon/docstring.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
if TYPE_CHECKING:
1818
from collections.abc import Callable, Iterator
19+
from typing import Literal
1920

2021
from sphinx.application import Sphinx
2122
from sphinx.config import Config as SphinxConfig
23+
from sphinx.ext.autodoc._property_types import _AutodocObjType
2224

2325
logger = logging.getLogger(__name__)
2426

@@ -328,10 +330,10 @@ def __init__(
328330
docstring: str | list[str],
329331
config: SphinxConfig | None = None,
330332
app: Sphinx | None = None,
331-
what: str = '',
333+
what: _AutodocObjType | Literal['object'] = 'object',
332334
name: str = '',
333-
obj: Any = None,
334-
options: Any = None,
335+
obj: Any | None = None,
336+
options: Any | None = None,
335337
) -> None:
336338
self._app = app
337339
if config:
@@ -343,7 +345,7 @@ def __init__(
343345

344346
self._config = Config() # type: ignore[assignment]
345347

346-
if not what:
348+
if what == 'object':
347349
if inspect.isclass(obj):
348350
what = 'class'
349351
elif inspect.ismodule(obj):
@@ -353,7 +355,7 @@ def __init__(
353355
else:
354356
what = 'object'
355357

356-
self._what = what
358+
self._what: _AutodocObjType | Literal['object'] = what
357359
self._name = name
358360
self._obj = obj
359361
self._opt = options
@@ -1206,10 +1208,10 @@ def __init__(
12061208
docstring: str | list[str],
12071209
config: SphinxConfig | None = None,
12081210
app: Sphinx | None = None,
1209-
what: str = '',
1211+
what: _AutodocObjType | Literal['object'] = 'object',
12101212
name: str = '',
1211-
obj: Any = None,
1212-
options: Any = None,
1213+
obj: Any | None = None,
1214+
options: Any | None = None,
12131215
) -> None:
12141216
self._directive_sections = ['.. index::']
12151217
super().__init__(docstring, config, app, what, name, obj, options)

tests/test_ext_autodoc/test_ext_autodoc_autoclass.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def test_show_inheritance_for_decendants_of_generic_type() -> None:
318318

319319

320320
def _autodoc_process_bases(
321-
app: Sphinx, name: str, obj: Any, options: dict[str, bool], bases: list[type]
321+
app: Sphinx, name: str, obj: Any, options: Any, bases: list[type]
322322
) -> None:
323323
assert name == 'target.classes.Quux'
324324
assert obj.__module__ == 'target.classes'

tests/test_ext_napoleon/test_ext_napoleon.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from collections.abc import Callable
1717
from typing import ParamSpec, TypeVar
1818

19+
from sphinx.ext.autodoc._property_types import _AutodocObjType
20+
1921
_P = ParamSpec('_P')
2022
_R = TypeVar('_R')
2123

@@ -151,7 +153,7 @@ def test_add_config_values(self) -> None:
151153
class TestSkipMember:
152154
def assert_skip(
153155
self,
154-
what: str,
156+
what: _AutodocObjType,
155157
member: str,
156158
obj: object,
157159
expect_default_skip: bool,

0 commit comments

Comments
 (0)