From db899f4885a5ee9b4e0fc71a0010e4b698c57343 2018-01-02 01:48:55 From: Antony Lee Date: 2018-01-02 01:48:55 Subject: [PATCH] In obj??, display the docstring if it is not in the source. Currently, `obj??` does not display obj's docstring because it is likely redundant with the source (which usually also includes the docstring). However, when the docstring had been dynamically added, then it should also be displayed by `obj??` (because it is not redundant in this case). A reasonable way to check for this condition is to parse the source and compare the result of `ast.get_docstring()` to the result of `inspect.getdoc()`, as done by this PR. --- diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 4f45345..311f3bc 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -13,6 +13,7 @@ reference the name under which an object is being read. __all__ = ['Inspector','InspectColors'] # stdlib modules +import ast import inspect from inspect import signature import linecache @@ -630,10 +631,10 @@ class Inspector(Colorable): # Functions, methods, classes append_field(_mime, 'Signature', 'definition', code_formatter) append_field(_mime, 'Init signature', 'init_definition', code_formatter) + append_field(_mime, 'Docstring', 'docstring', formatter) if detail_level > 0 and info['source']: append_field(_mime, 'Source', 'source', code_formatter) else: - append_field(_mime, 'Docstring', 'docstring', formatter) append_field(_mime, 'Init docstring', 'init_docstring', formatter) append_field(_mime, 'File', 'file') @@ -821,7 +822,7 @@ class Inspector(Colorable): pass # Add docstring only if no source is to be shown (avoid repetitions). - if ds and out.get('source', None) is None: + if ds and not self._source_contains_docstring(out.get('source'), ds): out['docstring'] = ds # Constructor docstring for classes @@ -936,6 +937,23 @@ class Inspector(Colorable): return object_info(**out) + @staticmethod + def _source_contains_docstring(src, doc): + """ + Check whether the source *src* contains the docstring *doc*. + + This is is helper function to skip displaying the docstring if the + source already contains it, avoiding repetition of information. + """ + try: + def_node, = ast.parse(dedent(src)).body + return ast.get_docstring(def_node) == doc + except Exception: + # The source can become invalid or even non-existent (because it + # is re-fetched from the source file) so the above code fail in + # arbitrary ways. + return False + def psearch(self,pattern,ns_table,ns_search=[], ignore_case=False,show_all=False): """Search namespaces with wildcards for objects.