##// END OF EJS Templates
Implement object info protocol....
Fernando Perez -
Show More
@@ -1165,6 +1165,10 b' class InteractiveShell(Configurable, Magic):'
1165
1165
1166 def object_inspect(self, oname):
1166 def object_inspect(self, oname):
1167 info = self._object_find(oname)
1167 info = self._object_find(oname)
1168 if info.found:
1169 return self.inspector.info(info.obj, info=info)
1170 else:
1171 return {}
1168
1172
1169 #-------------------------------------------------------------------------
1173 #-------------------------------------------------------------------------
1170 # Things related to history management
1174 # Things related to history management
@@ -25,6 +25,8 b' import os'
25 import string
25 import string
26 import sys
26 import sys
27 import types
27 import types
28 from collections import namedtuple
29 from itertools import izip_longest
28
30
29 # IPython's own
31 # IPython's own
30 from IPython.core import page
32 from IPython.core import page
@@ -36,45 +38,6 b' from IPython.utils.wildcard import list_namespace'
36 from IPython.utils.coloransi import *
38 from IPython.utils.coloransi import *
37
39
38 #****************************************************************************
40 #****************************************************************************
39 # HACK!!! This is a crude fix for bugs in python 2.3's inspect module. We
40 # simply monkeypatch inspect with code copied from python 2.4.
41 if sys.version_info[:2] == (2,3):
42 from inspect import ismodule, getabsfile, modulesbyfile
43 def getmodule(object):
44 """Return the module an object was defined in, or None if not found."""
45 if ismodule(object):
46 return object
47 if hasattr(object, '__module__'):
48 return sys.modules.get(object.__module__)
49 try:
50 file = getabsfile(object)
51 except TypeError:
52 return None
53 if file in modulesbyfile:
54 return sys.modules.get(modulesbyfile[file])
55 for module in sys.modules.values():
56 if hasattr(module, '__file__'):
57 modulesbyfile[
58 os.path.realpath(
59 getabsfile(module))] = module.__name__
60 if file in modulesbyfile:
61 return sys.modules.get(modulesbyfile[file])
62 main = sys.modules['__main__']
63 if not hasattr(object, '__name__'):
64 return None
65 if hasattr(main, object.__name__):
66 mainobject = getattr(main, object.__name__)
67 if mainobject is object:
68 return main
69 builtin = sys.modules['__builtin__']
70 if hasattr(builtin, object.__name__):
71 builtinobject = getattr(builtin, object.__name__)
72 if builtinobject is object:
73 return builtin
74
75 inspect.getmodule = getmodule
76
77 #****************************************************************************
78 # Builtin color schemes
41 # Builtin color schemes
79
42
80 Colors = TermColors # just a shorthand
43 Colors = TermColors # just a shorthand
@@ -103,7 +66,30 b' InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],'
103 'Linux')
66 'Linux')
104
67
105 #****************************************************************************
68 #****************************************************************************
106 # Auxiliary functions
69 # Auxiliary functions and objects
70
71 # See the messaging spec for the definition of all these fields. This list
72 # effectively defines the order of display
73 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
74 'length', 'file', 'definition', 'docstring', 'source',
75 'init_definition', 'class_docstring', 'init_docstring',
76 'call_def', 'call_docstring',
77 # These won't be printed but will be used to determine how to
78 # format the object
79 'ismagic', 'isalias',
80 ]
81
82
83 ObjectInfo = namedtuple('ObjectInfo', info_fields)
84
85
86 def mk_object_info(kw):
87 """Make a f"""
88 infodict = dict(izip_longest(info_fields, [None]))
89 infodict.update(kw)
90 return ObjectInfo(**infodict)
91
92
107 def getdoc(obj):
93 def getdoc(obj):
108 """Stable wrapper around inspect.getdoc.
94 """Stable wrapper around inspect.getdoc.
109
95
@@ -553,6 +539,215 b' class Inspector:'
553 page.page(output)
539 page.page(output)
554 # end pinfo
540 # end pinfo
555
541
542 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
543 """Compute a dict with detailed information about an object.
544
545 Optional arguments:
546
547 - oname: name of the variable pointing to the object.
548
549 - formatter: special formatter for docstrings (see pdoc)
550
551 - info: a structure with some information fields which may have been
552 precomputed already.
553
554 - detail_level: if set to 1, more information is given.
555 """
556
557 obj_type = type(obj)
558
559 header = self.__head
560 if info is None:
561 ismagic = 0
562 isalias = 0
563 ospace = ''
564 else:
565 ismagic = info.ismagic
566 isalias = info.isalias
567 ospace = info.namespace
568 # Get docstring, special-casing aliases:
569 if isalias:
570 if not callable(obj):
571 try:
572 ds = "Alias to the system command:\n %s" % obj[1]
573 except:
574 ds = "Alias: " + str(obj)
575 else:
576 ds = "Alias to " + str(obj)
577 if obj.__doc__:
578 ds += "\nDocstring:\n" + obj.__doc__
579 else:
580 ds = getdoc(obj)
581 if ds is None:
582 ds = '<no docstring>'
583 if formatter is not None:
584 ds = formatter(ds)
585
586 # store output in a dict, we'll later convert it to an ObjectInfo
587 out = {}
588
589 string_max = 200 # max size of strings to show (snipped if longer)
590 shalf = int((string_max -5)/2)
591
592 if ismagic:
593 obj_type_name = 'Magic function'
594 elif isalias:
595 obj_type_name = 'System alias'
596 else:
597 obj_type_name = obj_type.__name__
598 out['type_name'] = obj_type_name
599
600 try:
601 bclass = obj.__class__
602 out['base_class'] = str(bclass)
603 except: pass
604
605 # String form, but snip if too long in ? form (full in ??)
606 if detail_level >= self.str_detail_level:
607 try:
608 ostr = str(obj)
609 str_head = 'string_form'
610 if not detail_level and len(ostr)>string_max:
611 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
612 ostr = ("\n" + " " * len(str_head.expandtabs())).\
613 join(map(string.strip,ostr.split("\n")))
614 if ostr.find('\n') > -1:
615 # Print multi-line strings starting at the next line.
616 str_sep = '\n'
617 else:
618 str_sep = '\t'
619 out[str_head] = ostr
620 except:
621 pass
622
623 if ospace:
624 out['namespace'] = ospace
625
626 # Length (for strings and lists)
627 try:
628 out['length'] = str(len(obj))
629 except: pass
630
631 # Filename where object was defined
632 binary_file = False
633 try:
634 try:
635 fname = inspect.getabsfile(obj)
636 except TypeError:
637 # For an instance, the file that matters is where its class was
638 # declared.
639 if hasattr(obj,'__class__'):
640 fname = inspect.getabsfile(obj.__class__)
641 if fname.endswith('<string>'):
642 fname = 'Dynamically generated function. No source code available.'
643 if (fname.endswith('.so') or fname.endswith('.dll')):
644 binary_file = True
645 out['file'] = fname
646 except:
647 # if anything goes wrong, we don't want to show source, so it's as
648 # if the file was binary
649 binary_file = True
650
651 # reconstruct the function definition and print it:
652 defln = self._getdef(obj,oname)
653 if defln:
654 out['definition'] = self.format(defln)
655
656 # Docstrings only in detail 0 mode, since source contains them (we
657 # avoid repetitions). If source fails, we add them back, see below.
658 if ds and detail_level == 0:
659 out['docstring'] = indent(ds)
660
661 # Original source code for any callable
662 if detail_level:
663 # Flush the source cache because inspect can return out-of-date
664 # source
665 linecache.checkcache()
666 source_success = False
667 try:
668 try:
669 src = getsource(obj,binary_file)
670 except TypeError:
671 if hasattr(obj,'__class__'):
672 src = getsource(obj.__class__,binary_file)
673 if src is not None:
674 source = self.format(src)
675 out['source'] = source.rstrip()
676 source_success = True
677 except Exception, msg:
678 pass
679
680 # Constructor docstring for classes
681 if inspect.isclass(obj):
682 # reconstruct the function definition and print it:
683 try:
684 obj_init = obj.__init__
685 except AttributeError:
686 init_def = init_ds = None
687 else:
688 init_def = self._getdef(obj_init,oname)
689 init_ds = getdoc(obj_init)
690 # Skip Python's auto-generated docstrings
691 if init_ds and \
692 init_ds.startswith('x.__init__(...) initializes'):
693 init_ds = None
694
695 if init_def or init_ds:
696 if init_def:
697 out['init_definition'] = self.format(init_def)
698 if init_ds:
699 out['init_docstring'] = indent(init_ds)
700 # and class docstring for instances:
701 elif obj_type is types.InstanceType or \
702 isinstance(obj,object):
703
704 # First, check whether the instance docstring is identical to the
705 # class one, and print it separately if they don't coincide. In
706 # most cases they will, but it's nice to print all the info for
707 # objects which use instance-customized docstrings.
708 if ds:
709 try:
710 cls = getattr(obj,'__class__')
711 except:
712 class_ds = None
713 else:
714 class_ds = getdoc(cls)
715 # Skip Python's auto-generated docstrings
716 if class_ds and \
717 (class_ds.startswith('function(code, globals[,') or \
718 class_ds.startswith('instancemethod(function, instance,') or \
719 class_ds.startswith('module(name[,') ):
720 class_ds = None
721 if class_ds and ds != class_ds:
722 out['class_docstring'] = indent(class_ds)
723
724 # Next, try to show constructor docstrings
725 try:
726 init_ds = getdoc(obj.__init__)
727 # Skip Python's auto-generated docstrings
728 if init_ds and \
729 init_ds.startswith('x.__init__(...) initializes'):
730 init_ds = None
731 except AttributeError:
732 init_ds = None
733 if init_ds:
734 out['init_docstring'] = indent(init_ds)
735
736 # Call form docstring for callable instances
737 if hasattr(obj,'__call__'):
738 call_def = self._getdef(obj.__call__,oname)
739 if call_def is not None:
740 out['call_def'] = self.format(call_def)
741 call_ds = getdoc(obj.__call__)
742 # Skip Python's auto-generated docstrings
743 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
744 call_ds = None
745 if call_ds:
746 out['call_docstring'] = indent(call_ds)
747
748 return mk_object_info(out)
749
750
556 def psearch(self,pattern,ns_table,ns_search=[],
751 def psearch(self,pattern,ns_table,ns_search=[],
557 ignore_case=False,show_all=False):
752 ignore_case=False,show_all=False):
558 """Search namespaces with wildcards for objects.
753 """Search namespaces with wildcards for objects.
@@ -210,10 +210,11 b' class Kernel(Configurable):'
210 io.raw_print(completion_msg)
210 io.raw_print(completion_msg)
211
211
212 def object_info_request(self, ident, parent):
212 def object_info_request(self, ident, parent):
213 context = parent['content']['oname'].split('.')
213 ##context = parent['content']['oname'].split('.')
214 object_info = self._object_info(context)
214 ##object_info = self._object_info(context)
215 object_info = self.shell.object_inspect(parent['content']['oname'])
215 msg = self.session.send(self.reply_socket, 'object_info_reply',
216 msg = self.session.send(self.reply_socket, 'object_info_reply',
216 object_info, parent, ident)
217 object_info._asdict(), parent, ident)
217 io.raw_print(msg)
218 io.raw_print(msg)
218
219
219 def history_request(self, ident, parent):
220 def history_request(self, ident, parent):
@@ -450,13 +450,18 b' Message type: ``object_info_reply``::'
450 # For instances, provide the constructor and class docstrings
450 # For instances, provide the constructor and class docstrings
451 'init_docstring' : str,
451 'init_docstring' : str,
452 'class_docstring' : str,
452 'class_docstring' : str,
453
453
454 # If it's a callable object whose call method has a separate docstring and
455 # definition line:
456 'call_def' : str,
457 'call_docstring' : str,
458
454 # If detail_level was 1, we also try to find the source code that
459 # If detail_level was 1, we also try to find the source code that
455 # defines the object, if possible. The string 'None' will indicate
460 # defines the object, if possible. The string 'None' will indicate
456 # that no source was found.
461 # that no source was found.
457 'source' : str,
462 'source' : str,
458 }
463 }
459
464 '
460
465
461 Complete
466 Complete
462 --------
467 --------
General Comments 0
You need to be logged in to leave comments. Login now