Retireve docstirng form base classes (Closes #3140)

This commit is contained in:
Antonio Valentino 2017-08-18 10:51:24 +02:00
parent b2f841fcaa
commit 620491fcd5
3 changed files with 113 additions and 1 deletions

View File

@ -393,6 +393,16 @@ There are also new config values that you can set:
If ``False`` is given, autodoc forcely suppresses the error if the imported
module emits warnings. By default, ``True``.
.. confval:: autodoc_inherit_docstrings
This value controls the docstrings inheritance.
If set to True the cocstring for classes or methods, if not explicitly set,
is inherited form parents.
The default is ``True``.
.. versionadded:: 1.7
Docstring preprocessing
-----------------------

View File

@ -35,7 +35,7 @@ from sphinx.util import logging
from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \
safe_getattr, object_description, is_builtin_class_method, \
isenumclass, isenumattribute
isenumclass, isenumattribute, getdoc
from sphinx.util.docstrings import prepare_docstring
if False:
@ -525,6 +525,8 @@ class Documenter(object):
# type: (unicode, int) -> List[List[unicode]]
"""Decode and return lines of the docstring(s) for the object."""
docstring = self.get_attr(self.object, '__doc__', None)
if docstring is None and self.env.config.autodoc_inherit_docstrings:
docstring = getdoc(self.object)
# make sure we have Unicode docstrings, then sanitize and split
# into lines
if isinstance(docstring, text_type):
@ -682,6 +684,9 @@ class Documenter(object):
isattr = False
doc = self.get_attr(member, '__doc__', None)
if doc is None and self.env.config.autodoc_inherit_docstrings:
doc = getdoc(member)
# if the member __doc__ is the same as self's __doc__, it's just
# inherited and therefore not the member's doc
cls = self.get_attr(member, '__class__', None)
@ -1617,6 +1622,7 @@ def setup(app):
app.add_config_value('autodoc_docstring_signature', True, True)
app.add_config_value('autodoc_mock_imports', [], True)
app.add_config_value('autodoc_warningiserror', True, True)
app.add_config_value('autodoc_inherit_docstrings', True, True)
app.add_event('autodoc-process-docstring')
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')

View File

@ -11,6 +11,7 @@
from __future__ import absolute_import
import re
import sys
import typing
import inspect
from collections import OrderedDict
@ -456,3 +457,98 @@ class Signature(object):
', '.join(param_strings))
return qualified_name
if sys.version_info >= (3, 5):
getdoc = inspect.getdoc
else:
# code copyed from the inspect.py module of the standard library
# of Python 3.5
def _findclass(func):
cls = sys.modules.get(func.__module__)
if cls is None:
return None
for name in func.__qualname__.split('.')[:-1]:
cls = getattr(cls, name)
if not inspect.isclass(cls):
return None
return cls
def _finddoc(obj):
if inspect.isclass(obj):
for base in obj.__mro__:
if base is not object:
try:
doc = base.__doc__
except AttributeError:
continue
if doc is not None:
return doc
return None
if inspect.ismethod(obj):
name = obj.__func__.__name__
self = obj.__self__
if (inspect.isclass(self) and
getattr(getattr(self, name, None), '__func__') is obj.__func__):
# classmethod
cls = self
else:
cls = self.__class__
elif inspect.isfunction(obj):
name = obj.__name__
cls = _findclass(obj)
if cls is None or getattr(cls, name) is not obj:
return None
elif inspect.isbuiltin(obj):
name = obj.__name__
self = obj.__self__
if (inspect.isclass(self) and
self.__qualname__ + '.' + name == obj.__qualname__):
# classmethod
cls = self
else:
cls = self.__class__
# Should be tested before isdatadescriptor().
elif isinstance(obj, property):
func = obj.fget
name = func.__name__
cls = _findclass(func)
if cls is None or getattr(cls, name) is not obj:
return None
elif inspect.ismethoddescriptor(obj) or inspect.isdatadescriptor(obj):
name = obj.__name__
cls = obj.__objclass__
if getattr(cls, name) is not obj:
return None
else:
return None
for base in cls.__mro__:
try:
doc = getattr(base, name).__doc__
except AttributeError:
continue
if doc is not None:
return doc
return None
def getdoc(object):
"""Get the documentation string for an object.
All tabs are expanded to spaces. To clean up docstrings that are
indented to line up with blocks of code, any whitespace than can be
uniformly removed from the second line onwards is removed."""
try:
doc = object.__doc__
except AttributeError:
return None
if doc is None:
try:
doc = _finddoc(object)
except (AttributeError, TypeError):
return None
if not isinstance(doc, str):
return None
return inspect.cleandoc(doc)