source: python/vendor/Python-2.7.6/Lib/idlelib/CallTips.py

Last change on this file was 388, checked in by dmik, 11 years ago

python: Update vendor to 2.7.6.

  • Property svn:eol-style set to native
File size: 7.9 KB
Line 
1"""CallTips.py - An IDLE Extension to Jog Your Memory
2
3Call Tips are floating windows which display function, class, and method
4parameter and docstring information when you type an opening parenthesis, and
5which disappear when you type a closing parenthesis.
6
7"""
8import re
9import sys
10import types
11
12from idlelib import CallTipWindow
13from idlelib.HyperParser import HyperParser
14
15import __main__
16
17class CallTips:
18
19 menudefs = [
20 ('edit', [
21 ("Show call tip", "<<force-open-calltip>>"),
22 ])
23 ]
24
25 def __init__(self, editwin=None):
26 if editwin is None: # subprocess and test
27 self.editwin = None
28 return
29 self.editwin = editwin
30 self.text = editwin.text
31 self.calltip = None
32 self._make_calltip_window = self._make_tk_calltip_window
33
34 def close(self):
35 self._make_calltip_window = None
36
37 def _make_tk_calltip_window(self):
38 # See __init__ for usage
39 return CallTipWindow.CallTip(self.text)
40
41 def _remove_calltip_window(self, event=None):
42 if self.calltip:
43 self.calltip.hidetip()
44 self.calltip = None
45
46 def force_open_calltip_event(self, event):
47 """Happens when the user really wants to open a CallTip, even if a
48 function call is needed.
49 """
50 self.open_calltip(True)
51
52 def try_open_calltip_event(self, event):
53 """Happens when it would be nice to open a CallTip, but not really
54 necessary, for example after an opening bracket, so function calls
55 won't be made.
56 """
57 self.open_calltip(False)
58
59 def refresh_calltip_event(self, event):
60 """If there is already a calltip window, check if it is still needed,
61 and if so, reload it.
62 """
63 if self.calltip and self.calltip.is_active():
64 self.open_calltip(False)
65
66 def open_calltip(self, evalfuncs):
67 self._remove_calltip_window()
68
69 hp = HyperParser(self.editwin, "insert")
70 sur_paren = hp.get_surrounding_brackets('(')
71 if not sur_paren:
72 return
73 hp.set_index(sur_paren[0])
74 expression = hp.get_expression()
75 if not expression or (not evalfuncs and expression.find('(') != -1):
76 return
77 arg_text = self.fetch_tip(expression)
78 if not arg_text:
79 return
80 self.calltip = self._make_calltip_window()
81 self.calltip.showtip(arg_text, sur_paren[0], sur_paren[1])
82
83 def fetch_tip(self, expression):
84 """Return the argument list and docstring of a function or class
85
86 If there is a Python subprocess, get the calltip there. Otherwise,
87 either fetch_tip() is running in the subprocess itself or it was called
88 in an IDLE EditorWindow before any script had been run.
89
90 The subprocess environment is that of the most recently run script. If
91 two unrelated modules are being edited some calltips in the current
92 module may be inoperative if the module was not the last to run.
93
94 To find methods, fetch_tip must be fed a fully qualified name.
95
96 """
97 try:
98 rpcclt = self.editwin.flist.pyshell.interp.rpcclt
99 except AttributeError:
100 rpcclt = None
101 if rpcclt:
102 return rpcclt.remotecall("exec", "get_the_calltip",
103 (expression,), {})
104 else:
105 entity = self.get_entity(expression)
106 return get_arg_text(entity)
107
108 def get_entity(self, expression):
109 """Return the object corresponding to expression evaluated
110 in a namespace spanning sys.modules and __main.dict__.
111 """
112 if expression:
113 namespace = sys.modules.copy()
114 namespace.update(__main__.__dict__)
115 try:
116 return eval(expression, namespace)
117 except BaseException:
118 # An uncaught exception closes idle, and eval can raise any
119 # exception, especially if user classes are involved.
120 return None
121
122def _find_constructor(class_ob):
123 # Given a class object, return a function object used for the
124 # constructor (ie, __init__() ) or None if we can't find one.
125 try:
126 return class_ob.__init__.im_func
127 except AttributeError:
128 for base in class_ob.__bases__:
129 rc = _find_constructor(base)
130 if rc is not None: return rc
131 return None
132
133def get_arg_text(ob):
134 """Get a string describing the arguments for the given object,
135 only if it is callable."""
136 arg_text = ""
137 if ob is not None and hasattr(ob, '__call__'):
138 arg_offset = 0
139 if type(ob) in (types.ClassType, types.TypeType):
140 # Look for the highest __init__ in the class chain.
141 fob = _find_constructor(ob)
142 if fob is None:
143 fob = lambda: None
144 else:
145 arg_offset = 1
146 elif type(ob)==types.MethodType:
147 # bit of a hack for methods - turn it into a function
148 # but we drop the "self" param.
149 fob = ob.im_func
150 arg_offset = 1
151 else:
152 fob = ob
153 # Try to build one for Python defined functions
154 if type(fob) in [types.FunctionType, types.LambdaType]:
155 argcount = fob.func_code.co_argcount
156 real_args = fob.func_code.co_varnames[arg_offset:argcount]
157 defaults = fob.func_defaults or []
158 defaults = list(map(lambda name: "=%s" % repr(name), defaults))
159 defaults = [""] * (len(real_args) - len(defaults)) + defaults
160 items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
161 if fob.func_code.co_flags & 0x4:
162 items.append("...")
163 if fob.func_code.co_flags & 0x8:
164 items.append("***")
165 arg_text = ", ".join(items)
166 arg_text = "(%s)" % re.sub("(?<!\d)\.\d+", "<tuple>", arg_text)
167 # See if we can use the docstring
168 doc = getattr(ob, "__doc__", "")
169 if doc:
170 doc = doc.lstrip()
171 pos = doc.find("\n")
172 if pos < 0 or pos > 70:
173 pos = 70
174 if arg_text:
175 arg_text += "\n"
176 arg_text += doc[:pos]
177 return arg_text
178
179#################################################
180#
181# Test code
182#
183if __name__=='__main__':
184
185 def t1(): "()"
186 def t2(a, b=None): "(a, b=None)"
187 def t3(a, *args): "(a, ...)"
188 def t4(*args): "(...)"
189 def t5(a, *args): "(a, ...)"
190 def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
191 def t7((a, b), c, (d, e)): "(<tuple>, c, <tuple>)"
192
193 class TC(object):
194 "(ai=None, ...)"
195 def __init__(self, ai=None, *b): "(ai=None, ...)"
196 def t1(self): "()"
197 def t2(self, ai, b=None): "(ai, b=None)"
198 def t3(self, ai, *args): "(ai, ...)"
199 def t4(self, *args): "(...)"
200 def t5(self, ai, *args): "(ai, ...)"
201 def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)"
202 def t7(self, (ai, b), c, (d, e)): "(<tuple>, c, <tuple>)"
203
204 def test(tests):
205 ct = CallTips()
206 failed=[]
207 for t in tests:
208 expected = t.__doc__ + "\n" + t.__doc__
209 name = t.__name__
210 # exercise fetch_tip(), not just get_arg_text()
211 try:
212 qualified_name = "%s.%s" % (t.im_class.__name__, name)
213 except AttributeError:
214 qualified_name = name
215 arg_text = ct.fetch_tip(qualified_name)
216 if arg_text != expected:
217 failed.append(t)
218 fmt = "%s - expected %s, but got %s"
219 print fmt % (t.__name__, expected, get_arg_text(t))
220 print "%d of %d tests failed" % (len(failed), len(tests))
221
222 tc = TC()
223 tests = (t1, t2, t3, t4, t5, t6, t7,
224 TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7)
225
226 # test(tests)
227 from unittest import main
228 main('idlelib.idle_test.test_calltips', verbosity=2, exit=False)
Note: See TracBrowser for help on using the repository browser.