Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ Contributors
* Tim Hoffmann -- theme improvements
* Tim Pillinger -- documentation improvements
* Valentin Heinisch -- warning types improvement
* Vedant Kumar -- autodoc fixes
* Victor Wheeler -- documentation improvements
* Vince Salvino -- JavaScript search improvements
* Will Maier -- directory HTML builder
Expand Down
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ Bugs fixed
English stemmer) and Dutch (which uses the Dutch Porter stemmer).
Patch by Hugo van Kemenade

* #14576: autodoc: Fix an :py:exc:`IndexError` when an
``autodoc-process-signature`` event handler returns a signature
for a data object.
Patch by Vedant Kumar.


Release 9.1.0 (released Dec 31, 2025)
=====================================
Expand Down
9 changes: 8 additions & 1 deletion sphinx/ext/autodoc/_dynamic/_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ def _format_signatures(
):
if len(result) == 2 and isinstance(result[0], str):
args, retann = result
signatures[0] = (args, retann if isinstance(retann, str) else '')
replacement = (args, retann if isinstance(retann, str) else '')
if signatures:
signatures[0] = replacement
else:
# No signature was introspected (e.g. for data objects),
# but an event handler returned a replacement signature.
# See: https://github.com/sphinx-doc/sphinx/issues/14576
signatures.append(replacement)

if props.obj_type in {'module', 'data', 'type'}:
signatures[1:] = () # discard all signatures save the first
Expand Down
53 changes: 53 additions & 0 deletions tests/test_ext_autodoc/test_ext_autodoc_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,56 @@ def func(x: int, y: int) -> int: # type: ignore[empty-body]
assert captured == [
(app, 'function', '.func', func, options, '(x: int, y: int)', 'int')
]


def test_autodoc_process_signature_data_object() -> None:
# https://github.com/sphinx-doc/sphinx/issues/14576
# No signature is introspected for data objects, but a handler for
# ``autodoc-process-signature`` may still return a replacement
# signature; this must not raise an IndexError.
from sphinx.ext.autodoc._property_types import _AssignStatementProperties

def process_signature(*args: Any) -> tuple[str, str | None]:
return '()', None

events = FakeEvents()
events.connect('autodoc-process-signature', process_signature)

class SigBug:
class_var: Any

def __call__(self) -> None:
pass

sig_bug = SigBug()

props = _AssignStatementProperties(
obj_type='data',
module_name='',
parts=('sig_bug',),
docstring_lines=(),
value=sig_bug,
annotation='',
class_var=False,
instance_var=False,
_obj=sig_bug,
_obj___module__=None,
_obj_is_generic_alias=False,
_obj_is_attribute_descriptor=False,
_obj_is_mock=False,
_obj_is_sentinel=None,
_obj_repr_rst='',
_obj_type_annotation=None,
)

signatures = _format_signatures(
autodoc_annotations={},
config=_AutodocConfig(),
docstrings=None,
events=events,
get_attr=safe_getattr,
options=_AutoDocumenterOptions(),
parent=None,
props=props,
)
assert signatures == [('()', '')]
Loading