|
| 1 | +"""The Griffe extension.""" |
| 2 | + |
| 3 | +from __future__ import annotations |
| 4 | + |
| 5 | +import contextlib |
| 6 | +from typing import TYPE_CHECKING |
| 7 | + |
| 8 | +from griffe import Extension |
| 9 | +from griffe.exceptions import AliasResolutionError |
| 10 | + |
| 11 | +if TYPE_CHECKING: |
| 12 | + from griffe import Docstring, Module, Object |
| 13 | + |
| 14 | + |
| 15 | +def _inherited_docstring(obj: Object) -> Docstring | None: |
| 16 | + for parent_class in obj.parent.mro(): # type: ignore[union-attr] |
| 17 | + try: |
| 18 | + if docstring := parent_class.members[obj.name].docstring: |
| 19 | + return docstring |
| 20 | + except KeyError: |
| 21 | + pass |
| 22 | + return None |
| 23 | + |
| 24 | + |
| 25 | +def _inherit_docstrings(obj: Object) -> None: |
| 26 | + if obj.is_module: |
| 27 | + for member in obj.members.values(): |
| 28 | + if not member.is_alias: |
| 29 | + with contextlib.suppress(AliasResolutionError): |
| 30 | + _inherit_docstrings(member) # type: ignore[arg-type] |
| 31 | + elif obj.is_class: |
| 32 | + for member in obj.members.values(): |
| 33 | + if not member.is_alias: |
| 34 | + if member.docstring is None and (inherited := _inherited_docstring(member)): # type: ignore[arg-type] |
| 35 | + member.docstring = inherited |
| 36 | + if member.is_class: |
| 37 | + _inherit_docstrings(member) # type: ignore[arg-type] |
| 38 | + |
| 39 | + |
| 40 | +class InheritDocstringsExtension(Extension): |
| 41 | + """Griffe extension for inheriting docstrings.""" |
| 42 | + |
| 43 | + def on_package_loaded(self, *, pkg: Module) -> None: |
| 44 | + """Inherit docstrings from parent classes once the whole package is loaded.""" |
| 45 | + _inherit_docstrings(pkg) |
0 commit comments