Add PyErr_WarnEx()
[pytest.git] / Lib / idlelib / CallTips.py
blob997eb13a0f9fb5314033aaedba57ad26b4386ef5
1 """CallTips.py - An IDLE Extension to Jog Your Memory
3 Call Tips are floating windows which display function, class, and method
4 parameter and docstring information when you type an opening parenthesis, and
5 which disappear when you type a closing parenthesis.
6 """
7 import sys
8 import types
10 import CallTipWindow
11 from HyperParser import HyperParser
13 import __main__
15 class CallTips:
17 menudefs = [
18 ('edit', [
19 ("Show call tip", "<<force-open-calltip>>"),
23 def __init__(self, editwin=None):
24 if editwin is None: # subprocess and test
25 self.editwin = None
26 return
27 self.editwin = editwin
28 self.text = editwin.text
29 self.calltip = None
30 self._make_calltip_window = self._make_tk_calltip_window
32 def close(self):
33 self._make_calltip_window = None
35 def _make_tk_calltip_window(self):
36 # See __init__ for usage
37 return CallTipWindow.CallTip(self.text)
39 def _remove_calltip_window(self, event=None):
40 if self.calltip:
41 self.calltip.hidetip()
42 self.calltip = None
44 def force_open_calltip_event(self, event):
45 """Happens when the user really wants to open a CallTip, even if a
46 function call is needed.
47 """
48 self.open_calltip(True)
50 def try_open_calltip_event(self, event):
51 """Happens when it would be nice to open a CallTip, but not really
52 neccesary, for example after an opening bracket, so function calls
53 won't be made.
54 """
55 self.open_calltip(False)
57 def refresh_calltip_event(self, event):
58 """If there is already a calltip window, check if it is still needed,
59 and if so, reload it.
60 """
61 if self.calltip and self.calltip.is_active():
62 self.open_calltip(False)
64 def open_calltip(self, evalfuncs):
65 self._remove_calltip_window()
67 hp = HyperParser(self.editwin, "insert")
68 sur_paren = hp.get_surrounding_brackets('(')
69 if not sur_paren:
70 return
71 hp.set_index(sur_paren[0])
72 name = hp.get_expression()
73 if not name or (not evalfuncs and name.find('(') != -1):
74 return
75 arg_text = self.fetch_tip(name)
76 if not arg_text:
77 return
78 self.calltip = self._make_calltip_window()
79 self.calltip.showtip(arg_text, sur_paren[0], sur_paren[1])
81 def fetch_tip(self, name):
82 """Return the argument list and docstring of a function or class
84 If there is a Python subprocess, get the calltip there. Otherwise,
85 either fetch_tip() is running in the subprocess itself or it was called
86 in an IDLE EditorWindow before any script had been run.
88 The subprocess environment is that of the most recently run script. If
89 two unrelated modules are being edited some calltips in the current
90 module may be inoperative if the module was not the last to run.
92 """
93 try:
94 rpcclt = self.editwin.flist.pyshell.interp.rpcclt
95 except:
96 rpcclt = None
97 if rpcclt:
98 return rpcclt.remotecall("exec", "get_the_calltip",
99 (name,), {})
100 else:
101 entity = self.get_entity(name)
102 return get_arg_text(entity)
104 def get_entity(self, name):
105 "Lookup name in a namespace spanning sys.modules and __main.dict__"
106 if name:
107 namespace = sys.modules.copy()
108 namespace.update(__main__.__dict__)
109 try:
110 return eval(name, namespace)
111 except:
112 return None
114 def _find_constructor(class_ob):
115 # Given a class object, return a function object used for the
116 # constructor (ie, __init__() ) or None if we can't find one.
117 try:
118 return class_ob.__init__.im_func
119 except AttributeError:
120 for base in class_ob.__bases__:
121 rc = _find_constructor(base)
122 if rc is not None: return rc
123 return None
125 def get_arg_text(ob):
126 """Get a string describing the arguments for the given object"""
127 argText = ""
128 if ob is not None:
129 argOffset = 0
130 if type(ob) in (types.ClassType, types.TypeType):
131 # Look for the highest __init__ in the class chain.
132 fob = _find_constructor(ob)
133 if fob is None:
134 fob = lambda: None
135 else:
136 argOffset = 1
137 elif type(ob)==types.MethodType:
138 # bit of a hack for methods - turn it into a function
139 # but we drop the "self" param.
140 fob = ob.im_func
141 argOffset = 1
142 else:
143 fob = ob
144 # Try and build one for Python defined functions
145 if type(fob) in [types.FunctionType, types.LambdaType]:
146 try:
147 realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount]
148 defaults = fob.func_defaults or []
149 defaults = list(map(lambda name: "=%s" % repr(name), defaults))
150 defaults = [""] * (len(realArgs)-len(defaults)) + defaults
151 items = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
152 if fob.func_code.co_flags & 0x4:
153 items.append("...")
154 if fob.func_code.co_flags & 0x8:
155 items.append("***")
156 argText = ", ".join(items)
157 argText = "(%s)" % argText
158 except:
159 pass
160 # See if we can use the docstring
161 doc = getattr(ob, "__doc__", "")
162 if doc:
163 doc = doc.lstrip()
164 pos = doc.find("\n")
165 if pos < 0 or pos > 70:
166 pos = 70
167 if argText:
168 argText += "\n"
169 argText += doc[:pos]
170 return argText
172 #################################################
174 # Test code
176 if __name__=='__main__':
178 def t1(): "()"
179 def t2(a, b=None): "(a, b=None)"
180 def t3(a, *args): "(a, ...)"
181 def t4(*args): "(...)"
182 def t5(a, *args): "(a, ...)"
183 def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
185 class TC:
186 "(a=None, ...)"
187 def __init__(self, a=None, *b): "(a=None, ...)"
188 def t1(self): "()"
189 def t2(self, a, b=None): "(a, b=None)"
190 def t3(self, a, *args): "(a, ...)"
191 def t4(self, *args): "(...)"
192 def t5(self, a, *args): "(a, ...)"
193 def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"
195 def test(tests):
196 ct = CallTips()
197 failed=[]
198 for t in tests:
199 expected = t.__doc__ + "\n" + t.__doc__
200 name = t.__name__
201 arg_text = ct.fetch_tip(name)
202 if arg_text != expected:
203 failed.append(t)
204 print "%s - expected %s, but got %s" % (t, expected,
205 get_arg_text(entity))
206 print "%d of %d tests failed" % (len(failed), len(tests))
208 tc = TC()
209 tests = (t1, t2, t3, t4, t5, t6,
210 TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6)
212 test(tests)