From bbbaecf3fa7bc5d5121eee4f882f32e05938e3ac 2014-03-06 20:50:19 From: MinRK Date: 2014-03-06 20:50:19 Subject: [PATCH] Update signature presentation in pinfo classes classes: - init definition comes before class docstring - remove Constructor info block, because it no longer has multiple entries - don't include instance call definition as definition objects: - don't duplicate call def and definition in callables --- diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index df33440..5a3003e 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -447,12 +447,12 @@ class Inspector: if inspect.isclass(obj) and hasattr(obj, '__init__'): init_ds = getdoc(obj.__init__) if init_ds is not None: - lines.append(head("Constructor Docstring:")) + lines.append(head("Init Docstring:")) lines.append(indent(init_ds)) elif hasattr(obj,'__call__'): call_ds = getdoc(obj.__call__) if call_ds: - lines.append(head("Calling Docstring:")) + lines.append(head("Call Docstring:")) lines.append(indent(call_ds)) if not lines: @@ -494,7 +494,7 @@ class Inspector: # 0-offset, so we must adjust. page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1) - def _format_fields(self, fields, title_width=12): + def _format_fields(self, fields, title_width=0): """Formats a list of fields for display. Parameters @@ -502,10 +502,13 @@ class Inspector: fields : list A list of 2-tuples: (field_title, field_content) title_width : int - How many characters to pad titles to. Default 12. + How many characters to pad titles to. Default to longest title. """ out = [] header = self.__head + if title_width == 0: + for title, _ in fields: + title_width = max(len(title) + 2, title_width) for title, content in fields: if len(content.splitlines()) > 1: title = header(title + ":") + "\n" @@ -527,7 +530,7 @@ class Inspector: ] pinfo_fields_obj = [("Class Docstring", "class_docstring"), - ("Constructor Docstring","init_docstring"), + ("Init Docstring", "init_docstring"), ("Call def", "call_def"), ("Call docstring", "call_docstring")] @@ -567,6 +570,9 @@ class Inspector: displayfields.append(("Namespace", info['namespace'].rstrip())) add_fields(self.pinfo_fields3) + if info['isclass'] and info['init_definition']: + displayfields.append(("Init Definition", + info['init_definition'].rstrip())) # Source or docstring, depending on detail level and whether # source found. @@ -578,14 +584,9 @@ class Inspector: # Constructor info for classes if info['isclass']: - if info['init_definition'] or info['init_docstring']: - displayfields.append(("Constructor information", "")) - if info['init_definition'] is not None: - displayfields.append((" Definition", - info['init_definition'].rstrip())) - if info['init_docstring'] is not None: - displayfields.append((" Docstring", - indent(info['init_docstring']))) + if info['init_docstring'] is not None: + displayfields.append(("Init Docstring", + info['init_docstring'])) # Info for objects: else: @@ -693,11 +694,6 @@ class Inspector: fname = 'Dynamically generated function. No source code available.' out['file'] = fname - # reconstruct the function definition and print it: - defln = self._getdef(obj, oname) - if defln: - out['definition'] = self.format(defln) - # Docstrings only in detail 0 mode, since source contains them (we # avoid repetitions). If source fails, we add them back, see below. if ds and detail_level == 0: @@ -747,6 +743,11 @@ class Inspector: # and class docstring for instances: else: + # reconstruct the function definition and print it: + defln = self._getdef(obj, oname) + if defln: + out['definition'] = self.format(defln) + # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In # most cases they will, but it's nice to print all the info for @@ -778,8 +779,12 @@ class Inspector: # Call form docstring for callable instances if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) - if call_def is not None: - out['call_def'] = self.format(call_def) + if call_def: + call_def = self.format(call_def) + # it may never be the case that call def and definition differ, + # but don't include the same signature twice + if call_def != out.get('definition'): + out['call_def'] = call_def call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds == _func_call_docstring: diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index dddcc27..34c7c6c 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -116,14 +116,14 @@ def test_ipdb_magics(): ipdb> pdoc ExampleClass Class Docstring: Docstring for ExampleClass. - Constructor Docstring: + Init Docstring: Docstring for ExampleClass.__init__ ipdb> pinfo a - Type: ExampleClass - String Form:ExampleClass() - Namespace: Local... - Docstring: Docstring for ExampleClass. - Constructor Docstring:Docstring for ExampleClass.__init__ + Type: ExampleClass + String Form: ExampleClass() + Namespace: Local... + Docstring: Docstring for ExampleClass. + Init Docstring: Docstring for ExampleClass.__init__ ipdb> continue Restore previous trace function, e.g. for coverage.py diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index 0a47e7f..eb11459 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -242,7 +242,7 @@ def test_info(): # case-insensitive comparison needed on some filesystems # e.g. Windows: nt.assert_equal(i['file'].lower(), fname.lower()) - nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n') + nt.assert_equal(i['definition'], None) nt.assert_equal(i['docstring'], Call.__doc__) nt.assert_equal(i['source'], None) nt.assert_true(i['isclass']) @@ -260,7 +260,7 @@ def test_info(): nt.assert_equal(i['docstring'], "Modified instance docstring") nt.assert_equal(i['class_docstring'], Call.__doc__) nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) - nt.assert_equal(i['call_docstring'], c.__call__.__doc__) + nt.assert_equal(i['call_docstring'], Call.__call__.__doc__) # Test old-style classes, which for example may not have an __init__ method. if not py3compat.PY3: