pdoc treats overridden methods as inherited when mixing Generic[...] base class with non-generic ABC in multiple inheritance
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.5k
- Forks
- 228
- PR merge metrics
- No merged PRs in 30d
Description
Problem Description
When a subclass uses multiple inheritance and one of its base classes is a generic ABC (abc.ABC + typing.Generic[...]), pdoc incorrectly marks an overridden method from a non-generic base class as inherited, and does not show the overriding method’s docstring.
This does not happen for:
- multiple inheritance from two non-generic ABCs, or
- multiple inheritance from two generic ABCs.
So the misclassification appears specific to mixing a Generic[...] base with a non-generic ABC base.
Steps to reproduce the behavior:
# foo.py
from abc import ABC
from typing import Generic, TypeVar
T = TypeVar("T")
U = TypeVar("U")
class GenericABC1(ABC, Generic[T]):
""""""
def method_generic1(self):
pass
class GenericABC2(ABC, Generic[U]):
""""""
def method_generic2(self):
pass
class ABC1(ABC):
""""""
def method1(self):
pass
class ABC2(ABC):
""""""
def method2(self):
pass
class NonGenericSubclass(ABC1, ABC2):
"""
Both methods' docstring are displayed, and are not considered inherited.
"""
def method1(self):
"""method1 implementation docstring"""
pass
def method2(self):
"""method2 implementation docstring"""
pass
class GenericSubclass1(GenericABC1[T], GenericABC2[U]):
"""
Both methods' docstring are displayed, and are not considered inherited.
"""
def method_generic1(self):
"""method_generic1 implementation docstring"""
pass
def method_generic2(self):
"""method_generic2 implementation docstring"""
pass
class GenericSubclass2(GenericABC1[T], ABC1):
"""
method1's docstring should be displayed, but it is considered inherited. Behavior is different than inheriting either from both non-generic ABC, or from both generic ABC, as above.
"""
def method_generic1(self):
"""method_generic1 implementation docstring"""
pass
def method1(self):
"""method1 implementation docstring"""
pass
if __name__ == "__main__":
assert GenericSubclass2.method1 is not ABC1.method1
assert "method1 implementation" in (GenericSubclass2.method1.__doc__ or "")
pdoc ./foo
Open the generated HTML for module foo and scroll to GenericSubclass2.
Observed Behavior
For GenericSubclass2(GenericABC1[T], ABC1):
method_generic1is shown normally with its docstring.method1is not shown as a concrete method on GenericSubclass2.- Instead,
method1appears under Inherited Members asABC1.method1(). - The docstring
"method1 implementation docstring"is not displayed as the subclass implementation.
Expected Behavior
Because GenericSubclass2 explicitly defines def method1(self): ..., pdoc should:
- treat
method1as belonging toGenericSubclass2(not inherited), and - display the overriding method’s docstring.
This is the same behavior pdoc already has for NonGenericSubclass(ABC1, ABC2) and GenericSubclass1(GenericABC1[T], GenericABC2[U]).
System Information
pdoc --version
pdoc: 16.0.0
Python: 3.12.11
Platform: macOS-15.6.1-arm64-arm-64bit
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by saving the provided reproducer as foo.py and running pdoc ./foo, then inspect the generated HTML for GenericSubclass2. Trace how pdoc distinguishes concrete and inherited methods when GenericABC1[T] and ABC1 are mixed. Done means method1 is listed on GenericSubclass2 with its implementation docstring, not only under inherited members.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- documentation
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100