bpo-19903: IDLE: Calltips changed to use inspect.signature (#2822)

Idlelib.calltips.get_argspec now uses inspect.signature instead of inspect.getfullargspec, like help() does.  This improves the signature in the call tip in a few different cases, including builtins converted to provide a signature.  A message is added if the object is not callable, has an invalid signature, or if it has positional-only parameters.
Patch by Louie Lu.
This commit is contained in:
Louie Lu 2017-08-10 08:58:13 +08:00 committed by Terry Jan Reedy
parent 3ca9f50f96
commit 3b0f620c1a
3 changed files with 62 additions and 26 deletions

View file

@ -123,6 +123,8 @@ _MAX_LINES = 5 # enough for bytes
_INDENT = ' '*4 # for wrapped signatures
_first_param = re.compile(r'(?<=\()\w*\,?\s*')
_default_callable_argspec = "See source or doc"
_invalid_method = "invalid method signature"
_argument_positional = "\n['/' marks preceding arguments as positional-only]\n"
def get_argspec(ob):
@ -134,25 +136,30 @@ def get_argspec(ob):
empty line or _MAX_LINES. For builtins, this typically includes
the arguments in addition to the return value.
'''
argspec = ""
argspec = default = ""
try:
ob_call = ob.__call__
except BaseException:
return argspec
if isinstance(ob, type):
fob = ob.__init__
elif isinstance(ob_call, types.MethodType):
fob = ob_call
else:
fob = ob
if isinstance(fob, (types.FunctionType, types.MethodType)):
argspec = inspect.formatargspec(*inspect.getfullargspec(fob))
if (isinstance(ob, (type, types.MethodType)) or
isinstance(ob_call, types.MethodType)):
argspec = _first_param.sub("", argspec)
return default
fob = ob_call if isinstance(ob_call, types.MethodType) else ob
try:
argspec = str(inspect.signature(fob))
except ValueError as err:
msg = str(err)
if msg.startswith(_invalid_method):
return _invalid_method
if '/' in argspec:
"""Using AC's positional argument should add the explain"""
argspec += _argument_positional
if isinstance(fob, type) and argspec == '()':
"""fob with no argument, use default callable argspec"""
argspec = _default_callable_argspec
lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT)
if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
if isinstance(ob_call, types.MethodType):
doc = ob_call.__doc__
@ -171,6 +178,7 @@ def get_argspec(ob):
argspec = _default_callable_argspec
return argspec
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_calltips', verbosity=2)