mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Fix #9607: autodoc: Incorrect base class detection
In case of the descendants of generic class, the value of obj.__orig_bases__ is incorrect because it returns original base arguments for the child of the generic class instead of the target class itself. This uses obj.__dict__ to get the correct __orig_bases__ information.
This commit is contained in:
2
CHANGES
2
CHANGES
@@ -21,6 +21,8 @@ Bugs fixed
|
||||
* #9630: autodoc: Failed to build cross references if :confval:`primary_domain`
|
||||
is not 'py'
|
||||
* #9644: autodoc: Crashed on getting source info from problematic object
|
||||
* #9607: autodoc: Incorrect base class detection for the subclasses of the
|
||||
generic class
|
||||
* #9630: autosummary: Failed to build summary table if :confval:`primary_domain`
|
||||
is not 'py'
|
||||
|
||||
|
||||
@@ -1650,7 +1650,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
|
||||
# add inheritance info, if wanted
|
||||
if not self.doc_as_attr and self.options.show_inheritance:
|
||||
if hasattr(self.object, '__orig_bases__') and len(self.object.__orig_bases__):
|
||||
if inspect.getorigbases(self.object):
|
||||
# A subclass of generic types
|
||||
# refs: PEP-560 <https://www.python.org/dev/peps/pep-0560/>
|
||||
bases = list(self.object.__orig_bases__)
|
||||
|
||||
@@ -187,6 +187,21 @@ def getmro(obj: Any) -> Tuple[Type, ...]:
|
||||
return tuple()
|
||||
|
||||
|
||||
def getorigbases(obj: Any) -> Optional[Tuple[Any, ...]]:
|
||||
"""Get __orig_bases__ from *obj* safely."""
|
||||
if not inspect.isclass(obj):
|
||||
return None
|
||||
|
||||
# Get __orig_bases__ from obj.__dict__ to avoid accessing the parent's __orig_bases__.
|
||||
# refs: https://github.com/sphinx-doc/sphinx/issues/9607
|
||||
__dict__ = safe_getattr(obj, '__dict__', {})
|
||||
__orig_bases__ = __dict__.get('__orig_bases__')
|
||||
if isinstance(__orig_bases__, tuple) and len(__orig_bases__) > 0:
|
||||
return __orig_bases__
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def getslots(obj: Any) -> Optional[Dict]:
|
||||
"""Get __slots__ attribute of the class as dict.
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ class Quux(List[Union[int, float]]):
|
||||
pass
|
||||
|
||||
|
||||
class Corge(Quux):
|
||||
pass
|
||||
|
||||
|
||||
Alias = Foo
|
||||
|
||||
#: docstring
|
||||
|
||||
@@ -273,6 +273,21 @@ def test_show_inheritance_for_subclass_of_generic_type(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_show_inheritance_for_decendants_of_generic_type(app):
|
||||
options = {'show-inheritance': None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Corge', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Corge(iterable=(), /)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :py:class:`target.classes.Quux`',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_process_bases(app):
|
||||
def autodoc_process_bases(app, name, obj, options, bases):
|
||||
|
||||
Reference in New Issue
Block a user