Show More
@@ -1567,7 +1567,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
1567 | with self.builtin_trap: |
|
1567 | with self.builtin_trap: | |
1568 | info = self._object_find(oname) |
|
1568 | info = self._object_find(oname) | |
1569 | if info.found: |
|
1569 | if info.found: | |
1570 |
return self.inspector._ |
|
1570 | return self.inspector._get_info(info.obj, oname, info=info, | |
1571 | detail_level=detail_level |
|
1571 | detail_level=detail_level | |
1572 | ) |
|
1572 | ) | |
1573 | else: |
|
1573 | else: |
@@ -112,7 +112,8 b' def getdoc(obj):' | |||||
112 |
|
112 | |||
113 | It also attempts to call a getdoc() method on the given object. This |
|
113 | It also attempts to call a getdoc() method on the given object. This | |
114 | allows objects which provide their docstrings via non-standard mechanisms |
|
114 | allows objects which provide their docstrings via non-standard mechanisms | |
115 |
(like Pyro proxies) to still be inspected by ipython's ? system. |
|
115 | (like Pyro proxies) to still be inspected by ipython's ? system. | |
|
116 | """ | |||
116 | # Allow objects to offer customized documentation via a getdoc method: |
|
117 | # Allow objects to offer customized documentation via a getdoc method: | |
117 | try: |
|
118 | try: | |
118 | ds = obj.getdoc() |
|
119 | ds = obj.getdoc() | |
@@ -122,14 +123,13 b' def getdoc(obj):' | |||||
122 | # if we get extra info, we add it to the normal docstring. |
|
123 | # if we get extra info, we add it to the normal docstring. | |
123 | if isinstance(ds, string_types): |
|
124 | if isinstance(ds, string_types): | |
124 | return inspect.cleandoc(ds) |
|
125 | return inspect.cleandoc(ds) | |
125 |
|
||||
126 | try: |
|
126 | try: | |
127 | docstr = inspect.getdoc(obj) |
|
127 | docstr = inspect.getdoc(obj) | |
128 | encoding = get_encoding(obj) |
|
128 | encoding = get_encoding(obj) | |
129 | return py3compat.cast_unicode(docstr, encoding=encoding) |
|
129 | return py3compat.cast_unicode(docstr, encoding=encoding) | |
130 | except Exception: |
|
130 | except Exception: | |
131 | # Harden against an inspect failure, which can occur with |
|
131 | # Harden against an inspect failure, which can occur with | |
132 |
# |
|
132 | # extensions modules. | |
133 | raise |
|
133 | raise | |
134 | return None |
|
134 | return None | |
135 |
|
135 | |||
@@ -366,10 +366,11 b' def find_source_lines(obj):' | |||||
366 |
|
366 | |||
367 |
|
367 | |||
368 | class Inspector(Colorable): |
|
368 | class Inspector(Colorable): | |
|
369 | ||||
369 | def __init__(self, color_table=InspectColors, |
|
370 | def __init__(self, color_table=InspectColors, | |
370 | code_color_table=PyColorize.ANSICodeColors, |
|
371 | code_color_table=PyColorize.ANSICodeColors, | |
371 | scheme='NoColor', |
|
372 | scheme='NoColor', | |
372 |
str_detail_level=0, |
|
373 | str_detail_level=0, | |
373 | parent=None, config=None): |
|
374 | parent=None, config=None): | |
374 | super(Inspector, self).__init__(parent=parent, config=config) |
|
375 | super(Inspector, self).__init__(parent=parent, config=config) | |
375 | self.color_table = color_table |
|
376 | self.color_table = color_table | |
@@ -430,7 +431,7 b' class Inspector(Colorable):' | |||||
430 |
|
431 | |||
431 | # In Python 3, all classes are new-style, so they all have __init__. |
|
432 | # In Python 3, all classes are new-style, so they all have __init__. | |
432 | @skip_doctest_py3 |
|
433 | @skip_doctest_py3 | |
433 |
def pdoc(self,obj,oname='',formatter |
|
434 | def pdoc(self, obj, oname='', formatter=None): | |
434 | """Print the docstring for any object. |
|
435 | """Print the docstring for any object. | |
435 |
|
436 | |||
436 | Optional: |
|
437 | Optional: | |
@@ -505,7 +506,7 b' class Inspector(Colorable):' | |||||
505 |
|
506 | |||
506 | def pfile(self, obj, oname=''): |
|
507 | def pfile(self, obj, oname=''): | |
507 | """Show the whole file where an object was defined.""" |
|
508 | """Show the whole file where an object was defined.""" | |
508 |
|
509 | |||
509 | lineno = find_source_lines(obj) |
|
510 | lineno = find_source_lines(obj) | |
510 | if lineno is None: |
|
511 | if lineno is None: | |
511 | self.noinfo('file', oname) |
|
512 | self.noinfo('file', oname) | |
@@ -541,96 +542,128 b' class Inspector(Colorable):' | |||||
541 | title_width = max(len(title) + 2 for title, _ in fields) |
|
542 | title_width = max(len(title) + 2 for title, _ in fields) | |
542 | for title, content in fields: |
|
543 | for title, content in fields: | |
543 | if len(content.splitlines()) > 1: |
|
544 | if len(content.splitlines()) > 1: | |
544 |
title = header(title + |
|
545 | title = header(title + ':') + '\n' | |
545 | else: |
|
546 | else: | |
546 |
title = header((title+ |
|
547 | title = header((title + ':').ljust(title_width)) | |
547 | out.append(cast_unicode(title) + cast_unicode(content)) |
|
548 | out.append(cast_unicode(title) + cast_unicode(content)) | |
548 | return "\n".join(out) |
|
549 | return "\n".join(out) | |
549 |
|
550 | |||
550 |
def _format |
|
551 | def _mime_format(self, text, formatter=None): | |
551 | """Format an info dict as text""" |
|
552 | """Return a mime bundle representation of the input text. | |
552 |
|
|
553 | ||
553 | # hack docstring rendering |
|
554 | - if `formatter` is None, the returned mime bundle has | |
554 | info = self.info(obj, oname=oname, formatter=None, |
|
555 | a `text/plain` field, with the input text. | |
555 | info=info, detail_level=detail_level) |
|
556 | a `text/html` field with a `<pre>` tag containing the input text. | |
556 | if formatter: |
|
557 | ||
557 | return formatter(info["docstring"]) |
|
558 | - if `formatter` is not None, it must be a callable transforming the | |
558 |
|
559 | input text into a mime bundle. Default values for `text/plain` and | ||
559 | displayfields = [] |
|
560 | `text/html` representations are the ones described above. | |
560 | def add_fields(fields): |
|
561 | ||
561 | for title, key in fields: |
|
562 | Note: | |
562 | field = info[key] |
|
563 | ||
563 | if field is not None: |
|
564 | Formatters returning strings are supported but this behavior is deprecated. | |
564 | if key == "source": |
|
565 | ||
565 | displayfields.append((title, self.format(cast_unicode(field.rstrip())))) |
|
566 | """ | |
566 | else: |
|
567 | text = cast_unicode(text) | |
567 | displayfields.append((title, field.rstrip())) |
|
568 | defaults = { | |
|
569 | 'text/plain': text, | |||
|
570 | 'text/html': '<pre>' + text + '</pre>' | |||
|
571 | } | |||
|
572 | ||||
|
573 | if formatter is None: | |||
|
574 | return defaults | |||
|
575 | else: | |||
|
576 | formatted = formatter(text) | |||
|
577 | ||||
|
578 | if not isinstance(formatted, dict): | |||
|
579 | # Handle the deprecated behavior of a formatter returning | |||
|
580 | # a string instead of a mime bundle. | |||
|
581 | return { | |||
|
582 | 'text/plain': formatted, | |||
|
583 | 'text/html': '<pre>' + formatted + '</pre>' | |||
|
584 | } | |||
|
585 | ||||
|
586 | else: | |||
|
587 | return dict(defaults, **formatted) | |||
|
588 | ||||
|
589 | def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0): | |||
|
590 | """Retrieve an info dict and format it.""" | |||
|
591 | ||||
|
592 | info = self._info(obj, oname=oname, info=info, detail_level=detail_level) | |||
|
593 | ||||
|
594 | mime = { | |||
|
595 | 'text/plain': '', | |||
|
596 | 'text/html': '', | |||
|
597 | } | |||
|
598 | ||||
|
599 | def append_field(bundle, title, key, formatter=None): | |||
|
600 | field = info[key] | |||
|
601 | if field is not None: | |||
|
602 | formatted_field = self._mime_format(field, formatter) | |||
|
603 | bundle['text/plain'] += self.__head(title) + ':\n' + formatted_field['text/plain'] + '\n' | |||
|
604 | bundle['text/html'] += '<h1>' + title + '</h1>\n' + formatted_field['text/html'] + '\n' | |||
|
605 | ||||
|
606 | def code_formatter(text): | |||
|
607 | return { | |||
|
608 | 'text/plain': self.format(text), | |||
|
609 | 'text/html': '<pre>' + text + '</pre>' | |||
|
610 | } | |||
568 |
|
611 | |||
569 | if info['isalias']: |
|
612 | if info['isalias']: | |
570 |
a |
|
613 | append_field(mime, 'Repr', 'string_form') | |
571 |
|
614 | |||
572 | elif info['ismagic']: |
|
615 | elif info['ismagic']: | |
573 |
if detail_level > 0 |
|
616 | if detail_level > 0: | |
574 |
a |
|
617 | append_field(mime, 'Source', 'source', code_formatter) | |
575 | else: |
|
618 | else: | |
576 |
a |
|
619 | append_field(mime, 'Docstring', 'docstring', formatter) | |
577 |
|
620 | append_field(mime, 'File', 'file') | ||
578 | add_fields([("File", "file"), |
|
|||
579 | ]) |
|
|||
580 |
|
621 | |||
581 | elif info['isclass'] or is_simple_callable(obj): |
|
622 | elif info['isclass'] or is_simple_callable(obj): | |
582 | # Functions, methods, classes |
|
623 | # Functions, methods, classes | |
583 |
a |
|
624 | append_field(mime, 'Signature', 'definition', code_formatter) | |
584 |
|
|
625 | append_field(mime, 'Init signature', 'init_definition', code_formatter) | |
585 | ]) |
|
626 | if detail_level > 0: | |
586 | if detail_level > 0 and info['source'] is not None: |
|
627 | append_field(mime, 'Source', 'source', code_formatter) | |
587 | add_fields([("Source", "source")]) |
|
|||
588 | else: |
|
628 | else: | |
589 |
a |
|
629 | append_field(mime, 'Docstring', 'docstring', formatter) | |
590 |
|
|
630 | append_field(mime, 'Init docstring', 'init_docstring', formatter) | |
591 | ]) |
|
|||
592 |
|
631 | |||
593 |
a |
|
632 | append_field(mime, 'File', 'file') | |
594 |
|
|
633 | append_field(mime, 'Type', 'type_name') | |
595 | ]) |
|
|||
596 |
|
634 | |||
597 | else: |
|
635 | else: | |
598 | # General Python objects |
|
636 | # General Python objects | |
599 |
a |
|
637 | append_field(mime, 'Type', 'type_name') | |
600 |
|
638 | |||
601 | # Base class for old-style instances |
|
639 | # Base class for old-style instances | |
602 | if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']: |
|
640 | if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']: | |
603 |
|
|
641 | append_field(mime, 'Base Class', 'base_class') | |
604 |
|
642 | |||
605 |
a |
|
643 | append_field(mime, 'String form', 'string_form') | |
606 |
|
644 | |||
607 | # Namespace |
|
645 | # Namespace | |
608 | if info['namespace'] != 'Interactive': |
|
646 | if info['namespace'] != 'Interactive': | |
609 |
|
|
647 | append_field(mime, 'Namespace', 'namespace') | |
610 |
|
648 | |||
611 |
a |
|
649 | append_field(mime, 'Length', 'length') | |
612 | ("File", "file"), |
|
650 | append_field(mime, 'File', 'file'), | |
613 | ("Signature", "definition"), |
|
651 | append_field(mime, 'Signature', 'definition', code_formatter) | |
614 | ]) |
|
|||
615 |
|
652 | |||
616 | # Source or docstring, depending on detail level and whether |
|
653 | # Source or docstring, depending on detail level and whether | |
617 | # source found. |
|
654 | # source found. | |
618 |
if detail_level > 0 |
|
655 | if detail_level > 0: | |
619 | displayfields.append(("Source", |
|
656 | append_field(mime, 'Source', 'source', code_formatter) | |
620 | self.format(cast_unicode(info['source'])))) |
|
657 | else: | |
621 | elif info['docstring'] is not None: |
|
658 | append_field(mime, 'Docstring', 'docstring', formatter) | |
622 | displayfields.append(("Docstring", info["docstring"])) |
|
659 | ||
623 |
|
660 | append_field(mime, 'Class docstring', 'class_docstring', formatter) | ||
624 |
a |
|
661 | append_field(mime, 'Init docstring', 'init_docstring', formatter) | |
625 | ("Init docstring", "init_docstring"), |
|
662 | append_field(mime, 'Call signature', 'call_def', code_formatter) | |
626 | ("Call signature", "call_def"), |
|
663 | append_field(mime, 'Call docstring', 'call_docstring', formatter) | |
627 | ("Call docstring", "call_docstring")]) |
|
664 | ||
628 |
|
665 | return mime | ||
629 | if displayfields: |
|
666 | ||
630 | return self._format_fields(displayfields) |
|
|||
631 | else: |
|
|||
632 | return u'' |
|
|||
633 |
|
||||
634 | def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): |
|
667 | def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): | |
635 | """Show detailed information about an object. |
|
668 | """Show detailed information about an object. | |
636 |
|
669 | |||
@@ -638,26 +671,37 b' class Inspector(Colorable):' | |||||
638 |
|
671 | |||
639 | - oname: name of the variable pointing to the object. |
|
672 | - oname: name of the variable pointing to the object. | |
640 |
|
673 | |||
641 | - formatter: special formatter for docstrings (see pdoc) |
|
674 | - formatter: callable (optional) | |
|
675 | A special formatter for docstrings. | |||
|
676 | ||||
|
677 | The formatter is a callable that takes a string as an input | |||
|
678 | and returns either a formatted string or a mime type bundle | |||
|
679 | in the form of a dictionnary. | |||
|
680 | ||||
|
681 | Although the support of custom formatter returning a string | |||
|
682 | instead of a mime type bundle is deprecated. | |||
642 |
|
683 | |||
643 | - info: a structure with some information fields which may have been |
|
684 | - info: a structure with some information fields which may have been | |
644 | precomputed already. |
|
685 | precomputed already. | |
645 |
|
686 | |||
646 | - detail_level: if set to 1, more information is given. |
|
687 | - detail_level: if set to 1, more information is given. | |
647 | """ |
|
688 | """ | |
648 |
|
|
689 | info = self._get_info(obj, oname, formatter, info, detail_level) | |
649 |
if |
|
690 | if info: | |
650 |
page.page( |
|
691 | page.page(info) | |
651 |
|
692 | |||
652 | def info(self, obj, oname='', formatter=None, info=None, detail_level=0): |
|
693 | def info(self, obj, oname='', formatter=None, info=None, detail_level=0): | |
|
694 | """DEPRECATED. Compute a dict with detailed information about an object. | |||
|
695 | """ | |||
|
696 | return self._info(obj, oname=oname, info=info, detail_level=detail_level) | |||
|
697 | ||||
|
698 | def _info(self, obj, oname='', info=None, detail_level=0): | |||
653 | """Compute a dict with detailed information about an object. |
|
699 | """Compute a dict with detailed information about an object. | |
654 |
|
700 | |||
655 | Optional arguments: |
|
701 | Optional arguments: | |
656 |
|
702 | |||
657 | - oname: name of the variable pointing to the object. |
|
703 | - oname: name of the variable pointing to the object. | |
658 |
|
704 | |||
659 | - formatter: special formatter for docstrings (see pdoc) |
|
|||
660 |
|
||||
661 | - info: a structure with some information fields which may have been |
|
705 | - info: a structure with some information fields which may have been | |
662 | precomputed already. |
|
706 | precomputed already. | |
663 |
|
707 | |||
@@ -690,14 +734,12 b' class Inspector(Colorable):' | |||||
690 | ds = getdoc(obj) |
|
734 | ds = getdoc(obj) | |
691 | if ds is None: |
|
735 | if ds is None: | |
692 | ds = '<no docstring>' |
|
736 | ds = '<no docstring>' | |
693 | if formatter is not None: |
|
|||
694 | ds = formatter(ds) |
|
|||
695 |
|
737 | |||
696 | # store output in a dict, we initialize it here and fill it as we go |
|
738 | # store output in a dict, we initialize it here and fill it as we go | |
697 | out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) |
|
739 | out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) | |
698 |
|
740 | |||
699 | string_max = 200 # max size of strings to show (snipped if longer) |
|
741 | string_max = 200 # max size of strings to show (snipped if longer) | |
700 | shalf = int((string_max -5)/2) |
|
742 | shalf = int((string_max - 5) / 2) | |
701 |
|
743 | |||
702 | if ismagic: |
|
744 | if ismagic: | |
703 | obj_type_name = 'Magic function' |
|
745 | obj_type_name = 'Magic function' | |
@@ -798,7 +840,7 b' class Inspector(Colorable):' | |||||
798 | # reconstruct the function definition and print it: |
|
840 | # reconstruct the function definition and print it: | |
799 | defln = self._getdef(obj, oname) |
|
841 | defln = self._getdef(obj, oname) | |
800 | if defln: |
|
842 | if defln: | |
801 |
out['definition'] = |
|
843 | out['definition'] = defln | |
802 |
|
844 | |||
803 | # First, check whether the instance docstring is identical to the |
|
845 | # First, check whether the instance docstring is identical to the | |
804 | # class one, and print it separately if they don't coincide. In |
|
846 | # class one, and print it separately if they don't coincide. In | |
@@ -832,7 +874,7 b' class Inspector(Colorable):' | |||||
832 | if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): |
|
874 | if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): | |
833 | call_def = self._getdef(obj.__call__, oname) |
|
875 | call_def = self._getdef(obj.__call__, oname) | |
834 | if call_def: |
|
876 | if call_def: | |
835 |
call_def = |
|
877 | call_def = call_def | |
836 | # it may never be the case that call def and definition differ, |
|
878 | # it may never be the case that call def and definition differ, | |
837 | # but don't include the same signature twice |
|
879 | # but don't include the same signature twice | |
838 | if call_def != out.get('definition'): |
|
880 | if call_def != out.get('definition'): |
@@ -340,13 +340,13 b' if py3compat.PY3:' | |||||
340 | @skipif(not py3compat.PY3) |
|
340 | @skipif(not py3compat.PY3) | |
341 | def test_definition_kwonlyargs(): |
|
341 | def test_definition_kwonlyargs(): | |
342 | i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore |
|
342 | i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore | |
343 |
nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly) |
|
343 | nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)") | |
344 |
|
344 | |||
345 | def test_getdoc(): |
|
345 | def test_getdoc(): | |
346 | class A(object): |
|
346 | class A(object): | |
347 | """standard docstring""" |
|
347 | """standard docstring""" | |
348 | pass |
|
348 | pass | |
349 |
|
349 | |||
350 | class B(object): |
|
350 | class B(object): | |
351 | """standard docstring""" |
|
351 | """standard docstring""" | |
352 | def getdoc(self): |
|
352 | def getdoc(self): |
General Comments 0
You need to be logged in to leave comments.
Login now