Skip to content

Commit

Permalink
Merge pull request #9654 from tk0miya/9607_incorrect_orig_bases
Browse files Browse the repository at this point in the history
Fix #9607: autodoc: Incorrect base class detection
  • Loading branch information
tk0miya committed Sep 26, 2021
2 parents 4a9e015 + d288907 commit f34eb49
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -31,6 +31,8 @@ Bugs fixed
:confval:`autodoc_typehints_description_target` is set to "documented" when
its info-field-list contains ``:returns:`` field
* #9657: autodoc: The base class for a subclass of mocked object is incorrect
* #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'
* #9670: html: Fix download file with special characters
Expand Down
2 changes: 1 addition & 1 deletion sphinx/ext/autodoc/__init__.py
Expand Up @@ -1651,7 +1651,7 @@ def add_directive_header(self, sig: str) -> None:

# 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__)
Expand Down
15 changes: 15 additions & 0 deletions sphinx/util/inspect.py
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions tests/roots/test-ext-autodoc/target/classes.py
Expand Up @@ -29,6 +29,10 @@ class Quux(List[Union[int, float]]):
pass


class Corge(Quux):
pass


Alias = Foo

#: docstring
Expand Down
15 changes: 15 additions & 0 deletions tests/test_ext_autodoc_autoclass.py
Expand Up @@ -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):
Expand Down

0 comments on commit f34eb49

Please sign in to comment.