symbian-qemu-0.9.1-12/python-2.6.1/Lib/idlelib/CallTips.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """CallTips.py - An IDLE Extension to Jog Your Memory
       
     2 
       
     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 """
       
     8 import re
       
     9 import sys
       
    10 import types
       
    11 
       
    12 import CallTipWindow
       
    13 from HyperParser import HyperParser
       
    14 
       
    15 import __main__
       
    16 
       
    17 class 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         neccesary, 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         name = hp.get_expression()
       
    75         if not name or (not evalfuncs and name.find('(') != -1):
       
    76             return
       
    77         arg_text = self.fetch_tip(name)
       
    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, name):
       
    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:
       
   100             rpcclt = None
       
   101         if rpcclt:
       
   102             return rpcclt.remotecall("exec", "get_the_calltip",
       
   103                                      (name,), {})
       
   104         else:
       
   105             entity = self.get_entity(name)
       
   106             return get_arg_text(entity)
       
   107 
       
   108     def get_entity(self, name):
       
   109         "Lookup name in a namespace spanning sys.modules and __main.dict__"
       
   110         if name:
       
   111             namespace = sys.modules.copy()
       
   112             namespace.update(__main__.__dict__)
       
   113             try:
       
   114                 return eval(name, namespace)
       
   115             except (NameError, AttributeError):
       
   116                 return None
       
   117 
       
   118 def _find_constructor(class_ob):
       
   119     # Given a class object, return a function object used for the
       
   120     # constructor (ie, __init__() ) or None if we can't find one.
       
   121     try:
       
   122         return class_ob.__init__.im_func
       
   123     except AttributeError:
       
   124         for base in class_ob.__bases__:
       
   125             rc = _find_constructor(base)
       
   126             if rc is not None: return rc
       
   127     return None
       
   128 
       
   129 def get_arg_text(ob):
       
   130     """Get a string describing the arguments for the given object"""
       
   131     arg_text = ""
       
   132     if ob is not None:
       
   133         arg_offset = 0
       
   134         if type(ob) in (types.ClassType, types.TypeType):
       
   135             # Look for the highest __init__ in the class chain.
       
   136             fob = _find_constructor(ob)
       
   137             if fob is None:
       
   138                 fob = lambda: None
       
   139             else:
       
   140                 arg_offset = 1
       
   141         elif type(ob)==types.MethodType:
       
   142             # bit of a hack for methods - turn it into a function
       
   143             # but we drop the "self" param.
       
   144             fob = ob.im_func
       
   145             arg_offset = 1
       
   146         else:
       
   147             fob = ob
       
   148         # Try to build one for Python defined functions
       
   149         if type(fob) in [types.FunctionType, types.LambdaType]:
       
   150             argcount = fob.func_code.co_argcount
       
   151             real_args = fob.func_code.co_varnames[arg_offset:argcount]
       
   152             defaults = fob.func_defaults or []
       
   153             defaults = list(map(lambda name: "=%s" % repr(name), defaults))
       
   154             defaults = [""] * (len(real_args) - len(defaults)) + defaults
       
   155             items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
       
   156             if fob.func_code.co_flags & 0x4:
       
   157                 items.append("...")
       
   158             if fob.func_code.co_flags & 0x8:
       
   159                 items.append("***")
       
   160             arg_text = ", ".join(items)
       
   161             arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", arg_text)
       
   162         # See if we can use the docstring
       
   163         doc = getattr(ob, "__doc__", "")
       
   164         if doc:
       
   165             doc = doc.lstrip()
       
   166             pos = doc.find("\n")
       
   167             if pos < 0 or pos > 70:
       
   168                 pos = 70
       
   169             if arg_text:
       
   170                 arg_text += "\n"
       
   171             arg_text += doc[:pos]
       
   172     return arg_text
       
   173 
       
   174 #################################################
       
   175 #
       
   176 # Test code
       
   177 #
       
   178 if __name__=='__main__':
       
   179 
       
   180     def t1(): "()"
       
   181     def t2(a, b=None): "(a, b=None)"
       
   182     def t3(a, *args): "(a, ...)"
       
   183     def t4(*args): "(...)"
       
   184     def t5(a, *args): "(a, ...)"
       
   185     def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
       
   186     def t7((a, b), c, (d, e)): "(<tuple>, c, <tuple>)"
       
   187 
       
   188     class TC(object):
       
   189         "(ai=None, ...)"
       
   190         def __init__(self, ai=None, *b): "(ai=None, ...)"
       
   191         def t1(self): "()"
       
   192         def t2(self, ai, b=None): "(ai, b=None)"
       
   193         def t3(self, ai, *args): "(ai, ...)"
       
   194         def t4(self, *args): "(...)"
       
   195         def t5(self, ai, *args): "(ai, ...)"
       
   196         def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)"
       
   197         def t7(self, (ai, b), c, (d, e)): "(<tuple>, c, <tuple>)"
       
   198 
       
   199     def test(tests):
       
   200         ct = CallTips()
       
   201         failed=[]
       
   202         for t in tests:
       
   203             expected = t.__doc__ + "\n" + t.__doc__
       
   204             name = t.__name__
       
   205             # exercise fetch_tip(), not just get_arg_text()
       
   206             try:
       
   207                 qualified_name = "%s.%s" % (t.im_class.__name__, name)
       
   208             except AttributeError:
       
   209                 qualified_name = name
       
   210             arg_text = ct.fetch_tip(qualified_name)
       
   211             if arg_text != expected:
       
   212                 failed.append(t)
       
   213                 fmt = "%s - expected %s, but got %s"
       
   214                 print  fmt % (t.__name__, expected, get_arg_text(t))
       
   215         print "%d of %d tests failed" % (len(failed), len(tests))
       
   216 
       
   217     tc = TC()
       
   218     tests = (t1, t2, t3, t4, t5, t6, t7,
       
   219              TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7)
       
   220 
       
   221     test(tests)