blob: a3dda2678bd4da48220757196c15694d5066f47a [file] [log] [blame]
wohlganger58fc71c2017-09-10 16:19:47 -05001"""Pop up a reminder of how to call a function.
David Scherer7aced172000-08-15 01:13:23 +00002
Kurt B. Kaisere54710b2002-12-12 19:15:39 +00003Call 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.
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00006"""
Terry Jan Reedy0fe45132019-03-24 17:12:28 -04007import __main__
Terry Jan Reedya0f1e222014-01-26 19:55:34 -05008import inspect
Thomas Wouterscf297e42007-02-23 15:07:44 +00009import re
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010import sys
Terry Jan Reedya0f1e222014-01-26 19:55:34 -050011import textwrap
David Scherer7aced172000-08-15 01:13:23 +000012import types
13
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040014from idlelib import calltip_w
15from idlelib.hyperparser import HyperParser
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000016
David Scherer7aced172000-08-15 01:13:23 +000017
Terry Jan Reedy06e20292018-06-19 23:00:35 -040018class Calltip:
David Scherer7aced172000-08-15 01:13:23 +000019
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000020 def __init__(self, editwin=None):
Raymond Hettingerc5e378d2004-05-04 08:34:56 +000021 if editwin is None: # subprocess and test
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000022 self.editwin = None
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000023 else:
24 self.editwin = editwin
25 self.text = editwin.text
26 self.active_calltip = None
27 self._calltip_window = self._make_tk_calltip_window
David Scherer7aced172000-08-15 01:13:23 +000028
29 def close(self):
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000030 self._calltip_window = None
David Scherer7aced172000-08-15 01:13:23 +000031
David Scherer7aced172000-08-15 01:13:23 +000032 def _make_tk_calltip_window(self):
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000033 # See __init__ for usage
Terry Jan Reedy9af18362018-06-20 02:18:49 -040034 return calltip_w.CalltipWindow(self.text)
David Scherer7aced172000-08-15 01:13:23 +000035
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000036 def _remove_calltip_window(self, event=None):
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000037 if self.active_calltip:
38 self.active_calltip.hidetip()
39 self.active_calltip = None
Kurt B. Kaiserae676472001-07-12 23:10:35 +000040
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000041 def force_open_calltip_event(self, event):
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000042 "The user selected the menu entry or hotkey, open the tip."
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000043 self.open_calltip(True)
Serhiy Storchaka213ce122017-06-27 07:02:32 +030044 return "break"
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000045
46 def try_open_calltip_event(self, event):
Terry Jan Reedy9af18362018-06-20 02:18:49 -040047 """Happens when it would be nice to open a calltip, but not really
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000048 necessary, for example after an opening bracket, so function calls
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000049 won't be made.
50 """
51 self.open_calltip(False)
52
53 def refresh_calltip_event(self, event):
Tal Einat87e59ac2018-08-05 09:21:08 +030054 if self.active_calltip and self.active_calltip.tipwindow:
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000055 self.open_calltip(False)
56
57 def open_calltip(self, evalfuncs):
David Scherer7aced172000-08-15 01:13:23 +000058 self._remove_calltip_window()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000059
60 hp = HyperParser(self.editwin, "insert")
61 sur_paren = hp.get_surrounding_brackets('(')
62 if not sur_paren:
63 return
64 hp.set_index(sur_paren[0])
Terry Jan Reedye606e232012-06-03 00:27:54 -040065 expression = hp.get_expression()
66 if not expression:
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000067 return
Terry Jan Reedye606e232012-06-03 00:27:54 -040068 if not evalfuncs and (expression.find('(') != -1):
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000069 return
Terry Jan Reedye606e232012-06-03 00:27:54 -040070 argspec = self.fetch_tip(expression)
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000071 if not argspec:
72 return
73 self.active_calltip = self._calltip_window()
74 self.active_calltip.showtip(argspec, sur_paren[0], sur_paren[1])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000075
Terry Jan Reedye606e232012-06-03 00:27:54 -040076 def fetch_tip(self, expression):
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000077 """Return the argument list and docstring of a function or class.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000078
Kurt B. Kaisere54710b2002-12-12 19:15:39 +000079 If there is a Python subprocess, get the calltip there. Otherwise,
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +000080 either this fetch_tip() is running in the subprocess or it was
81 called in an IDLE running without the subprocess.
Kurt B. Kaisere54710b2002-12-12 19:15:39 +000082
83 The subprocess environment is that of the most recently run script. If
84 two unrelated modules are being edited some calltips in the current
85 module may be inoperative if the module was not the last to run.
86
Thomas Wouterscf297e42007-02-23 15:07:44 +000087 To find methods, fetch_tip must be fed a fully qualified name.
88
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000089 """
Kurt B. Kaisere54710b2002-12-12 19:15:39 +000090 try:
91 rpcclt = self.editwin.flist.pyshell.interp.rpcclt
Terry Jan Reedye606e232012-06-03 00:27:54 -040092 except AttributeError:
Kurt B. Kaisere54710b2002-12-12 19:15:39 +000093 rpcclt = None
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000094 if rpcclt:
95 return rpcclt.remotecall("exec", "get_the_calltip",
Terry Jan Reedye606e232012-06-03 00:27:54 -040096 (expression,), {})
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000097 else:
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -040098 return get_argspec(get_entity(expression))
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000099
wohlganger58fc71c2017-09-10 16:19:47 -0500100
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400101def get_entity(expression):
102 """Return the object corresponding to expression evaluated
Terry Jan Reedy0fe45132019-03-24 17:12:28 -0400103 in a namespace spanning sys.modules and __main.dict__.
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400104 """
105 if expression:
Terry Jan Reedy0fe45132019-03-24 17:12:28 -0400106 namespace = {**sys.modules, **__main__.__dict__}
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400107 try:
Terry Jan Reedy2b751552019-03-23 03:50:15 -0400108 return eval(expression, namespace) # Only protect user code.
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400109 except BaseException:
110 # An uncaught exception closes idle, and eval can raise any
111 # exception, especially if user classes are involved.
112 return None
David Scherer7aced172000-08-15 01:13:23 +0000113
Terry Jan Reedyd5710f82014-01-21 20:45:17 -0500114# The following are used in get_argspec and some in tests
Terry Jan Reedya0f1e222014-01-26 19:55:34 -0500115_MAX_COLS = 85
Terry Jan Reedyd5710f82014-01-21 20:45:17 -0500116_MAX_LINES = 5 # enough for bytes
Terry Jan Reedya0f1e222014-01-26 19:55:34 -0500117_INDENT = ' '*4 # for wrapped signatures
R David Murray44b548d2016-09-08 13:59:53 -0400118_first_param = re.compile(r'(?<=\()\w*\,?\s*')
Terry Jan Reedy715476d2014-01-21 15:36:51 -0500119_default_callable_argspec = "See source or doc"
Louie Lu3b0f6202017-08-10 08:58:13 +0800120_invalid_method = "invalid method signature"
Miss Islington (bot)39346ff2019-06-04 19:11:42 -0700121_argument_positional = " # '/' marks preceding args as positional-only."
David Scherer7aced172000-08-15 01:13:23 +0000122
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +0000123def get_argspec(ob):
Terry Jan Reedy715476d2014-01-21 15:36:51 -0500124 '''Return a string describing the signature of a callable object, or ''.
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400125
126 For Python-coded functions and methods, the first line is introspected.
127 Delete 'self' parameter for classes (.__init__) and bound methods.
Terry Jan Reedyd5710f82014-01-21 20:45:17 -0500128 The next lines are the first lines of the doc string up to the first
129 empty line or _MAX_LINES. For builtins, this typically includes
130 the arguments in addition to the return value.
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400131 '''
Louie Lu3b0f6202017-08-10 08:58:13 +0800132 argspec = default = ""
Terry Jan Reedy715476d2014-01-21 15:36:51 -0500133 try:
134 ob_call = ob.__call__
135 except BaseException:
Louie Lu3b0f6202017-08-10 08:58:13 +0800136 return default
137
138 fob = ob_call if isinstance(ob_call, types.MethodType) else ob
139
140 try:
141 argspec = str(inspect.signature(fob))
142 except ValueError as err:
143 msg = str(err)
144 if msg.startswith(_invalid_method):
145 return _invalid_method
146
Miss Islington (bot)39346ff2019-06-04 19:11:42 -0700147 if '/' in argspec and len(argspec) < _MAX_COLS - len(_argument_positional):
148 # Add explanation TODO remove after 3.7, before 3.9.
Louie Lu3b0f6202017-08-10 08:58:13 +0800149 argspec += _argument_positional
150 if isinstance(fob, type) and argspec == '()':
Miss Islington (bot)39346ff2019-06-04 19:11:42 -0700151 # If fob has no argument, use default callable argspec.
Louie Lu3b0f6202017-08-10 08:58:13 +0800152 argspec = _default_callable_argspec
Terry Jan Reedy2a2ce4f2012-06-07 19:41:04 -0400153
Terry Jan Reedya0f1e222014-01-26 19:55:34 -0500154 lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT)
Louie Lu3b0f6202017-08-10 08:58:13 +0800155 if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
Terry Jan Reedya0f1e222014-01-26 19:55:34 -0500156
Terry Jan Reedy715476d2014-01-21 15:36:51 -0500157 if isinstance(ob_call, types.MethodType):
158 doc = ob_call.__doc__
159 else:
160 doc = getattr(ob, "__doc__", "")
161 if doc:
Terry Jan Reedya0f1e222014-01-26 19:55:34 -0500162 for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]:
Terry Jan Reedyd5710f82014-01-21 20:45:17 -0500163 line = line.strip()
164 if not line:
165 break
166 if len(line) > _MAX_COLS:
167 line = line[: _MAX_COLS - 3] + '...'
168 lines.append(line)
Emmanuel Ariasab54b9a2019-01-03 04:47:58 -0300169 argspec = '\n'.join(lines)
Terry Jan Reedy715476d2014-01-21 15:36:51 -0500170 if not argspec:
171 argspec = _default_callable_argspec
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +0000172 return argspec
David Scherer7aced172000-08-15 01:13:23 +0000173
Louie Lu3b0f6202017-08-10 08:58:13 +0800174
Kurt B. Kaiser152b3c22007-08-30 06:35:15 +0000175if __name__ == '__main__':
Terry Jan Reedydb4e5c52013-05-27 21:32:03 -0400176 from unittest import main
Terry Jan Reedy06e20292018-06-19 23:00:35 -0400177 main('idlelib.idle_test.test_calltip', verbosity=2)