Close #3014: autodoc: Add autodoc-process-bases

Add `autodoc-process-bases` to modify the base classes of the class
definitions.  This allows the extensions to insert or modify the list
of the base classes via event-handlers.
This commit is contained in:
Takeshi KOMIYA 2021-05-16 00:35:03 +09:00
parent 1513d50774
commit 67db20d705
4 changed files with 72 additions and 7 deletions

View File

@ -28,6 +28,8 @@ Features added
* #9195: autodoc: The arguments of ``typing.Literal`` are wrongly rendered
* #9185: autodoc: :confval:`autodoc_typehints` allows ``'both'`` setting to
allow typehints to be included both in the signature and description
* #3014: autodoc: Add :event:`autodoc-process-bases` to modify the base classes
of the class definitions
* #3257: autosummary: Support instance attributes for classes
* #9129: html search: Show search summaries when html_copy_source = False
* #9120: html theme: Eliminate prompt characters of code-block from copyable

View File

@ -749,6 +749,21 @@ needed docstring processing in event :event:`autodoc-process-docstring`:
.. autofunction:: cut_lines
.. autofunction:: between
.. event:: autodoc-process-bases (app, name, obj, options, bases)
.. versionadded:: 4.1
Emitted when autodoc has read and processed a class to determine the
base-classes. *bases* is a list of classes that the event handler can
modify **in place** to change what Sphinx puts into the output. It's
emitted only if ``show-inheritance`` option given.
:param app: the Sphinx application object
:param name: the fully qualified name of the object
:param obj: the object itself
:param options: the options given to the class directive
:param bases: the list of base classes signature. see above.
Skipping members
----------------

View File

@ -1626,18 +1626,23 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
# add inheritance info, if wanted
if not self.doc_as_attr and self.options.show_inheritance:
sourcename = self.get_sourcename()
self.add_line('', sourcename)
if hasattr(self.object, '__orig_bases__') and len(self.object.__orig_bases__):
# A subclass of generic types
# refs: PEP-560 <https://www.python.org/dev/peps/pep-0560/>
bases = [restify(cls) for cls in self.object.__orig_bases__]
self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename)
bases = list(self.object.__orig_bases__)
elif hasattr(self.object, '__bases__') and len(self.object.__bases__):
# A normal class
bases = [restify(cls) for cls in self.object.__bases__]
self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename)
bases = list(self.object.__bases__)
else:
bases = []
self.env.events.emit('autodoc-process-bases',
self.fullname, self.object, self.options, bases)
base_classes = [restify(cls) for cls in bases]
sourcename = self.get_sourcename()
self.add_line('', sourcename)
self.add_line(' ' + _('Bases: %s') % ', '.join(base_classes), sourcename)
def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:
members = get_class_members(self.object, self.objpath, self.get_attr)
@ -2676,6 +2681,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_event('autodoc-process-docstring')
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')
app.add_event('autodoc-process-bases')
app.connect('config-inited', migrate_autodoc_member_order, priority=800)

View File

@ -10,6 +10,7 @@
"""
import sys
from typing import List, Union
import pytest
@ -264,6 +265,47 @@ def test_show_inheritance_for_subclass_of_generic_type(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_process_bases(app):
def autodoc_process_bases(app, name, obj, options, bases):
assert name == 'target.classes.Quux'
assert obj.__module__ == 'target.classes'
assert obj.__name__ == 'Quux'
assert options == {'show-inheritance': True,
'members': []}
assert bases == [List[Union[int, float]]]
bases.pop()
bases.extend([int, str])
app.connect('autodoc-process-bases', autodoc_process_bases)
options = {'show-inheritance': None}
actual = do_autodoc(app, 'class', 'target.classes.Quux', options)
if sys.version_info < (3, 7):
assert list(actual) == [
'',
'.. py:class:: Quux(*args, **kwds)',
' :module: target.classes',
'',
' Bases: :class:`int`, :class:`str`',
'',
' A subclass of List[Union[int, float]]',
'',
]
else:
assert list(actual) == [
'',
'.. py:class:: Quux(iterable=(), /)',
' :module: target.classes',
'',
' Bases: :class:`int`, :class:`str`',
'',
' A subclass of List[Union[int, float]]',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_class_doc_from_class(app):
options = {"members": None,