bpo-40257: Output object's own docstring in pydoc (GH-19479)

diff --git a/Lib/inspect.py b/Lib/inspect.py
index 90435a1..6f7d5cd 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -542,17 +542,6 @@
     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 @@
         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 f172700..a89b804 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -825,11 +825,8 @@
                 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 @@
                 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 @@
             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 @@
     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 f193807..2dc8454 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -439,8 +439,7 @@
     @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 @@
                          '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 ebd8d4a..800913b 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -1254,7 +1254,8 @@
 
         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), """\