]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/PyCrust/introspect.py
7f4efb64c12f2646487daff4ae6cbfdef4fe1fac
   1 """Provides a variety of introspective-type support functions for things 
   2 like call tips and command auto completion.""" 
   4 __author__ 
= "Patrick K. O'Brien <pobrien@orbtech.com>" 
   6 __version__ 
= "$Revision$"[11:-2] 
  12 def getAutoCompleteList(command
='', locals=None, includeMagic
=1, \
 
  13                         includeSingle
=1, includeDouble
=1): 
  14     """Return list of auto-completion options for command. 
  16     The list of options will be based on the locals namespace.""" 
  18     # Get the proper chunk of code from the command. 
  19     root 
= getRoot(command
, terminator
='.') 
  21         object = eval(root
, locals) 
  22         attributes 
= getAttributeNames(object, includeMagic
, \
 
  23                                        includeSingle
, includeDouble
) 
  28 def getAttributeNames(object, includeMagic
=1, includeSingle
=1, includeDouble
=1): 
  29     """Return list of unique attributes, including inherited, for an object.""" 
  33         try: attributes 
+= object._getAttributeNames
() 
  35     # Get all attribute names, removing duplicates from the attribute list. 
  36     for item 
in getAllAttributeNames(object): 
  38     attributes 
+= dict.keys() 
  39     attributes
.sort(lambda x
, y
: cmp(x
.upper(), y
.upper())) 
  41         attributes 
= filter(lambda item
: item
[0]!='_' or item
[1]=='_', attributes
) 
  43         attributes 
= filter(lambda item
: item
[:2]!='__', attributes
) 
  44     # Make sure we haven't picked up any bogus attributes somehow. 
  45     attributes 
= [attribute 
for attribute 
in attributes 
if hasattr(object, attribute
)] 
  48 def getAllAttributeNames(object): 
  49     """Return list of all attributes, including inherited, for an object. 
  51     Recursively walk through a class and all base classes. 
  54     # !!! Do Not use hasattr() as a test anywhere in this function, 
  55     # !!! because it is unreliable with remote objects - xmlrpc, soap, etc. 
  58     # Wake up sleepy objects - a hack for ZODB objects in "ghost" state. 
  59     wakeupcall 
= dir(object) 
  61     # Get attributes available through the normal convention. 
  62     attributes 
+= dir(object) 
  64         keys 
= object.__dict
__.keys() 
  69     # For a class instance, get the attributes for the class. 
  70     if hasattr(object, '__class__'): 
  71         # Break a circular reference. This happens with extension classes. 
  72         if object.__class
__ is object: 
  75             attributes 
+= getAllAttributeNames(object.__class
__) 
  76     # Also get attributes from any and all parent classes. 
  78         bases 
= object.__bases
__ 
  82         if isinstance(bases
, type(())): 
  84                 if type(base
) is types
.TypeType
: 
  85                     # Break a circular reference. Happens in Python 2.2. 
  88                     attributes 
+= getAllAttributeNames(base
) 
  91 def getCallTip(command
='', locals=None): 
  92     """Return call tip text for a command. 
  94     The call tip information will be based on the locals namespace.""" 
  96     calltip 
= ('', '', '') 
  97     # Get the proper chunk of code from the command. 
  98     root 
= getRoot(command
, terminator
='(') 
 100         object = eval(root
, locals) 
 105     # Switch to the object that has the information we need. 
 106     if inspect
.isbuiltin(object): 
 107         # Builtin functions don't have an argspec that we can get. 
 109     elif inspect
.ismethod(object) or hasattr(object, 'im_func'): 
 110         # Get the function from the object otherwise inspect.getargspec() 
 111         # complains that the object isn't a Python function. 
 112         object = object.im_func
 
 113     elif inspect
.isclass(object): 
 114         # Get the __init__ method function for the class. 
 115         constructor 
= getConstructor(object) 
 116         if constructor 
is not None: 
 118     elif callable(object): 
 119         # Get the __call__ method instead. 
 121             object = object.__call
__.im_func
 
 126     if hasattr(object, '__name__'): 
 127         name 
= object.__name
__ 
 130     if inspect
.isbuiltin(object): 
 131         # Builtin functions don't have an argspec that we can get. 
 133     elif inspect
.isfunction(object): 
 134         # tip1 is a string like: "getCallTip(command='', locals=None)" 
 135         argspec 
= apply(inspect
.formatargspec
, inspect
.getargspec(object)) 
 137             # The first parameter to a method is a reference to the 
 138             # instance, usually coded as "self", and is passed 
 139             # automatically by Python and therefore we want to drop it. 
 140             temp 
= argspec
.split(',') 
 141             if len(temp
) == 1:  # No other arguments. 
 143             else:  # Drop the first argument. 
 144                 argspec 
= '(' + ','.join(temp
[1:]).lstrip() 
 145         tip1 
= name 
+ argspec
 
 146     doc 
= inspect
.getdoc(object) 
 148         # tip2 is the first separated line of the docstring, like: 
 149         # "Return call tip text for a command." 
 150         # tip3 is the rest of the docstring, like: 
 151         # "The call tip information will be based on ... <snip> 
 152         docpieces 
= doc
.split('\n\n') 
 154         tip3 
= '\n\n'.join(docpieces
[1:]) 
 155         tip 
= '%s\n\n%s\n\n%s' % (tip1
, tip2
, tip3
) 
 158     calltip 
= (name
, argspec
[1:-1], tip
.strip()) 
 161 def getConstructor(object): 
 162     """Return constructor for class object, or None if there isn't one.""" 
 164         return object.__init
__.im_func
 
 165     except AttributeError: 
 166         for base 
in object.__bases
__: 
 167             constructor 
= getConstructor(base
) 
 168             if constructor 
is not None: 
 172 def getRoot(command
, terminator
=None): 
 173     """Return the rightmost root portion of an arbitrary Python command. 
 175     The command would normally terminate with a "(" or ".". Anything after  
 176     the terminator will be dropped, allowing you to get back to the root. 
 177     Return only the root portion that can be eval()'d without side effects. 
 180     validChars 
= "._" + string
.uppercase 
+ string
.lowercase 
+ string
.digits
 
 182         # Drop the final terminator and anything that follows. 
 183         pieces 
= command
.split(terminator
) 
 185             command 
= terminator
.join(pieces
[:-1]) 
 186     if len(command
) == 0: 
 188     elif command 
in ("''", '""', '""""""', '[]', '()', '{}'): 
 189         # Let empty type delimiter pairs go through. 
 192         # Go backward through the command until we hit an "invalid" character. 
 194         while i 
and command
[i
-1] in validChars
: 
 196         # Detect situations where we are in the middle of a string. 
 197         # This code catches the simplest case, but needs to catch others. 
 198         if command
[i
-1] in ("'", '"'): 
 199             # We're in the middle of a string so we aren't dealing with an 
 200             # object and it would be misleading to return anything here. 
 203             # Grab everything from the "invalid" character to the end.