Skip to content

Commit

Permalink
feat: Implement extension
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Nov 14, 2023
1 parent 053ade4 commit 993e4e1
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
4 changes: 3 additions & 1 deletion pyproject.toml
Expand Up @@ -27,7 +27,9 @@ classifiers = [
"Topic :: Utilities",
"Typing :: Typed",
]
dependencies = []
dependencies = [
"griffe>=0.38",
]

[project.urls]
Homepage = "https://mkdocstrings.github.io/griffe-inherited-docstrings"
Expand Down
4 changes: 3 additions & 1 deletion src/griffe_inherited_docstrings/__init__.py
Expand Up @@ -5,4 +5,6 @@

from __future__ import annotations

__all__: list[str] = []
from griffe_inherited_docstrings.extension import InheritDocstringsExtension

__all__: list[str] = ["InheritDocstringsExtension"]
45 changes: 45 additions & 0 deletions src/griffe_inherited_docstrings/extension.py
@@ -0,0 +1,45 @@
"""The Griffe extension."""

from __future__ import annotations

import contextlib
from typing import TYPE_CHECKING

from griffe import Extension
from griffe.exceptions import AliasResolutionError

if TYPE_CHECKING:
from griffe import Docstring, Module, Object


def _inherited_docstring(obj: Object) -> Docstring | None:
for parent_class in obj.parent.mro(): # type: ignore[union-attr]
try:
if docstring := parent_class.members[obj.name].docstring:
return docstring
except KeyError:
pass
return None


def _inherit_docstrings(obj: Object) -> None:
if obj.is_module:
for member in obj.members.values():
if not member.is_alias:
with contextlib.suppress(AliasResolutionError):
_inherit_docstrings(member) # type: ignore[arg-type]
elif obj.is_class:
for member in obj.members.values():
if not member.is_alias:
if member.docstring is None and (inherited := _inherited_docstring(member)): # type: ignore[arg-type]
member.docstring = inherited
if member.is_class:
_inherit_docstrings(member) # type: ignore[arg-type]


class InheritDocstringsExtension(Extension):
"""Griffe extension for inheriting docstrings."""

def on_package_loaded(self, *, pkg: Module) -> None:
"""Inherit docstrings from parent classes once the whole package is loaded."""
_inherit_docstrings(pkg)
28 changes: 28 additions & 0 deletions tests/test_extension.py
@@ -0,0 +1,28 @@
"""Tests for the extension."""

from __future__ import annotations

from griffe.extensions import Extensions
from griffe.tests import temporary_visited_package

from griffe_inherited_docstrings import InheritDocstringsExtension


def test_inherit_docstrings() -> None:
"""Inherit docstrings from parent classes."""
with temporary_visited_package(
"package",
modules={
"__init__.py": """
class Parent:
def method(self):
'''Docstring from parent method.'''
class Child(Parent):
def method(self):
...
""",
},
extensions=Extensions(InheritDocstringsExtension()),
) as package:
assert package["Child.method"].docstring.value == package["Parent.method"].docstring.value

0 comments on commit 993e4e1

Please sign in to comment.