]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/PyCrust/introspect.py
4f3abd1477ea638bb201981d8390b6fcfea2b817
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 __date__
= "August 8, 2001"
7 __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()
41 attributes
= filter(lambda item
: item
[0]!='_' or item
[1]=='_', attributes
)
43 attributes
= filter(lambda item
: item
[:2]!='__', attributes
)
46 def getAllAttributeNames(object):
47 """Return list of all attributes, including inherited, for an object.
49 Recursively walk through a class and all base classes.
52 # Get attributes available through the normal convention.
53 attributes
+= dir(object)
54 # For a class instance, get the attributes for the class.
55 if hasattr(object, '__class__'):
56 attributes
+= getAllAttributeNames(object.__class
__)
57 # Also get attributes from any and all parent classes.
58 if hasattr(object, '__bases__'):
59 for base
in object.__bases
__:
60 attributes
+= getAllAttributeNames(base
)
63 def getCallTip(command
='', locals=None):
64 """Return call tip text for a command.
66 The call tip information will be based on the locals namespace."""
68 # Get the proper chunk of code from the command.
69 root
= getRoot(command
, terminator
='(')
71 object = eval(root
, locals)
75 if hasattr(object, '__name__'): # Make sure this is a useable object.
76 # Switch to the object that has the information we need.
77 if inspect
.ismethod(object):
78 # Get the function from the object otherwise inspec.getargspec()
79 # complains that the object isn't a Python function.
80 object = object.im_func
82 elif inspect
.isclass(object):
83 # Get the __init__ method for the class.
85 object = object.__init
__.im_func
87 except AttributeError:
88 for base
in object.__bases
__:
89 constructor
= _find_constructor(base
)
90 if constructor
is not None:
94 name
= object.__name
__
95 if inspect
.isbuiltin(object):
96 # Builtin functions don't have an argspec that we can get.
99 # tip1 is a string like: "getCallTip(command='', locals=None)"
100 argspec
= apply(inspect
.formatargspec
, inspect
.getargspec(object))
102 # The first parameter to a method is a reference to the
103 # instance, usually coded as "self", and is passed
104 # automatically by Python and therefore we want to drop it.
105 temp
= argspec
.split(',')
106 if len(temp
) == 1: # No other arguments.
108 else: # Drop the first argument.
109 argspec
= '(' + ','.join(temp
[1:]).lstrip()
110 tip1
= name
+ argspec
111 doc
= inspect
.getdoc(object)
113 # tip2 is the first separated line of the docstring, like:
114 # "Return call tip text for a command."
115 # tip3 is the rest of the docstring, like:
116 # "The call tip information will be based on ... <snip>
117 docpieces
= doc
.split('\n\n')
119 tip3
= '\n\n'.join(docpieces
[1:])
120 tip
= '%s\n\n%s\n\n%s' % (tip1
, tip2
, tip3
)
127 def getRoot(command
, terminator
=None):
128 """Return the rightmost root portion of an arbitrary Python command.
130 The command would normally terminate with a "(" or ".". Anything after
131 the terminator will be dropped, allowing you to get back to the root.
132 Return only the root portion that can be eval()'d without side effect.
135 validChars
= "._" + string
.uppercase
+ string
.lowercase
+ string
.digits
137 # Drop the final terminator and anything that follows.
138 pieces
= command
.split(terminator
)
140 command
= terminator
.join(pieces
[:-1])
141 if len(command
) == 0:
143 elif command
in ("''", '""', '""""""', '[]', '()', '{}'):
144 # Let empty type delimiter pairs go through.
147 # Go backward through the command until we hit an "invalid" character.
149 while i
and command
[i
-1] in validChars
:
151 # Detect situations where we are in the middle of a string.
152 # This code catches the simplest case, but needs to catch others.
153 if command
[i
-1] in ("'", '"'):
154 # Were in the middle of a string so we aren't dealing with an
155 # object and it would be misleading to return anything here.
158 # Grab everything from the "invalid" character to the end.