diff -r edb12dad7bf6 Doc/library/inspect.rst --- a/Doc/library/inspect.rst Fri Mar 14 14:20:09 2014 +0000 +++ b/Doc/library/inspect.rst Sun Mar 16 22:03:16 2014 +0200 @@ -337,10 +337,18 @@ Retrieving source code ---------------------- -.. function:: getdoc(object) +.. function:: getdoc(object[, parent]) Get the documentation string for an object, cleaned up with :func:`cleandoc`. + If *parent* is given and *object.__doc__* is ``None``, and either the first + parameter is a bound method, or a class object is passed in + as *parent*, :func:`.getdoc` will search the MRO based + on ``object.__name__`` until it finds an attribute with a + non ``None`` ``__doc__`` value. + + .. versionchanged:: 3.5 + Added the *parent* parameter. .. function:: getcomments(object) diff -r edb12dad7bf6 Doc/make.bat --- a/Doc/make.bat Fri Mar 14 14:20:09 2014 +0000 +++ b/Doc/make.bat Sun Mar 16 22:03:16 2014 +0200 @@ -1,7 +1,7 @@ @@echo off setlocal -if "%PYTHON%" EQU "" set PYTHON=py -2 +if "%PYTHON%" EQU "" set PYTHON=py -3 if "%HTMLHELP%" EQU "" set HTMLHELP=%ProgramFiles%\HTML Help Workshop\hhc.exe if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/sphinxext/patchlevel.py`) do set DISTVERSION=%%v @@ -33,7 +33,7 @@ if not exist build\%1 mkdir build\%1 if not exist build\doctrees mkdir build\doctrees cmd /C %PYTHON% --version -cmd /C %PYTHON% tools\sphinx-build.py -b%1 -dbuild\doctrees . build\%* +cmd /C %PYTHON% c:\Python34\Scripts\sphinx-build.exe -b%1 -dbuild\doctrees . build\%* if "%1" EQU "htmlhelp" "%HTMLHELP%" build\htmlhelp\python%DISTVERSION:.=%.hhp goto end diff -r edb12dad7bf6 Lib/inspect.py --- a/Lib/inspect.py Fri Mar 14 14:20:09 2014 +0000 +++ b/Lib/inspect.py Sun Mar 16 22:03:16 2014 +0200 @@ -467,9 +467,14 @@ expline = line.expandtabs() return len(expline) - len(expline.lstrip()) -def getdoc(object): +def getdoc(object, parent=None): """Get the documentation string for an object. + In the case where obj.__doc__ is None, and either the first + parameter is a bound method, or a class object is passed in + as the second parameter, `getdoc` will search the MRO based + on obj.__name__ until it finds an attribute with a + non-None __doc__ value. 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.""" @@ -477,6 +482,26 @@ doc = object.__doc__ except AttributeError: return None + if doc is None: + if ismethod(object): + parent = object.__self__.__class__ + if isclass(parent): + name = object.__name__ + for base in getmro(parent): + try: + baseobj = getattr(base, name) + except AttributeError: + if name in base.__dict__: + baseobj = base.__dict__[name] + else: + continue + try: + doc = baseobj.__doc__ + except AttributeError: + continue + if doc is not None: + break + if not isinstance(doc, str): return None return cleandoc(doc) diff -r edb12dad7bf6 Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Fri Mar 14 14:20:09 2014 +0000 +++ b/Lib/test/test_inspect.py Sun Mar 16 22:03:16 2014 +0200 @@ -278,6 +278,27 @@ self.assertEqual(inspect.getdoc(git.abuse), 'Another\n\ndocstring\n\ncontaining\n\ntabs') + # test for inheritance chain + class Parent: + def ham(self): + """eggs""" + class Child(Parent): + def ham(self): + pass + class Nephew(Child): + def ham(self): + pass + + self.assertEqual(inspect.getdoc(Child().ham), + 'eggs') + self.assertEqual(inspect.getdoc(Child.ham, parent=Child), + 'eggs') + self.assertEqual(inspect.getdoc(Nephew.ham, parent=Nephew), + 'eggs') + self.assertIsNone(inspect.getdoc(Nephew.ham)) + # test wrong parent + self.assertIsNone(inspect.getdoc(Child.ham, parent=mod.StupidGit)) + def test_cleandoc(self): self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'), 'An\nindented\ndocstring.')