diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2020-05-18 17:25:07 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-18 17:25:07 (GMT) |
commit | 08b47c367a08f571a986366aa33828d3951fa88d (patch) | |
tree | be06ca168536a48a19f2a093192ad7137ff8aa3c /Lib/pydoc.py | |
parent | 98e42d1f882b9b59f587d538c562dbc7d11c64c3 (diff) | |
download | cpython-08b47c367a08f571a986366aa33828d3951fa88d.zip cpython-08b47c367a08f571a986366aa33828d3951fa88d.tar.gz cpython-08b47c367a08f571a986366aa33828d3951fa88d.tar.bz2 |
bpo-40257: Revert changes to inspect.getdoc() (GH-20073)
Diffstat (limited to 'Lib/pydoc.py')
-rwxr-xr-x | Lib/pydoc.py | 96 |
1 files changed, 94 insertions, 2 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 898cc44..628f9fc 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -90,9 +90,101 @@ def pathdirs(): normdirs.append(normdir) return dirs +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.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 + if inspect.ismemberdescriptor(obj): + slots = getattr(cls, '__slots__', None) + if isinstance(slots, dict) and name in slots: + return slots[name] + else: + return None + for base in cls.__mro__: + try: + 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.""" + doc = _getowndoc(object) + if doc is None: + try: + doc = _finddoc(object) + except (AttributeError, TypeError): + return None + if not isinstance(doc, str): + return None + return inspect.cleandoc(doc) + def getdoc(object): """Get the doc string or comments for an object.""" - result = inspect.getdoc(object) or inspect.getcomments(object) + result = _getdoc(object) or inspect.getcomments(object) return result and re.sub('^ *\n', '', result.rstrip()) or '' def splitdoc(doc): @@ -1669,7 +1761,7 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0, inspect.isclass(object) or inspect.isroutine(object) or inspect.isdatadescriptor(object) or - inspect.getdoc(object)): + _getdoc(object)): # If the passed object is a piece of data or an instance, # document its available methods instead of its value. if hasattr(object, '__origin__'): |