Skip to content

Commit

Permalink
Merge pull request #9261 from tk0miya/9250_inherited_docstring
Browse files Browse the repository at this point in the history
Fix #9250: autodoc: The inherited method not having docstring is wrongly parsed
  • Loading branch information
tk0miya committed May 23, 2021
2 parents 27e0122 + 0fb8e33 commit 830b3fb
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -54,6 +54,7 @@ Bugs fixed
* #8597: autodoc: a docsting having metadata only should be treated as
undocumented
* #9185: autodoc: typehints for overloaded functions and methods are inaccurate
* #9250: autodoc: The inherited method not having docstring is wrongly parsed
* #9217: manpage: The name of manpage directory that is generated by
:confval:`man_make_section_directory` is not correct
* #9224: ``:param:`` and ``:type:`` fields does not support a type containing
Expand Down
4 changes: 2 additions & 2 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1704,7 +1704,7 @@ def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
__init__ = self.get_attr(self.object, '__init__', None)
initdocstring = getdoc(__init__, self.get_attr,
self.config.autodoc_inherit_docstrings,
self.parent, self.object_name)
self.object, '__init__')
# for new-style classes, no __init__ means default __init__
if (initdocstring is not None and
(initdocstring == object.__init__.__doc__ or # for pypy
Expand All @@ -1715,7 +1715,7 @@ def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
__new__ = self.get_attr(self.object, '__new__', None)
initdocstring = getdoc(__new__, self.get_attr,
self.config.autodoc_inherit_docstrings,
self.parent, self.object_name)
self.object, '__new__')
# for new-style classes, no __new__ means default __new__
if (initdocstring is not None and
(initdocstring == object.__new__.__doc__ or # for pypy
Expand Down
25 changes: 17 additions & 8 deletions sphinx/util/inspect.py
Expand Up @@ -838,16 +838,25 @@ def getdoc(obj: Any, attrgetter: Callable = safe_getattr,
if ispartial(obj) and doc == obj.__class__.__doc__:
return getdoc(obj.func)
elif doc is None and allow_inherited:
doc = inspect.getdoc(obj)

if doc is None and cls and name:
# inspect.getdoc() does not support some kind of inherited and decorated methods.
# This tries to obtain the docstring from super classes.
for basecls in getattr(cls, '__mro__', []):
if cls and name:
# Check a docstring of the attribute or method from super classes.
for basecls in getmro(cls):
meth = safe_getattr(basecls, name, None)
if meth is not None:
doc = inspect.getdoc(meth)
if doc:
doc = attrgetter(meth, '__doc__', None)
if doc is not None:
break

if doc is None:
# retry using `inspect.getdoc()`
for basecls in getmro(cls):
meth = safe_getattr(basecls, name, None)
if meth is not None:
doc = inspect.getdoc(meth)
if doc is not None:
break

if doc is None:
doc = inspect.getdoc(obj)

return doc
7 changes: 5 additions & 2 deletions tests/test_util_inspect.py
Expand Up @@ -674,7 +674,10 @@ def func1(a, b, c):
def test_getdoc_inherited_decorated_method():
class Foo:
def meth(self):
"""docstring."""
"""
docstring
indented text
"""

class Bar(Foo):
@functools.lru_cache()
Expand All @@ -683,7 +686,7 @@ def meth(self):
pass

assert inspect.getdoc(Bar.meth, getattr, False, Bar, "meth") is None
assert inspect.getdoc(Bar.meth, getattr, True, Bar, "meth") == "docstring."
assert inspect.getdoc(Bar.meth, getattr, True, Bar, "meth") == Foo.meth.__doc__


def test_is_builtin_class_method():
Expand Down

0 comments on commit 830b3fb

Please sign in to comment.