Commit ecf796ed authored by Kurt B. Kaiser's avatar Kurt B. Kaiser

1. Calltips now 'handle' tuples in the argument list (display '<tuple>' :)

   Suggested solution by Christos Georgiou, Bug 791968.
2. Clean up tests, were not failing when they should have been.
4. Remove some camelcase and an unneeded try/except block.
parent 90f84922
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
Call Tips are floating windows which display function, class, and method Call Tips are floating windows which display function, class, and method
parameter and docstring information when you type an opening parenthesis, and parameter and docstring information when you type an opening parenthesis, and
which disappear when you type a closing parenthesis. which disappear when you type a closing parenthesis.
""" """
import re
import sys import sys
import types import types
...@@ -89,6 +91,8 @@ class CallTips: ...@@ -89,6 +91,8 @@ class CallTips:
two unrelated modules are being edited some calltips in the current two unrelated modules are being edited some calltips in the current
module may be inoperative if the module was not the last to run. module may be inoperative if the module was not the last to run.
To find methods, fetch_tip must be fed a fully qualified name.
""" """
try: try:
rpcclt = self.editwin.flist.pyshell.interp.rpcclt rpcclt = self.editwin.flist.pyshell.interp.rpcclt
...@@ -108,7 +112,7 @@ class CallTips: ...@@ -108,7 +112,7 @@ class CallTips:
namespace.update(__main__.__dict__) namespace.update(__main__.__dict__)
try: try:
return eval(name, namespace) return eval(name, namespace)
except: except NameError:
return None return None
def _find_constructor(class_ob): def _find_constructor(class_ob):
...@@ -124,39 +128,37 @@ def _find_constructor(class_ob): ...@@ -124,39 +128,37 @@ def _find_constructor(class_ob):
def get_arg_text(ob): def get_arg_text(ob):
"""Get a string describing the arguments for the given object""" """Get a string describing the arguments for the given object"""
argText = "" arg_text = ""
if ob is not None: if ob is not None:
argOffset = 0 arg_offset = 0
if type(ob) in (types.ClassType, types.TypeType): if type(ob) in (types.ClassType, types.TypeType):
# Look for the highest __init__ in the class chain. # Look for the highest __init__ in the class chain.
fob = _find_constructor(ob) fob = _find_constructor(ob)
if fob is None: if fob is None:
fob = lambda: None fob = lambda: None
else: else:
argOffset = 1 arg_offset = 1
elif type(ob)==types.MethodType: elif type(ob)==types.MethodType:
# bit of a hack for methods - turn it into a function # bit of a hack for methods - turn it into a function
# but we drop the "self" param. # but we drop the "self" param.
fob = ob.im_func fob = ob.im_func
argOffset = 1 arg_offset = 1
else: else:
fob = ob fob = ob
# Try and build one for Python defined functions # Try to build one for Python defined functions
if type(fob) in [types.FunctionType, types.LambdaType]: if type(fob) in [types.FunctionType, types.LambdaType]:
try: argcount = fob.func_code.co_argcount
realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount] real_args = fob.func_code.co_varnames[arg_offset:argcount]
defaults = fob.func_defaults or [] defaults = fob.func_defaults or []
defaults = list(map(lambda name: "=%s" % repr(name), defaults)) defaults = list(map(lambda name: "=%s" % repr(name), defaults))
defaults = [""] * (len(realArgs)-len(defaults)) + defaults defaults = [""] * (len(real_args) - len(defaults)) + defaults
items = map(lambda arg, dflt: arg+dflt, realArgs, defaults) items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
if fob.func_code.co_flags & 0x4: if fob.func_code.co_flags & 0x4:
items.append("...") items.append("...")
if fob.func_code.co_flags & 0x8: if fob.func_code.co_flags & 0x8:
items.append("***") items.append("***")
argText = ", ".join(items) arg_text = ", ".join(items)
argText = "(%s)" % argText arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", arg_text)
except:
pass
# See if we can use the docstring # See if we can use the docstring
doc = getattr(ob, "__doc__", "") doc = getattr(ob, "__doc__", "")
if doc: if doc:
...@@ -164,10 +166,10 @@ def get_arg_text(ob): ...@@ -164,10 +166,10 @@ def get_arg_text(ob):
pos = doc.find("\n") pos = doc.find("\n")
if pos < 0 or pos > 70: if pos < 0 or pos > 70:
pos = 70 pos = 70
if argText: if arg_text:
argText += "\n" arg_text += "\n"
argText += doc[:pos] arg_text += doc[:pos]
return argText return arg_text
################################################# #################################################
# #
...@@ -181,16 +183,18 @@ if __name__=='__main__': ...@@ -181,16 +183,18 @@ if __name__=='__main__':
def t4(*args): "(...)" def t4(*args): "(...)"
def t5(a, *args): "(a, ...)" def t5(a, *args): "(a, ...)"
def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)" def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
def t7((a, b), c, (d, e)): "(<tuple>, c, <tuple>)"
class TC: class TC(object):
"(a=None, ...)" "(ai=None, ...)"
def __init__(self, a=None, *b): "(a=None, ...)" def __init__(self, ai=None, *b): "(ai=None, ...)"
def t1(self): "()" def t1(self): "()"
def t2(self, a, b=None): "(a, b=None)" def t2(self, ai, b=None): "(ai, b=None)"
def t3(self, a, *args): "(a, ...)" def t3(self, ai, *args): "(ai, ...)"
def t4(self, *args): "(...)" def t4(self, *args): "(...)"
def t5(self, a, *args): "(a, ...)" def t5(self, ai, *args): "(ai, ...)"
def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)" def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)"
def t7(self, (ai, b), c, (d, e)): "(<tuple>, c, <tuple>)"
def test(tests): def test(tests):
ct = CallTips() ct = CallTips()
...@@ -198,15 +202,20 @@ if __name__=='__main__': ...@@ -198,15 +202,20 @@ if __name__=='__main__':
for t in tests: for t in tests:
expected = t.__doc__ + "\n" + t.__doc__ expected = t.__doc__ + "\n" + t.__doc__
name = t.__name__ name = t.__name__
arg_text = ct.fetch_tip(name) # exercise fetch_tip(), not just get_arg_text()
try:
qualified_name = "%s.%s" % (t.im_class.__name__, name)
except AttributeError:
qualified_name = name
arg_text = ct.fetch_tip(qualified_name)
if arg_text != expected: if arg_text != expected:
failed.append(t) failed.append(t)
print "%s - expected %s, but got %s" % (t, expected, fmt = "%s - expected %s, but got %s"
get_arg_text(entity)) print fmt % (t.__name__, expected, get_arg_text(t))
print "%d of %d tests failed" % (len(failed), len(tests)) print "%d of %d tests failed" % (len(failed), len(tests))
tc = TC() tc = TC()
tests = (t1, t2, t3, t4, t5, t6, tests = (t1, t2, t3, t4, t5, t6, t7,
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6) TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7)
test(tests) test(tests)
...@@ -3,6 +3,9 @@ What's New in IDLE 2.6a1? ...@@ -3,6 +3,9 @@ What's New in IDLE 2.6a1?
*Release date: XX-XXX-200X* *Release date: XX-XXX-200X*
- Calltips now 'handle' tuples in the argument list (display '<tuple>' :)
Suggested solution by Christos Georgiou, Bug 791968.
- Add 'raw' support to configHandler. Patch 1650174 Tal Einat. - Add 'raw' support to configHandler. Patch 1650174 Tal Einat.
- Avoid hang when encountering a duplicate in a completion list. Bug 1571112. - Avoid hang when encountering a duplicate in a completion list. Bug 1571112.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment