Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inheritance logic when intermediate class is present #5

Merged
8 changes: 5 additions & 3 deletions src/griffe_inherited_docstrings/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

def _docstring_above(obj: Object) -> Docstring | None:
with contextlib.suppress(IndexError, KeyError):
parent = obj.parent.mro()[0] # type: ignore[union-attr]
return parent.members[obj.name].docstring
for parent in obj.parent.mro(): # type: ignore[union-attr]
# Fetch docstring from first parent that has the member.
if obj.name in parent.members:
return parent.members[obj.name].docstring
return None


Expand All @@ -35,7 +37,7 @@ def _inherit_docstrings(obj: Object, *, merge: bool = False, seen: set[str] | No

elif obj.is_class:
# Recursively handle top-most parents first.
# It means that we can just check the first parent
# It means that we can just check the first parent with the member
# when actually inheriting (and optionally merging) a docstring,
# since the docstrings of the other parents have already been inherited.
for parent in reversed(obj.mro()): # type: ignore[attr-defined]
Expand Down
29 changes: 29 additions & 0 deletions tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,32 @@ def meth(self):
assert package["D.meth"].docstring.value == package["A.meth"].docstring.value + "\n\n" + f"{meth_doc} D."
assert package["E.attr"].docstring.value == package["D.attr"].docstring.value + "\n\n" + f"{attr_doc} E."
assert package["E.meth"].docstring.value == package["D.meth"].docstring.value + "\n\n" + f"{meth_doc} E."


def test_inherit_and_merge_docstrings_intermediate_class() -> None:
"""Inherit and merge docstrings from parent classes with an intermediate class.

It is important that the intermediate class doesn't have the member for which
docstring inheritance should be performed.
"""
with temporary_visited_package(
"package",
modules={
"__init__.py": """
class Parent:
def method(self):
'''Parent.'''

class Intermediate(Parent):
# This shouldn't break the inherting of docstrings.
# See https://github.com/mkdocstrings/griffe-inherited-docstrings/issues/4.
...

class Child(Intermediate):
def method(self):
'''Child.'''
""",
},
extensions=Extensions(InheritDocstringsExtension(merge=True)),
) as package:
assert package["Child.method"].docstring.value == "Parent.\n\nChild."