From 766900e416af3ec9665e0df3260812b1e4d9c72b Mon Sep 17 00:00:00 2001 From: pholica Date: Mon, 3 Feb 2025 02:46:35 +0100 Subject: [PATCH] autodoc: Handle multiple inheritance correctly (#13136) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- CHANGES.rst | 2 ++ sphinx/ext/autodoc/__init__.py | 11 ++++++++++- .../roots/test-ext-autodoc/target/inheritance.py | 8 +++++++- tests/test_extensions/test_ext_autodoc.py | 1 + .../test_ext_autodoc_automodule.py | 16 ++++++++++++++++ .../test_extensions/test_ext_autodoc_configs.py | 12 ++++++++++++ 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 28438131a..e3eaf731f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -134,6 +134,8 @@ Bugs fixed * #12975: Avoid rendering a trailing comma in C and C++ multi-line signatures. * #13178: autodoc: Fix resolution for ``pathlib`` types. Patch by Adam Turner. +* #13136: autodoc: Correctly handle multiple inheritance. + Patch by Pavel Holica Testing ------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 5c2b202b9..eaa0294e6 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -742,10 +742,19 @@ class Documenter: def is_filtered_inherited_member(name: str, obj: Any) -> bool: inherited_members = self.options.inherited_members or set() + seen = set() if inspect.isclass(self.object): for cls in self.object.__mro__: - if cls.__name__ in inherited_members and cls != self.object: + if name in cls.__dict__: + seen.add(cls) + if ( + cls.__name__ in inherited_members + and cls != self.object + and any( + issubclass(potential_child, cls) for potential_child in seen + ) + ): # given member is a member of specified *super class* return True if name in cls.__dict__: diff --git a/tests/roots/test-ext-autodoc/target/inheritance.py b/tests/roots/test-ext-autodoc/target/inheritance.py index 5c65aa65a..a8ddc5b92 100644 --- a/tests/roots/test-ext-autodoc/target/inheritance.py +++ b/tests/roots/test-ext-autodoc/target/inheritance.py @@ -14,7 +14,13 @@ class Base: """Inherited static method.""" -class Derived(Base): +class AnotherBase: + #: docstring + def another_inheritedmeth(self): + """Another inherited function.""" + + +class Derived(Base, AnotherBase): def inheritedmeth(self): # no docstring here pass diff --git a/tests/test_extensions/test_ext_autodoc.py b/tests/test_extensions/test_ext_autodoc.py index b1ba88403..9383401ac 100644 --- a/tests/test_extensions/test_ext_autodoc.py +++ b/tests/test_extensions/test_ext_autodoc.py @@ -831,6 +831,7 @@ def test_autodoc_inherited_members(app): } actual = do_autodoc(app, 'class', 'target.inheritance.Derived', options) assert list(filter(lambda l: 'method::' in l, actual)) == [ + ' .. py:method:: Derived.another_inheritedmeth()', ' .. py:method:: Derived.inheritedclassmeth()', ' .. py:method:: Derived.inheritedmeth()', ' .. py:method:: Derived.inheritedstaticmeth(cls)', diff --git a/tests/test_extensions/test_ext_autodoc_automodule.py b/tests/test_extensions/test_ext_autodoc_automodule.py index c9503a765..c27c7b595 100644 --- a/tests/test_extensions/test_ext_autodoc_automodule.py +++ b/tests/test_extensions/test_ext_autodoc_automodule.py @@ -134,6 +134,16 @@ def test_automodule_inherited_members(app): '.. py:module:: target.inheritance', '', '', + '.. py:class:: AnotherBase()', + ' :module: target.inheritance', + '', + '', + ' .. py:method:: AnotherBase.another_inheritedmeth()', + ' :module: target.inheritance', + '', + ' Another inherited function.', + '', + '', '.. py:class:: Base()', ' :module: target.inheritance', '', @@ -169,6 +179,12 @@ def test_automodule_inherited_members(app): ' :module: target.inheritance', '', '', + ' .. py:method:: Derived.another_inheritedmeth()', + ' :module: target.inheritance', + '', + ' Another inherited function.', + '', + '', ' .. py:method:: Derived.inheritedmeth()', ' :module: target.inheritance', '', diff --git a/tests/test_extensions/test_ext_autodoc_configs.py b/tests/test_extensions/test_ext_autodoc_configs.py index 66681f696..73a3f1712 100644 --- a/tests/test_extensions/test_ext_autodoc_configs.py +++ b/tests/test_extensions/test_ext_autodoc_configs.py @@ -319,6 +319,12 @@ def test_autodoc_inherit_docstrings_for_inherited_members(app): ' :module: target.inheritance', '', '', + ' .. py:method:: Derived.another_inheritedmeth()', + ' :module: target.inheritance', + '', + ' Another inherited function.', + '', + '', ' .. py:attribute:: Derived.inheritedattr', ' :module: target.inheritance', ' :value: None', @@ -356,6 +362,12 @@ def test_autodoc_inherit_docstrings_for_inherited_members(app): ' :module: target.inheritance', '', '', + ' .. py:method:: Derived.another_inheritedmeth()', + ' :module: target.inheritance', + '', + ' Another inherited function.', + '', + '', ' .. py:method:: Derived.inheritedclassmeth()', ' :module: target.inheritance', ' :classmethod:',