diff --git a/CHANGES b/CHANGES index d27b6cd07..10bf627fb 100644 --- a/CHANGES +++ b/CHANGES @@ -58,6 +58,8 @@ Bugs fixed declarations. * C++, suppress warnings for directly dependent typenames in cross references generated automatically in signatures. +* #5637: autodoc: Incorrect handling of nested class names on show-inheritance +* #5637: inheritance_diagram: Incorrect handling of nested class names Testing -------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index b9404804b..ae56cb183 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1146,7 +1146,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if hasattr(self.object, '__bases__') and len(self.object.__bases__): bases = [':class:`%s`' % b.__name__ if b.__module__ in ('__builtin__', 'builtins') - else ':class:`%s.%s`' % (b.__module__, b.__name__) + else ':class:`%s.%s`' % (b.__module__, b.__qualname__) for b in self.object.__bases__] self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 83e277523..db2a15b14 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -229,7 +229,7 @@ class InheritanceGraph: if module in ('__builtin__', 'builtins'): fullname = cls.__name__ else: - fullname = '%s.%s' % (module, cls.__name__) + fullname = '%s.%s' % (module, cls.__qualname__) if parts == 0: result = fullname else: diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py index f6970a36c..e28eeef8a 100644 --- a/tests/roots/test-ext-autodoc/target/__init__.py +++ b/tests/roots/test-ext-autodoc/target/__init__.py @@ -110,6 +110,10 @@ class Outer(object): factory = dict +class InnerChild(Outer.Inner): + """InnerChild docstring""" + + class DocstringSig(object): def meth(self): """meth(FOO, BAR=1) -> BAZ diff --git a/tests/roots/test-inheritance/diagram_w_nested_classes.rst b/tests/roots/test-inheritance/diagram_w_nested_classes.rst new file mode 100644 index 000000000..7fa02175f --- /dev/null +++ b/tests/roots/test-inheritance/diagram_w_nested_classes.rst @@ -0,0 +1,5 @@ +Diagram with Nested Classes +=========================== + +.. inheritance-diagram:: + dummy.test_nested diff --git a/tests/roots/test-inheritance/dummy/test_nested.py b/tests/roots/test-inheritance/dummy/test_nested.py new file mode 100644 index 000000000..1e732aab5 --- /dev/null +++ b/tests/roots/test-inheritance/dummy/test_nested.py @@ -0,0 +1,12 @@ +""" + Test with nested classes. +""" + + +class A(object): + class B(object): + pass + + +class C(A.B): + pass diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 52e9bf5c5..e6b4cc5b6 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -685,6 +685,7 @@ def test_autodoc_ignore_module_all(app): assert list(filter(lambda l: 'class::' in l, actual)) == [ '.. py:class:: Class(arg)', '.. py:class:: CustomDict', + '.. py:class:: InnerChild', '.. py:class:: InstAttCls()', '.. py:class:: Outer', ' .. py:class:: Outer.Inner', @@ -775,6 +776,18 @@ def test_autodoc_inner_class(app): ' ', ] + options['show-inheritance'] = True + actual = do_autodoc(app, 'class', 'target.InnerChild', options) + assert list(actual) == [ + '', + '.. py:class:: InnerChild', + ' :module: target', '', + ' Bases: :class:`target.Outer.Inner`', + '', + ' InnerChild docstring', + ' ' + ] + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_classmethod(app): diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py index baeaa401e..3125f2c6e 100644 --- a/tests/test_ext_inheritance_diagram.py +++ b/tests/test_ext_inheritance_diagram.py @@ -132,6 +132,14 @@ def test_inheritance_diagram(app, status, warning): ('dummy.test.A', 'dummy.test.A', [], None), ] + # inheritance diagram involving a base class nested within another class + for cls in graphs['diagram_w_nested_classes'].class_info: + assert cls in [ + ('dummy.test_nested.A', 'dummy.test_nested.A', [], None), + ('dummy.test_nested.C', 'dummy.test_nested.C', ['dummy.test_nested.A.B'], None), + ('dummy.test_nested.A.B', 'dummy.test_nested.A.B', [], None) + ] + @pytest.mark.sphinx('html', testroot='ext-inheritance_diagram') @pytest.mark.usefixtures('if_graphviz_found')