diff -r 469ff344f8fd Doc/library/inspect.rst --- a/Doc/library/inspect.rst Sat Jan 31 12:20:40 2015 -0800 +++ b/Doc/library/inspect.rst Sun Feb 01 04:58:02 2015 +0000 @@ -356,6 +356,7 @@ .. function:: getdoc(object) Get the documentation string for an object, cleaned up with :func:`cleandoc`. + If the object has no documentation string, ``None`` is returned. .. function:: getcomments(object) @@ -365,6 +366,17 @@ Python source file (if the object is a module). +.. function:: splitdoc(doc) + + Return a tuple where the first element is the synopsis of the function and the second + element is the rest of the documentation. Return an empty synopsis string + if there is no single-line synopsis, and return an empty second element if + there is no body. Return two empty strings if the input is ``None``. + This will fail with a :exc:`TypeError` for other inputs. + + .. versionadded:: 3.5 + + .. function:: getfile(object) Return the name of the (text or binary) file in which an object was defined. diff -r 469ff344f8fd Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst Sat Jan 31 12:20:40 2015 -0800 +++ b/Doc/whatsnew/3.5.rst Sun Feb 01 04:58:02 2015 +0000 @@ -221,6 +221,10 @@ subclassing of :class:`~inspect.Signature` easier. (Contributed by Yury Selivanov and Eric Snow in :issue:`17373`.) +* New function :func:`inspect.splitdoc`, which returns a tuple from a + documentation string, where the first element is the synopsis of + the function and the second element is the rest of the documentation. + ipaddress --------- diff -r 469ff344f8fd Lib/inspect.py --- a/Lib/inspect.py Sat Jan 31 12:20:40 2015 -0800 +++ b/Lib/inspect.py Sun Feb 01 04:58:02 2015 +0000 @@ -13,6 +13,7 @@ getfile(), getsourcefile(), getsource() - find an object's source code getdoc(), getcomments() - get documentation on an object + splitdoc() - split a doc string into a synopsis line (if any) and the rest getmodule() - determine the module that an object came from getclasstree() - arrange classes so as to represent their hierarchy @@ -482,6 +483,20 @@ return None return cleandoc(doc) +def splitdoc(doc): + """Split a doc string into a synopsis line (if any) and the rest.""" + if doc is None: + return '', '' + if not isinstance(doc, str): + raise TypeError("doc must be a string or None") + + lines = doc.strip().split('\n', 2) + if len(lines) == 1: + return lines[0], '' + elif len(lines) >= 2 and not lines[1].rstrip(): + return lines[0], lines[2] + return '', '\n'.join(lines) + def cleandoc(doc): """Clean up indentation from docstrings. diff -r 469ff344f8fd Lib/pydoc.py --- a/Lib/pydoc.py Sat Jan 31 12:20:40 2015 -0800 +++ b/Lib/pydoc.py Sun Feb 01 04:58:02 2015 +0000 @@ -91,13 +91,14 @@ return result and re.sub('^ *\n', '', result.rstrip()) or '' def splitdoc(doc): - """Split a doc string into a synopsis line (if any) and the rest.""" - lines = doc.strip().split('\n') - if len(lines) == 1: - return lines[0], '' - elif len(lines) >= 2 and not lines[1].rstrip(): - return lines[0], '\n'.join(lines[2:]) - return '', '\n'.join(lines) + """**DEPRECATED** + + Split a doc string into a synopsis line (if any) and the rest. + """ + warnings.warn("the pydoc.splitdoc is deprecated in favour " + "of inspect.splitdoc", + PendingDeprecationWarning, stacklevel=2) + return inspect.splitdoc(doc) def classname(object, modname): """Get a class name and qualify it with a module name if necessary.""" diff -r 469ff344f8fd Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Sat Jan 31 12:20:40 2015 -0800 +++ b/Lib/test/test_inspect.py Sun Feb 01 04:58:02 2015 +0000 @@ -292,6 +292,37 @@ self.assertEqual(inspect.getdoc(git.abuse), 'Another\n\ndocstring\n\ncontaining\n\ntabs') + def undocumented(): + pass + self.assertIsNone(inspect.getdoc(undocumented)) + + def test_splitdoc(self): + with self.assertRaises(TypeError): + inspect.splitdoc(b"byte string") + + self.assertEqual(inspect.splitdoc(inspect.getdoc(mod)), + ('A module docstring.', '')) + + self.assertEqual(inspect.splitdoc(inspect.getdoc(mod.StupidGit)), + ('A longer,', 'indented\n\ndocstring.')) + + no_synopsis = """A multiline docstring + without a single-line synopsis""" + tests = ( + # (docstring, synopsis, body) + (no_synopsis, '', no_synopsis), + (' Strip indent', 'Strip indent', ''), + ('Indented blank line\n' + ' \n' + ' Indented body', + 'Indented blank line', ' Indented body'), + ('', '', ''), + (None, '', ''), + ) + for doc, synopsis, body in tests: + with self.subTest(repr(doc)): + self.assertEqual(inspect.splitdoc(doc), (synopsis, body)) + def test_cleandoc(self): self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'), 'An\nindented\ndocstring.')