summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2020-04-15 23:00:20 +0300
committerGitHub <noreply@github.com>2020-04-15 23:00:20 +0300
commitfbf2786c4c89430e2067016603078cf3500cfe94 (patch)
tree151141df42e6e058127ef59eae7f95c5e4644991 /Lib
parentba1bcffe5cafc1bb0ac6fdf9ecef51e75e342707 (diff)
downloadcpython-git-fbf2786c4c89430e2067016603078cf3500cfe94.tar.gz
bpo-40257: Output object's own docstring in pydoc (GH-19479)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/inspect.py33
-rwxr-xr-xLib/pydoc.py19
-rw-r--r--Lib/test/test_inspect.py15
-rw-r--r--Lib/test/test_pydoc.py3
4 files changed, 39 insertions, 31 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 90435a10ca..6f7d5cd19c 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -542,17 +542,6 @@ def _findclass(func):
return cls
def _finddoc(obj):
- if 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 ismethod(obj):
name = obj.__func__.__name__
self = obj.__self__
@@ -596,23 +585,35 @@ def _finddoc(obj):
return None
for base in cls.__mro__:
try:
- doc = getattr(base, name).__doc__
+ doc = _getowndoc(getattr(base, name))
except AttributeError:
continue
if doc is not None:
return doc
return None
+def _getowndoc(obj):
+ """Get the documentation string for an object if it is not
+ inherited from its class."""
+ try:
+ doc = object.__getattribute__(obj, '__doc__')
+ if doc is None:
+ return None
+ if obj is not type:
+ typedoc = type(obj).__doc__
+ if isinstance(typedoc, str) and typedoc == doc:
+ return None
+ return doc
+ except AttributeError:
+ 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
+ doc = _getowndoc(object)
if doc is None:
try:
doc = _finddoc(object)
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index f172700a15..a89b804570 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -825,11 +825,8 @@ class HTMLDoc(Doc):
push(msg)
for name, kind, homecls, value in ok:
base = self.docother(getattr(object, name), name, mod)
- if callable(value) or inspect.isdatadescriptor(value):
- doc = getattr(value, "__doc__", None)
- else:
- doc = None
- if doc is None:
+ doc = getdoc(value)
+ if not doc:
push('<dl><dt>%s</dl>\n' % base)
else:
doc = self.markup(getdoc(value), self.preformat,
@@ -1309,10 +1306,7 @@ location listed above.
hr.maybe()
push(msg)
for name, kind, homecls, value in ok:
- if callable(value) or inspect.isdatadescriptor(value):
- doc = getdoc(value)
- else:
- doc = None
+ doc = getdoc(value)
try:
obj = getattr(object, name)
except AttributeError:
@@ -1448,7 +1442,9 @@ location listed above.
chop = maxlen - len(line)
if chop < 0: repr = repr[:chop] + '...'
line = (name and self.bold(name) + ' = ' or '') + repr
- if doc is not None:
+ if not doc:
+ doc = getdoc(object)
+ if doc:
line += '\n' + self.indent(str(doc))
return line
@@ -1672,7 +1668,8 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
if not (inspect.ismodule(object) or
inspect.isclass(object) or
inspect.isroutine(object) or
- inspect.isdatadescriptor(object)):
+ inspect.isdatadescriptor(object) or
+ inspect.getdoc(object)):
# If the passed object is a piece of data or an instance,
# document its available methods instead of its value.
object = type(object)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index f193807e80..2dc8454595 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -439,8 +439,7 @@ class TestRetrievingSourceCode(GetSourceBase):
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
def test_getdoc_inherited(self):
- self.assertEqual(inspect.getdoc(mod.FesteringGob),
- 'A longer,\n\nindented\n\ndocstring.')
+ self.assertIsNone(inspect.getdoc(mod.FesteringGob))
self.assertEqual(inspect.getdoc(mod.FesteringGob.abuse),
'Another\n\ndocstring\n\ncontaining\n\ntabs')
self.assertEqual(inspect.getdoc(mod.FesteringGob().abuse),
@@ -449,9 +448,19 @@ class TestRetrievingSourceCode(GetSourceBase):
'The automatic gainsaying.')
@unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings")
+ def test_getowndoc(self):
+ getowndoc = inspect._getowndoc
+ self.assertEqual(getowndoc(type), type.__doc__)
+ self.assertEqual(getowndoc(int), int.__doc__)
+ self.assertEqual(getowndoc(int.to_bytes), int.to_bytes.__doc__)
+ self.assertEqual(getowndoc(int().to_bytes), int.to_bytes.__doc__)
+ self.assertEqual(getowndoc(int.from_bytes), int.from_bytes.__doc__)
+ self.assertEqual(getowndoc(int.real), int.real.__doc__)
+
+ @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings")
def test_finddoc(self):
finddoc = inspect._finddoc
- self.assertEqual(finddoc(int), int.__doc__)
+ self.assertIsNone(finddoc(int))
self.assertEqual(finddoc(int.to_bytes), int.to_bytes.__doc__)
self.assertEqual(finddoc(int().to_bytes), int.to_bytes.__doc__)
self.assertEqual(finddoc(int.from_bytes), int.from_bytes.__doc__)
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index ebd8d4a6c3..800913b425 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -1254,7 +1254,8 @@ cm(x) method of builtins.type instance
X.attr.__doc__ = 'Custom descriptor'
self.assertEqual(self._get_summary_lines(X.attr), """\
-<test.test_pydoc.TestDescriptions.test_custom_non_data_descriptor.<locals>.Descr object>""")
+<test.test_pydoc.TestDescriptions.test_custom_non_data_descriptor.<locals>.Descr object>
+ Custom descriptor""")
X.attr.__name__ = 'foo'
self.assertEqual(self._get_summary_lines(X.attr), """\