Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(119440)

Delta Between Two Patch Sets: Lib/inspect.py

Issue 20334: make inspect Signature hashable
Left Patch Set: Created 5 years, 10 months ago
Right Patch Set: Created 5 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Lib/test/test_inspect.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 """Get useful information from live Python objects. 1 """Get useful information from live Python objects.
2 2
3 This module encapsulates the interface provided by the internal special 3 This module encapsulates the interface provided by the internal special
4 attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion. 4 attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion.
5 It also provides some help for examining source code and class layout. 5 It also provides some help for examining source code and class layout.
6 6
7 Here are some of the useful functions provided by this module: 7 Here are some of the useful functions provided by this module:
8 8
9 ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(), 9 ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
10 isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), 10 isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
11 isroutine() - check object types 11 isroutine() - check object types
12 getmembers() - get members of an object that satisfy a given condition 12 getmembers() - get members of an object that satisfy a given condition
13 13
14 getfile(), getsourcefile(), getsource() - find an object's source code 14 getfile(), getsourcefile(), getsource() - find an object's source code
15 getdoc(), getcomments() - get documentation on an object 15 getdoc(), getcomments() - get documentation on an object
16 getmodule() - determine the module that an object came from 16 getmodule() - determine the module that an object came from
17 getclasstree() - arrange classes so as to represent their hierarchy 17 getclasstree() - arrange classes so as to represent their hierarchy
18 18
19 getargspec(), getargvalues(), getcallargs() - get info about function argume nts 19 getargspec(), getargvalues(), getcallargs() - get info about function argume nts
20 getfullargspec() - same, with support for Python-3000 features 20 getfullargspec() - same, with support for Python 3 features
21 formatargspec(), formatargvalues() - format an argument spec 21 formatargspec(), formatargvalues() - format an argument spec
22 getouterframes(), getinnerframes() - get info about frames 22 getouterframes(), getinnerframes() - get info about frames
23 currentframe() - get the current stack frame 23 currentframe() - get the current stack frame
24 stack(), trace() - get info about frames on the stack or in a traceback 24 stack(), trace() - get info about frames on the stack or in a traceback
25 25
26 signature() - get a Signature object for the callable 26 signature() - get a Signature object for the callable
27 """ 27 """
28 28
29 # This module is in the public domain. No warranties. 29 # This module is in the public domain. No warranties.
30 30
31 __author__ = ('Ka-Ping Yee <ping@lfw.org>', 31 __author__ = ('Ka-Ping Yee <ping@lfw.org>',
32 'Yury Selivanov <yselivanov@sprymix.com>') 32 'Yury Selivanov <yselivanov@sprymix.com>')
33 33
34 import ast 34 import ast
35 import enum
35 import importlib.machinery 36 import importlib.machinery
36 import itertools 37 import itertools
37 import linecache 38 import linecache
38 import os 39 import os
39 import re 40 import re
40 import sys 41 import sys
41 import tokenize 42 import tokenize
43 import token
42 import types 44 import types
43 import warnings 45 import warnings
44 import functools 46 import functools
45 import builtins 47 import builtins
46 from operator import attrgetter 48 from operator import attrgetter
47 from collections import namedtuple, OrderedDict 49 from collections import namedtuple, OrderedDict
48 50
49 # Create constants for the compiler flags in Include/code.h 51 # Create constants for the compiler flags in Include/code.h
50 # We try to get them from dis to avoid duplication, but fall 52 # We try to get them from dis to avoid duplication, but fall
51 # back to hardcoding so the dependency is optional 53 # back to hardcoding so the dependency is optional
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 # Classify the object or its descriptor. 407 # Classify the object or its descriptor.
406 if isinstance(dict_obj, staticmethod): 408 if isinstance(dict_obj, staticmethod):
407 kind = "static method" 409 kind = "static method"
408 obj = dict_obj 410 obj = dict_obj
409 elif isinstance(dict_obj, classmethod): 411 elif isinstance(dict_obj, classmethod):
410 kind = "class method" 412 kind = "class method"
411 obj = dict_obj 413 obj = dict_obj
412 elif isinstance(dict_obj, property): 414 elif isinstance(dict_obj, property):
413 kind = "property" 415 kind = "property"
414 obj = dict_obj 416 obj = dict_obj
415 elif isfunction(obj) or ismethoddescriptor(obj): 417 elif isroutine(obj):
416 kind = "method" 418 kind = "method"
417 else: 419 else:
418 kind = "data" 420 kind = "data"
419 result.append(Attribute(name, kind, homecls, obj)) 421 result.append(Attribute(name, kind, homecls, obj))
420 processed.add(name) 422 processed.add(name)
421 return result 423 return result
422 424
423 # ----------------------------------------------------------- class helpers 425 # ----------------------------------------------------------- class helpers
424 426
425 def getmro(cls): 427 def getmro(cls):
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 lines.pop(0) 511 lines.pop(0)
510 return '\n'.join(lines) 512 return '\n'.join(lines)
511 513
512 def getfile(object): 514 def getfile(object):
513 """Work out which source or compiled file an object was defined in.""" 515 """Work out which source or compiled file an object was defined in."""
514 if ismodule(object): 516 if ismodule(object):
515 if hasattr(object, '__file__'): 517 if hasattr(object, '__file__'):
516 return object.__file__ 518 return object.__file__
517 raise TypeError('{!r} is a built-in module'.format(object)) 519 raise TypeError('{!r} is a built-in module'.format(object))
518 if isclass(object): 520 if isclass(object):
519 object = sys.modules.get(object.__module__) 521 if hasattr(object, '__module__'):
520 if hasattr(object, '__file__'): 522 object = sys.modules.get(object.__module__)
521 return object.__file__ 523 if hasattr(object, '__file__'):
524 return object.__file__
522 raise TypeError('{!r} is a built-in class'.format(object)) 525 raise TypeError('{!r} is a built-in class'.format(object))
523 if ismethod(object): 526 if ismethod(object):
524 object = object.__func__ 527 object = object.__func__
525 if isfunction(object): 528 if isfunction(object):
526 object = object.__code__ 529 object = object.__code__
527 if istraceback(object): 530 if istraceback(object):
528 object = object.tb_frame 531 object = object.tb_frame
529 if isframe(object): 532 if isframe(object):
530 object = object.f_code 533 object = object.f_code
531 if iscode(object): 534 if iscode(object):
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 if co.co_flags & CO_VARKEYWORDS: 907 if co.co_flags & CO_VARKEYWORDS:
905 varkw = co.co_varnames[nargs] 908 varkw = co.co_varnames[nargs]
906 return args, varargs, kwonlyargs, varkw 909 return args, varargs, kwonlyargs, varkw
907 910
908 911
909 ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') 912 ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
910 913
911 def getargspec(func): 914 def getargspec(func):
912 """Get the names and default values of a function's arguments. 915 """Get the names and default values of a function's arguments.
913 916
914 A tuple of four things is returned: (args, varargs, varkw, defaults). 917 A tuple of four things is returned: (args, varargs, keywords, defaults).
915 'args' is a list of the argument names. 918 'args' is a list of the argument names, including keyword-only argument name s.
916 'args' will include keyword-only argument names. 919 'varargs' and 'keywords' are the names of the * and ** arguments or None.
917 'varargs' and 'varkw' are the names of the * and ** arguments or None.
918 'defaults' is an n-tuple of the default values of the last n arguments. 920 'defaults' is an n-tuple of the default values of the last n arguments.
919 921
920 Use the getfullargspec() API for Python-3000 code, as annotations 922 Use the getfullargspec() API for Python 3 code, as annotations
921 and keyword arguments are supported. getargspec() will raise ValueError 923 and keyword arguments are supported. getargspec() will raise ValueError
922 if the func has either annotations or keyword arguments. 924 if the func has either annotations or keyword arguments.
923 """ 925 """
924 926
925 args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ 927 args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
926 getfullargspec(func) 928 getfullargspec(func)
927 if kwonlyargs or ann: 929 if kwonlyargs or ann:
928 raise ValueError("Function has keyword-only arguments or annotations" 930 raise ValueError("Function has keyword-only arguments or annotations"
929 ", use getfullargspec() API which can support them") 931 ", use getfullargspec() API which can support them")
930 return ArgSpec(args, varargs, varkw, defaults) 932 return ArgSpec(args, varargs, varkw, defaults)
931 933
932 FullArgSpec = namedtuple('FullArgSpec', 934 FullArgSpec = namedtuple('FullArgSpec',
933 'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations') 935 'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations')
934 936
935 def getfullargspec(func): 937 def getfullargspec(func):
936 """Get the names and default values of a function's arguments. 938 """Get the names and default values of a callable object's arguments.
937 939
938 A tuple of seven things is returned: 940 A tuple of seven things is returned:
939 (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations). 941 (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations).
940 'args' is a list of the argument names. 942 'args' is a list of the argument names.
941 'varargs' and 'varkw' are the names of the * and ** arguments or None. 943 'varargs' and 'varkw' are the names of the * and ** arguments or None.
942 'defaults' is an n-tuple of the default values of the last n arguments. 944 'defaults' is an n-tuple of the default values of the last n arguments.
943 'kwonlyargs' is a list of keyword-only argument names. 945 'kwonlyargs' is a list of keyword-only argument names.
944 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults. 946 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
945 'annotations' is a dictionary mapping argument names to annotations. 947 'annotations' is a dictionary mapping argument names to annotations.
946 948
947 The first four items in the tuple correspond to getargspec(). 949 The first four items in the tuple correspond to getargspec().
948 """ 950 """
949 951
950 if ismethod(func): 952 try:
951 func = func.__func__ 953 # Re: `skip_bound_arg=False`
952 if not isfunction(func): 954 #
953 raise TypeError('{!r} is not a Python function'.format(func)) 955 # There is a notable difference in behaviour between getfullargspec
954 args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) 956 # and Signature: the former always returns 'self' parameter for bound
955 return FullArgSpec(args, varargs, varkw, func.__defaults__, 957 # methods, whereas the Signature always shows the actual calling
956 kwonlyargs, func.__kwdefaults__, func.__annotations__) 958 # signature of the passed object.
959 #
960 # To simulate this behaviour, we "unbind" bound methods, to trick
961 # inspect.signature to always return their first parameter ("self",
962 # usually)
963
964 # Re: `follow_wrapper_chains=False`
965 #
966 # getfullargspec() historically ignored __wrapped__ attributes,
967 # so we ensure that remains the case in 3.3+
968
969 sig = _signature_from_callable(func,
970 follow_wrapper_chains=False,
971 skip_bound_arg=False,
972 sigcls=Signature)
973 except Exception as ex:
974 # Most of the times 'signature' will raise ValueError.
975 # But, it can also raise AttributeError, and, maybe something
976 # else. So to be fully backwards compatible, we catch all
977 # possible exceptions here, and reraise a TypeError.
978 raise TypeError('unsupported callable') from ex
979
980 args = []
981 varargs = None
982 varkw = None
983 kwonlyargs = []
984 defaults = ()
985 annotations = {}
986 defaults = ()
987 kwdefaults = {}
988
989 if sig.return_annotation is not sig.empty:
990 annotations['return'] = sig.return_annotation
991
992 for param in sig.parameters.values():
993 kind = param.kind
994 name = param.name
995
996 if kind is _POSITIONAL_ONLY:
997 args.append(name)
998 elif kind is _POSITIONAL_OR_KEYWORD:
999 args.append(name)
1000 if param.default is not param.empty:
1001 defaults += (param.default,)
1002 elif kind is _VAR_POSITIONAL:
1003 varargs = name
1004 elif kind is _KEYWORD_ONLY:
1005 kwonlyargs.append(name)
1006 if param.default is not param.empty:
1007 kwdefaults[name] = param.default
1008 elif kind is _VAR_KEYWORD:
1009 varkw = name
1010
1011 if param.annotation is not param.empty:
1012 annotations[name] = param.annotation
1013
1014 if not kwdefaults:
1015 # compatibility with 'func.__kwdefaults__'
1016 kwdefaults = None
1017
1018 if not defaults:
1019 # compatibility with 'func.__defaults__'
1020 defaults = None
1021
1022 return FullArgSpec(args, varargs, varkw, defaults,
1023 kwonlyargs, kwdefaults, annotations)
1024
957 1025
958 ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') 1026 ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
959 1027
960 def getargvalues(frame): 1028 def getargvalues(frame):
961 """Get information about arguments passed into a particular frame. 1029 """Get information about arguments passed into a particular frame.
962 1030
963 A tuple of four things is returned: (args, varargs, varkw, locals). 1031 A tuple of four things is returned: (args, varargs, varkw, locals).
964 'args' is a list of the argument names. 1032 'args' is a list of the argument names.
965 'varargs' and 'varkw' are the names of the * and ** arguments or None. 1033 'varargs' and 'varkw' are the names of the * and ** arguments or None.
966 'locals' is the locals dictionary of the given frame.""" 1034 'locals' is the locals dictionary of the given frame."""
967 args, varargs, varkw = getargs(frame.f_code) 1035 args, varargs, varkw = getargs(frame.f_code)
968 return ArgInfo(args, varargs, varkw, frame.f_locals) 1036 return ArgInfo(args, varargs, varkw, frame.f_locals)
969 1037
970 def formatannotation(annotation, base_module=None): 1038 def formatannotation(annotation, base_module=None):
971 if isinstance(annotation, type): 1039 if isinstance(annotation, type):
972 if annotation.__module__ in ('builtins', base_module): 1040 if annotation.__module__ in ('builtins', base_module):
973 return annotation.__name__ 1041 return annotation.__qualname__
974 return annotation.__module__+'.'+annotation.__name__ 1042 return annotation.__module__+'.'+annotation.__qualname__
975 return repr(annotation) 1043 return repr(annotation)
976 1044
977 def formatannotationrelativeto(object): 1045 def formatannotationrelativeto(object):
978 module = getattr(object, '__module__', None) 1046 module = getattr(object, '__module__', None)
979 def _formatannotation(annotation): 1047 def _formatannotation(annotation):
980 return formatannotation(annotation, module) 1048 return formatannotation(annotation, module)
981 return _formatannotation 1049 return _formatannotation
982 1050
983 def formatargspec(args, varargs=None, varkw=None, defaults=None, 1051 def formatargspec(args, varargs=None, varkw=None, defaults=None,
984 kwonlyargs=(), kwonlydefaults={}, annotations={}, 1052 kwonlyargs=(), kwonlydefaults={}, annotations={},
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 return '(' + ', '.join(specs) + ')' 1119 return '(' + ', '.join(specs) + ')'
1052 1120
1053 def _missing_arguments(f_name, argnames, pos, values): 1121 def _missing_arguments(f_name, argnames, pos, values):
1054 names = [repr(name) for name in argnames if name not in values] 1122 names = [repr(name) for name in argnames if name not in values]
1055 missing = len(names) 1123 missing = len(names)
1056 if missing == 1: 1124 if missing == 1:
1057 s = names[0] 1125 s = names[0]
1058 elif missing == 2: 1126 elif missing == 2:
1059 s = "{} and {}".format(*names) 1127 s = "{} and {}".format(*names)
1060 else: 1128 else:
1061 tail = ", {} and {}".format(names[-2:]) 1129 tail = ", {} and {}".format(*names[-2:])
1062 del names[-2:] 1130 del names[-2:]
1063 s = ", ".join(names) + tail 1131 s = ", ".join(names) + tail
1064 raise TypeError("%s() missing %i required %s argument%s: %s" % 1132 raise TypeError("%s() missing %i required %s argument%s: %s" %
1065 (f_name, missing, 1133 (f_name, missing,
1066 "positional" if pos else "keyword-only", 1134 "positional" if pos else "keyword-only",
1067 "" if missing == 1 else "s", s)) 1135 "" if missing == 1 else "s", s))
1068 1136
1069 def _too_many(f_name, args, kwonly, varargs, defcount, given, values): 1137 def _too_many(f_name, args, kwonly, varargs, defcount, given, values):
1070 atleast = len(args) - defcount 1138 atleast = len(args) - defcount
1071 kwonly_given = len([arg for arg in kwonly if arg in values]) 1139 kwonly_given = len([arg for arg in kwonly if arg in values])
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 req = args[:num_args - num_defaults] 1202 req = args[:num_args - num_defaults]
1135 for arg in req: 1203 for arg in req:
1136 if arg not in arg2value: 1204 if arg not in arg2value:
1137 _missing_arguments(f_name, req, True, arg2value) 1205 _missing_arguments(f_name, req, True, arg2value)
1138 for i, arg in enumerate(args[num_args - num_defaults:]): 1206 for i, arg in enumerate(args[num_args - num_defaults:]):
1139 if arg not in arg2value: 1207 if arg not in arg2value:
1140 arg2value[arg] = defaults[i] 1208 arg2value[arg] = defaults[i]
1141 missing = 0 1209 missing = 0
1142 for kwarg in kwonlyargs: 1210 for kwarg in kwonlyargs:
1143 if kwarg not in arg2value: 1211 if kwarg not in arg2value:
1144 if kwarg in kwonlydefaults: 1212 if kwonlydefaults and kwarg in kwonlydefaults:
1145 arg2value[kwarg] = kwonlydefaults[kwarg] 1213 arg2value[kwarg] = kwonlydefaults[kwarg]
1146 else: 1214 else:
1147 missing += 1 1215 missing += 1
1148 if missing: 1216 if missing:
1149 _missing_arguments(f_name, kwonlyargs, False, arg2value) 1217 _missing_arguments(f_name, kwonlyargs, False, arg2value)
1150 return arg2value 1218 return arg2value
1151 1219
1152 ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound') 1220 ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound')
1153 1221
1154 def getclosurevars(func): 1222 def getclosurevars(func):
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1237 else: 1305 else:
1238 lines = index = None 1306 lines = index = None
1239 1307
1240 return Traceback(filename, lineno, frame.f_code.co_name, lines, index) 1308 return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
1241 1309
1242 def getlineno(frame): 1310 def getlineno(frame):
1243 """Get the line number from a frame object, allowing for optimization.""" 1311 """Get the line number from a frame object, allowing for optimization."""
1244 # FrameType.f_lineno is now a descriptor that grovels co_lnotab 1312 # FrameType.f_lineno is now a descriptor that grovels co_lnotab
1245 return frame.f_lineno 1313 return frame.f_lineno
1246 1314
1315 FrameInfo = namedtuple('FrameInfo', ('frame',) + Traceback._fields)
1316
1247 def getouterframes(frame, context=1): 1317 def getouterframes(frame, context=1):
1248 """Get a list of records for a frame and all higher (calling) frames. 1318 """Get a list of records for a frame and all higher (calling) frames.
1249 1319
1250 Each record contains a frame object, filename, line number, function 1320 Each record contains a frame object, filename, line number, function
1251 name, a list of lines of context, and index within the context.""" 1321 name, a list of lines of context, and index within the context."""
1252 framelist = [] 1322 framelist = []
1253 while frame: 1323 while frame:
1254 framelist.append((frame,) + getframeinfo(frame, context)) 1324 frameinfo = (frame,) + getframeinfo(frame, context)
1325 framelist.append(FrameInfo(*frameinfo))
1255 frame = frame.f_back 1326 frame = frame.f_back
1256 return framelist 1327 return framelist
1257 1328
1258 def getinnerframes(tb, context=1): 1329 def getinnerframes(tb, context=1):
1259 """Get a list of records for a traceback's frame and all lower frames. 1330 """Get a list of records for a traceback's frame and all lower frames.
1260 1331
1261 Each record contains a frame object, filename, line number, function 1332 Each record contains a frame object, filename, line number, function
1262 name, a list of lines of context, and index within the context.""" 1333 name, a list of lines of context, and index within the context."""
1263 framelist = [] 1334 framelist = []
1264 while tb: 1335 while tb:
1265 framelist.append((tb.tb_frame,) + getframeinfo(tb, context)) 1336 frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)
1337 framelist.append(FrameInfo(*frameinfo))
1266 tb = tb.tb_next 1338 tb = tb.tb_next
1267 return framelist 1339 return framelist
1268 1340
1269 def currentframe(): 1341 def currentframe():
1270 """Return the frame of the caller or None if this is not possible.""" 1342 """Return the frame of the caller or None if this is not possible."""
1271 return sys._getframe(1) if hasattr(sys, "_getframe") else None 1343 return sys._getframe(1) if hasattr(sys, "_getframe") else None
1272 1344
1273 def stack(context=1): 1345 def stack(context=1):
1274 """Return a list of records for the stack above the caller's frame.""" 1346 """Return a list of records for the stack above the caller's frame."""
1275 return getouterframes(sys._getframe(1), context) 1347 return getouterframes(sys._getframe(1), context)
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1412 else: 1484 else:
1413 return {} 1485 return {}
1414 1486
1415 ############################################################################### 1487 ###############################################################################
1416 ### Function Signature Object (PEP 362) 1488 ### Function Signature Object (PEP 362)
1417 ############################################################################### 1489 ###############################################################################
1418 1490
1419 1491
1420 _WrapperDescriptor = type(type.__call__) 1492 _WrapperDescriptor = type(type.__call__)
1421 _MethodWrapper = type(all.__call__) 1493 _MethodWrapper = type(all.__call__)
1494 _ClassMethodWrapper = type(int.__dict__['from_bytes'])
1422 1495
1423 _NonUserDefinedCallables = (_WrapperDescriptor, 1496 _NonUserDefinedCallables = (_WrapperDescriptor,
1424 _MethodWrapper, 1497 _MethodWrapper,
1498 _ClassMethodWrapper,
1425 types.BuiltinFunctionType) 1499 types.BuiltinFunctionType)
1426 1500
1427 1501
1428 def _get_user_defined_method(cls, method_name): 1502 def _signature_get_user_defined_method(cls, method_name):
1503 """Private helper. Checks if ``cls`` has an attribute
1504 named ``method_name`` and returns it only if it is a
1505 pure python function.
1506 """
1429 try: 1507 try:
1430 meth = getattr(cls, method_name) 1508 meth = getattr(cls, method_name)
1431 except AttributeError: 1509 except AttributeError:
1432 return 1510 return
1433 else: 1511 else:
1434 if not isinstance(meth, _NonUserDefinedCallables): 1512 if not isinstance(meth, _NonUserDefinedCallables):
1435 # Once '__signature__' will be added to 'C'-level 1513 # Once '__signature__' will be added to 'C'-level
1436 # callables, this check won't be necessary 1514 # callables, this check won't be necessary
1437 return meth 1515 return meth
1438 1516
1439 1517
1440 def signature(obj): 1518 def _signature_get_partial(wrapped_sig, partial, extra_args=()):
1441 '''Get a signature object for the passed callable.''' 1519 """Private helper to calculate how 'wrapped_sig' signature will
1520 look like after applying a 'functools.partial' object (or alike)
1521 on it.
1522 """
1523
1524 old_params = wrapped_sig.parameters
1525 new_params = OrderedDict(old_params.items())
1526
1527 partial_args = partial.args or ()
1528 partial_keywords = partial.keywords or {}
1529
1530 if extra_args:
1531 partial_args = extra_args + partial_args
1532
1533 try:
1534 ba = wrapped_sig.bind_partial(*partial_args, **partial_keywords)
1535 except TypeError as ex:
1536 msg = 'partial object {!r} has incorrect arguments'.format(partial)
1537 raise ValueError(msg) from ex
1538
1539
1540 transform_to_kwonly = False
1541 for param_name, param in old_params.items():
1542 try:
1543 arg_value = ba.arguments[param_name]
1544 except KeyError:
1545 pass
1546 else:
1547 if param.kind is _POSITIONAL_ONLY:
1548 # If positional-only parameter is bound by partial,
1549 # it effectively disappears from the signature
1550 new_params.pop(param_name)
1551 continue
1552
1553 if param.kind is _POSITIONAL_OR_KEYWORD:
1554 if param_name in partial_keywords:
1555 # This means that this parameter, and all parameters
1556 # after it should be keyword-only (and var-positional
1557 # should be removed). Here's why. Consider the following
1558 # function:
1559 # foo(a, b, *args, c):
1560 # pass
1561 #
1562 # "partial(foo, a='spam')" will have the following
1563 # signature: "(*, a='spam', b, c)". Because attempting
1564 # to call that partial with "(10, 20)" arguments will
1565 # raise a TypeError, saying that "a" argument received
1566 # multiple values.
1567 transform_to_kwonly = True
1568 # Set the new default value
1569 new_params[param_name] = param.replace(default=arg_value)
1570 else:
1571 # was passed as a positional argument
1572 new_params.pop(param.name)
1573 continue
1574
1575 if param.kind is _KEYWORD_ONLY:
1576 # Set the new default value
1577 new_params[param_name] = param.replace(default=arg_value)
1578
1579 if transform_to_kwonly:
1580 assert param.kind is not _POSITIONAL_ONLY
1581
1582 if param.kind is _POSITIONAL_OR_KEYWORD:
1583 new_param = new_params[param_name].replace(kind=_KEYWORD_ONLY)
1584 new_params[param_name] = new_param
1585 new_params.move_to_end(param_name)
1586 elif param.kind in (_KEYWORD_ONLY, _VAR_KEYWORD):
1587 new_params.move_to_end(param_name)
1588 elif param.kind is _VAR_POSITIONAL:
1589 new_params.pop(param.name)
1590
1591 return wrapped_sig.replace(parameters=new_params.values())
1592
1593
1594 def _signature_bound_method(sig):
1595 """Private helper to transform signatures for unbound
1596 functions to bound methods.
1597 """
1598
1599 params = tuple(sig.parameters.values())
1600
1601 if not params or params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
1602 raise ValueError('invalid method signature')
1603
1604 kind = params[0].kind
1605 if kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY):
1606 # Drop first parameter:
1607 # '(p1, p2[, ...])' -> '(p2[, ...])'
1608 params = params[1:]
1609 else:
1610 if kind is not _VAR_POSITIONAL:
1611 # Unless we add a new parameter type we never
1612 # get here
1613 raise ValueError('invalid argument type')
1614 # It's a var-positional parameter.
1615 # Do nothing. '(*args[, ...])' -> '(*args[, ...])'
1616
1617 return sig.replace(parameters=params)
1618
1619
1620 def _signature_is_builtin(obj):
1621 """Private helper to test if `obj` is a callable that might
1622 support Argument Clinic's __text_signature__ protocol.
1623 """
1624 return (isbuiltin(obj) or
1625 ismethoddescriptor(obj) or
1626 isinstance(obj, _NonUserDefinedCallables) or
1627 # Can't test 'isinstance(type)' here, as it would
1628 # also be True for regular python classes
1629 obj in (type, object))
1630
1631
1632 def _signature_is_functionlike(obj):
1633 """Private helper to test if `obj` is a duck type of FunctionType.
1634 A good example of such objects are functions compiled with
1635 Cython, which have all attributes that a pure Python function
1636 would have, but have their code statically compiled.
1637 """
1638
1639 if not callable(obj) or isclass(obj):
1640 # All function-like objects are obviously callables,
1641 # and not classes.
1642 return False
1643
1644 name = getattr(obj, '__name__', None)
1645 code = getattr(obj, '__code__', None)
1646 defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
1647 kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
1648 annotations = getattr(obj, '__annotations__', None)
1649
1650 return (isinstance(code, types.CodeType) and
1651 isinstance(name, str) and
1652 (defaults is None or isinstance(defaults, tuple)) and
1653 (kwdefaults is None or isinstance(kwdefaults, dict)) and
1654 isinstance(annotations, dict))
1655
1656
1657 def _signature_get_bound_param(spec):
1658 """ Private helper to get first parameter name from a
1659 __text_signature__ of a builtin method, which should
1660 be in the following format: '($param1, ...)'.
1661 Assumptions are that the first argument won't have
1662 a default value or an annotation.
1663 """
1664
1665 assert spec.startswith('($')
1666
1667 pos = spec.find(',')
1668 if pos == -1:
1669 pos = spec.find(')')
1670
1671 cpos = spec.find(':')
1672 assert cpos == -1 or cpos > pos
1673
1674 cpos = spec.find('=')
1675 assert cpos == -1 or cpos > pos
1676
1677 return spec[2:pos]
1678
1679
1680 def _signature_strip_non_python_syntax(signature):
1681 """
1682 Private helper function. Takes a signature in Argument Clinic's
1683 extended signature format.
1684
1685 Returns a tuple of three things:
1686 * that signature re-rendered in standard Python syntax,
1687 * the index of the "self" parameter (generally 0), or None if
1688 the function does not have a "self" parameter, and
1689 * the index of the last "positional only" parameter,
1690 or None if the signature has no positional-only parameters.
1691 """
1692
1693 if not signature:
1694 return signature, None, None
1695
1696 self_parameter = None
1697 last_positional_only = None
1698
1699 lines = [l.encode('ascii') for l in signature.split('\n')]
1700 generator = iter(lines).__next__
1701 token_stream = tokenize.tokenize(generator)
1702
1703 delayed_comma = False
1704 skip_next_comma = False
1705 text = []
1706 add = text.append
1707
1708 current_parameter = 0
1709 OP = token.OP
1710 ERRORTOKEN = token.ERRORTOKEN
1711
1712 # token stream always starts with ENCODING token, skip it
1713 t = next(token_stream)
1714 assert t.type == tokenize.ENCODING
1715
1716 for t in token_stream:
1717 type, string = t.type, t.string
1718
1719 if type == OP:
1720 if string == ',':
1721 if skip_next_comma:
1722 skip_next_comma = False
1723 else:
1724 assert not delayed_comma
1725 delayed_comma = True
1726 current_parameter += 1
1727 continue
1728
1729 if string == '/':
1730 assert not skip_next_comma
1731 assert last_positional_only is None
1732 skip_next_comma = True
1733 last_positional_only = current_parameter - 1
1734 continue
1735
1736 if (type == ERRORTOKEN) and (string == '$'):
1737 assert self_parameter is None
1738 self_parameter = current_parameter
1739 continue
1740
1741 if delayed_comma:
1742 delayed_comma = False
1743 if not ((type == OP) and (string == ')')):
1744 add(', ')
1745 add(string)
1746 if (string == ','):
1747 add(' ')
1748 clean_signature = ''.join(text)
1749 return clean_signature, self_parameter, last_positional_only
1750
1751
1752 def _signature_fromstr(cls, obj, s, skip_bound_arg=True):
1753 """Private helper to parse content of '__text_signature__'
1754 and return a Signature based on it.
1755 """
1756
1757 Parameter = cls._parameter_cls
1758
1759 clean_signature, self_parameter, last_positional_only = \
1760 _signature_strip_non_python_syntax(s)
1761
1762 program = "def foo" + clean_signature + ": pass"
1763
1764 try:
1765 module = ast.parse(program)
1766 except SyntaxError:
1767 module = None
1768
1769 if not isinstance(module, ast.Module):
1770 raise ValueError("{!r} builtin has invalid signature".format(obj))
1771
1772 f = module.body[0]
1773
1774 parameters = []
1775 empty = Parameter.empty
1776 invalid = object()
1777
1778 module = None
1779 module_dict = {}
1780 module_name = getattr(obj, '__module__', None)
1781 if module_name:
1782 module = sys.modules.get(module_name, None)
1783 if module:
1784 module_dict = module.__dict__
1785 sys_module_dict = sys.modules
1786
1787 def parse_name(node):
1788 assert isinstance(node, ast.arg)
1789 if node.annotation != None:
1790 raise ValueError("Annotations are not currently supported")
1791 return node.arg
1792
1793 def wrap_value(s):
1794 try:
1795 value = eval(s, module_dict)
1796 except NameError:
1797 try:
1798 value = eval(s, sys_module_dict)
1799 except NameError:
1800 raise RuntimeError()
1801
1802 if isinstance(value, str):
1803 return ast.Str(value)
1804 if isinstance(value, (int, float)):
1805 return ast.Num(value)
1806 if isinstance(value, bytes):
1807 return ast.Bytes(value)
1808 if value in (True, False, None):
1809 return ast.NameConstant(value)
1810 raise RuntimeError()
1811
1812 class RewriteSymbolics(ast.NodeTransformer):
1813 def visit_Attribute(self, node):
1814 a = []
1815 n = node
1816 while isinstance(n, ast.Attribute):
1817 a.append(n.attr)
1818 n = n.value
1819 if not isinstance(n, ast.Name):
1820 raise RuntimeError()
1821 a.append(n.id)
1822 value = ".".join(reversed(a))
1823 return wrap_value(value)
1824
1825 def visit_Name(self, node):
1826 if not isinstance(node.ctx, ast.Load):
1827 raise ValueError()
1828 return wrap_value(node.id)
1829
1830 def p(name_node, default_node, default=empty):
1831 name = parse_name(name_node)
1832 if name is invalid:
1833 return None
1834 if default_node and default_node is not _empty:
1835 try:
1836 default_node = RewriteSymbolics().visit(default_node)
1837 o = ast.literal_eval(default_node)
1838 except ValueError:
1839 o = invalid
1840 if o is invalid:
1841 return None
1842 default = o if o is not invalid else default
1843 parameters.append(Parameter(name, kind, default=default, annotation=empt y))
1844
1845 # non-keyword-only parameters
1846 args = reversed(f.args.args)
1847 defaults = reversed(f.args.defaults)
1848 iter = itertools.zip_longest(args, defaults, fillvalue=None)
1849 if last_positional_only is not None:
1850 kind = Parameter.POSITIONAL_ONLY
1851 else:
1852 kind = Parameter.POSITIONAL_OR_KEYWORD
1853 for i, (name, default) in enumerate(reversed(list(iter))):
1854 p(name, default)
1855 if i == last_positional_only:
1856 kind = Parameter.POSITIONAL_OR_KEYWORD
1857
1858 # *args
1859 if f.args.vararg:
1860 kind = Parameter.VAR_POSITIONAL
1861 p(f.args.vararg, empty)
1862
1863 # keyword-only arguments
1864 kind = Parameter.KEYWORD_ONLY
1865 for name, default in zip(f.args.kwonlyargs, f.args.kw_defaults):
1866 p(name, default)
1867
1868 # **kwargs
1869 if f.args.kwarg:
1870 kind = Parameter.VAR_KEYWORD
1871 p(f.args.kwarg, empty)
1872
1873 if self_parameter is not None:
1874 # Possibly strip the bound argument:
1875 # - We *always* strip first bound argument if
1876 # it is a module.
1877 # - We don't strip first bound argument if
1878 # skip_bound_arg is False.
1879 assert parameters
1880 _self = getattr(obj, '__self__', None)
1881 self_isbound = _self is not None
1882 self_ismodule = ismodule(_self)
1883 if self_isbound and (self_ismodule or skip_bound_arg):
1884 parameters.pop(0)
1885 else:
1886 # for builtins, self parameter is always positional-only!
1887 p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY)
1888 parameters[0] = p
1889
1890 return cls(parameters, return_annotation=cls.empty)
1891
1892
1893 def _signature_from_builtin(cls, func, skip_bound_arg=True):
1894 """Private helper function to get signature for
1895 builtin callables.
1896 """
1897
1898 if not _signature_is_builtin(func):
1899 raise TypeError("{!r} is not a Python builtin "
1900 "function".format(func))
1901
1902 s = getattr(func, "__text_signature__", None)
1903 if not s:
1904 raise ValueError("no signature found for builtin {!r}".format(func))
1905
1906 return _signature_fromstr(cls, func, s, skip_bound_arg)
1907
1908
1909 def _signature_from_callable(obj, *,
1910 follow_wrapper_chains=True,
1911 skip_bound_arg=True,
1912 sigcls):
1913
1914 """Private helper function to get signature for arbitrary
1915 callable objects.
1916 """
1442 1917
1443 if not callable(obj): 1918 if not callable(obj):
1444 raise TypeError('{!r} is not a callable object'.format(obj)) 1919 raise TypeError('{!r} is not a callable object'.format(obj))
1445 1920
1446 if isinstance(obj, types.MethodType): 1921 if isinstance(obj, types.MethodType):
1447 # In this case we skip the first parameter of the underlying 1922 # In this case we skip the first parameter of the underlying
1448 # function (usually `self` or `cls`). 1923 # function (usually `self` or `cls`).
1449 sig = signature(obj.__func__) 1924 sig = _signature_from_callable(
1450 return sig.replace(parameters=tuple(sig.parameters.values())[1:]) 1925 obj.__func__,
1926 follow_wrapper_chains=follow_wrapper_chains,
1927 skip_bound_arg=skip_bound_arg,
1928 sigcls=sigcls)
1929
1930 if skip_bound_arg:
1931 return _signature_bound_method(sig)
1932 else:
1933 return sig
1451 1934
1452 # Was this function wrapped by a decorator? 1935 # Was this function wrapped by a decorator?
1453 obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__"))) 1936 if follow_wrapper_chains:
1937 obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
1454 1938
1455 try: 1939 try:
1456 sig = obj.__signature__ 1940 sig = obj.__signature__
1457 except AttributeError: 1941 except AttributeError:
1458 pass 1942 pass
1459 else: 1943 else:
1460 if sig is not None: 1944 if sig is not None:
1945 if not isinstance(sig, Signature):
1946 raise TypeError(
1947 'unexpected object {!r} in __signature__ '
1948 'attribute'.format(sig))
1461 return sig 1949 return sig
1462 1950
1463 1951 try:
1464 if isinstance(obj, types.FunctionType): 1952 partialmethod = obj._partialmethod
1465 return Signature.from_function(obj) 1953 except AttributeError:
1466 1954 pass
1467 if isinstance(obj, types.BuiltinFunctionType): 1955 else:
1468 return Signature.from_builtin(obj) 1956 if isinstance(partialmethod, functools.partialmethod):
1957 # Unbound partialmethod (see functools.partialmethod)
1958 # This means, that we need to calculate the signature
1959 # as if it's a regular partial object, but taking into
1960 # account that the first positional argument
1961 # (usually `self`, or `cls`) will not be passed
1962 # automatically (as for boundmethods)
1963
1964 wrapped_sig = _signature_from_callable(
1965 partialmethod.func,
1966 follow_wrapper_chains=follow_wrapper_chains,
1967 skip_bound_arg=skip_bound_arg,
1968 sigcls=sigcls)
1969
1970 sig = _signature_get_partial(wrapped_sig, partialmethod, (None,))
1971
1972 first_wrapped_param = tuple(wrapped_sig.parameters.values())[0]
1973 new_params = (first_wrapped_param,) + tuple(sig.parameters.values())
1974
1975 return sig.replace(parameters=new_params)
1976
1977 if isfunction(obj) or _signature_is_functionlike(obj):
1978 # If it's a pure Python function, or an object that is duck type
1979 # of a Python function (Cython functions, for instance), then:
1980 return sigcls.from_function(obj)
1981
1982 if _signature_is_builtin(obj):
1983 return _signature_from_builtin(sigcls, obj,
1984 skip_bound_arg=skip_bound_arg)
1469 1985
1470 if isinstance(obj, functools.partial): 1986 if isinstance(obj, functools.partial):
1471 sig = signature(obj.func) 1987 wrapped_sig = _signature_from_callable(
1472 1988 obj.func,
1473 new_params = OrderedDict(sig.parameters.items()) 1989 follow_wrapper_chains=follow_wrapper_chains,
1474 1990 skip_bound_arg=skip_bound_arg,
1475 partial_args = obj.args or () 1991 sigcls=sigcls)
1476 partial_keywords = obj.keywords or {} 1992 return _signature_get_partial(wrapped_sig, obj)
1477 try:
1478 ba = sig.bind_partial(*partial_args, **partial_keywords)
1479 except TypeError as ex:
1480 msg = 'partial object {!r} has incorrect arguments'.format(obj)
1481 raise ValueError(msg) from ex
1482
1483 for arg_name, arg_value in ba.arguments.items():
1484 param = new_params[arg_name]
1485 if arg_name in partial_keywords:
1486 # We set a new default value, because the following code
1487 # is correct:
1488 #
1489 # >>> def foo(a): print(a)
1490 # >>> print(partial(partial(foo, a=10), a=20)())
1491 # 20
1492 # >>> print(partial(partial(foo, a=10), a=20)(a=30))
1493 # 30
1494 #
1495 # So, with 'partial' objects, passing a keyword argument is
1496 # like setting a new default value for the corresponding
1497 # parameter
1498 #
1499 # We also mark this parameter with '_partial_kwarg'
1500 # flag. Later, in '_bind', the 'default' value of this
1501 # parameter will be added to 'kwargs', to simulate
1502 # the 'functools.partial' real call.
1503 new_params[arg_name] = param.replace(default=arg_value,
1504 _partial_kwarg=True)
1505
1506 elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and
1507 not param._partial_kwarg):
1508 new_params.pop(arg_name)
1509
1510 return sig.replace(parameters=new_params.values())
1511 1993
1512 sig = None 1994 sig = None
1513 if isinstance(obj, type): 1995 if isinstance(obj, type):
1514 # obj is a class or a metaclass 1996 # obj is a class or a metaclass
1515 1997
1516 # First, let's see if it has an overloaded __call__ defined 1998 # First, let's see if it has an overloaded __call__ defined
1517 # in its metaclass 1999 # in its metaclass
1518 call = _get_user_defined_method(type(obj), '__call__') 2000 call = _signature_get_user_defined_method(type(obj), '__call__')
1519 if call is not None: 2001 if call is not None:
1520 sig = signature(call) 2002 sig = _signature_from_callable(
2003 call,
2004 follow_wrapper_chains=follow_wrapper_chains,
2005 skip_bound_arg=skip_bound_arg,
2006 sigcls=sigcls)
1521 else: 2007 else:
1522 # Now we check if the 'obj' class has a '__new__' method 2008 # Now we check if the 'obj' class has a '__new__' method
1523 new = _get_user_defined_method(obj, '__new__') 2009 new = _signature_get_user_defined_method(obj, '__new__')
1524 if new is not None: 2010 if new is not None:
1525 sig = signature(new) 2011 sig = _signature_from_callable(
2012 new,
2013 follow_wrapper_chains=follow_wrapper_chains,
2014 skip_bound_arg=skip_bound_arg,
2015 sigcls=sigcls)
1526 else: 2016 else:
1527 # Finally, we should have at least __init__ implemented 2017 # Finally, we should have at least __init__ implemented
1528 init = _get_user_defined_method(obj, '__init__') 2018 init = _signature_get_user_defined_method(obj, '__init__')
1529 if init is not None: 2019 if init is not None:
1530 sig = signature(init) 2020 sig = _signature_from_callable(
2021 init,
2022 follow_wrapper_chains=follow_wrapper_chains,
2023 skip_bound_arg=skip_bound_arg,
2024 sigcls=sigcls)
2025
2026 if sig is None:
2027 # At this point we know, that `obj` is a class, with no user-
2028 # defined '__init__', '__new__', or class-level '__call__'
2029
2030 for base in obj.__mro__[:-1]:
2031 # Since '__text_signature__' is implemented as a
2032 # descriptor that extracts text signature from the
2033 # class docstring, if 'obj' is derived from a builtin
2034 # class, its own '__text_signature__' may be 'None'.
2035 # Therefore, we go through the MRO (except the last
2036 # class in there, which is 'object') to find the first
2037 # class with non-empty text signature.
2038 try:
2039 text_sig = base.__text_signature__
2040 except AttributeError:
2041 pass
2042 else:
2043 if text_sig:
2044 # If 'obj' class has a __text_signature__ attribute:
2045 # return a signature based on it
2046 return _signature_fromstr(sigcls, obj, text_sig)
2047
2048 # No '__text_signature__' was found for the 'obj' class.
2049 # Last option is to check if its '__init__' is
2050 # object.__init__ or type.__init__.
2051 if type not in obj.__mro__:
2052 # We have a class (not metaclass), but no user-defined
2053 # __init__ or __new__ for it
2054 if obj.__init__ is object.__init__:
2055 # Return a signature of 'object' builtin.
2056 return signature(object)
2057
1531 elif not isinstance(obj, _NonUserDefinedCallables): 2058 elif not isinstance(obj, _NonUserDefinedCallables):
1532 # An object with __call__ 2059 # An object with __call__
1533 # We also check that the 'obj' is not an instance of 2060 # We also check that the 'obj' is not an instance of
1534 # _WrapperDescriptor or _MethodWrapper to avoid 2061 # _WrapperDescriptor or _MethodWrapper to avoid
1535 # infinite recursion (and even potential segfault) 2062 # infinite recursion (and even potential segfault)
1536 call = _get_user_defined_method(type(obj), '__call__') 2063 call = _signature_get_user_defined_method(type(obj), '__call__')
1537 if call is not None: 2064 if call is not None:
1538 sig = signature(call) 2065 try:
2066 sig = _signature_from_callable(
2067 call,
2068 follow_wrapper_chains=follow_wrapper_chains,
2069 skip_bound_arg=skip_bound_arg,
2070 sigcls=sigcls)
2071 except ValueError as ex:
2072 msg = 'no signature found for {!r}'.format(obj)
2073 raise ValueError(msg) from ex
1539 2074
1540 if sig is not None: 2075 if sig is not None:
1541 # For classes and objects we skip the first parameter of their 2076 # For classes and objects we skip the first parameter of their
1542 # __call__, __new__, or __init__ methods 2077 # __call__, __new__, or __init__ methods
1543 return sig.replace(parameters=tuple(sig.parameters.values())[1:]) 2078 if skip_bound_arg:
2079 return _signature_bound_method(sig)
2080 else:
2081 return sig
1544 2082
1545 if isinstance(obj, types.BuiltinFunctionType): 2083 if isinstance(obj, types.BuiltinFunctionType):
1546 # Raise a nicer error message for builtins 2084 # Raise a nicer error message for builtins
1547 msg = 'no signature found for builtin function {!r}'.format(obj) 2085 msg = 'no signature found for builtin function {!r}'.format(obj)
1548 raise ValueError(msg) 2086 raise ValueError(msg)
1549 2087
1550 raise ValueError('callable {!r} is not supported by signature'.format(obj)) 2088 raise ValueError('callable {!r} is not supported by signature'.format(obj))
1551 2089
1552 2090
1553 class _void: 2091 class _void:
1554 '''A private marker - used in Parameter & Signature''' 2092 """A private marker - used in Parameter & Signature."""
1555 2093
1556 2094
1557 class _empty: 2095 class _empty:
1558 pass 2096 """Marker object for Signature.empty and Parameter.empty."""
1559 2097
1560 2098
1561 class _ParameterKind(int): 2099 class _ParameterKind(enum.IntEnum):
1562 def __new__(self, *args, name): 2100 POSITIONAL_ONLY = 0
1563 obj = int.__new__(self, *args) 2101 POSITIONAL_OR_KEYWORD = 1
1564 obj._name = name 2102 VAR_POSITIONAL = 2
1565 return obj 2103 KEYWORD_ONLY = 3
2104 VAR_KEYWORD = 4
1566 2105
1567 def __str__(self): 2106 def __str__(self):
1568 return self._name 2107 return self._name_
1569 2108
1570 def __repr__(self): 2109
1571 return '<_ParameterKind: {!r}>'.format(self._name) 2110 _POSITIONAL_ONLY = _ParameterKind.POSITIONAL_ONLY
1572 2111 _POSITIONAL_OR_KEYWORD = _ParameterKind.POSITIONAL_OR_KEYWORD
1573 2112 _VAR_POSITIONAL = _ParameterKind.VAR_POSITIONAL
1574 _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') 2113 _KEYWORD_ONLY = _ParameterKind.KEYWORD_ONLY
1575 _POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') 2114 _VAR_KEYWORD = _ParameterKind.VAR_KEYWORD
1576 _VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL')
1577 _KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY')
1578 _VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD')
1579 2115
1580 2116
1581 class Parameter: 2117 class Parameter:
1582 '''Represents a parameter in a function signature. 2118 """Represents a parameter in a function signature.
1583 2119
1584 Has the following public attributes: 2120 Has the following public attributes:
1585 2121
1586 * name : str 2122 * name : str
1587 The name of the parameter as a string. 2123 The name of the parameter as a string.
1588 * default : object 2124 * default : object
1589 The default value for the parameter if specified. If the 2125 The default value for the parameter if specified. If the
1590 parameter has no default value, this attribute is not set. 2126 parameter has no default value, this attribute is set to
2127 `Parameter.empty`.
1591 * annotation 2128 * annotation
1592 The annotation for the parameter if specified. If the 2129 The annotation for the parameter if specified. If the
1593 parameter has no annotation, this attribute is not set. 2130 parameter has no annotation, this attribute is set to
2131 `Parameter.empty`.
1594 * kind : str 2132 * kind : str
1595 Describes how argument values are bound to the parameter. 2133 Describes how argument values are bound to the parameter.
1596 Possible values: `Parameter.POSITIONAL_ONLY`, 2134 Possible values: `Parameter.POSITIONAL_ONLY`,
1597 `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, 2135 `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
1598 `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. 2136 `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
1599 ''' 2137 """
1600 2138
1601 __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') 2139 __slots__ = ('_name', '_kind', '_default', '_annotation')
1602 2140
1603 POSITIONAL_ONLY = _POSITIONAL_ONLY 2141 POSITIONAL_ONLY = _POSITIONAL_ONLY
1604 POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD 2142 POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
1605 VAR_POSITIONAL = _VAR_POSITIONAL 2143 VAR_POSITIONAL = _VAR_POSITIONAL
1606 KEYWORD_ONLY = _KEYWORD_ONLY 2144 KEYWORD_ONLY = _KEYWORD_ONLY
1607 VAR_KEYWORD = _VAR_KEYWORD 2145 VAR_KEYWORD = _VAR_KEYWORD
1608 2146
1609 empty = _empty 2147 empty = _empty
1610 2148
1611 def __init__(self, name, kind, *, default=_empty, annotation=_empty, 2149 def __init__(self, name, kind, *, default=_empty, annotation=_empty):
1612 _partial_kwarg=False):
1613 2150
1614 if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, 2151 if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
1615 _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): 2152 _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
1616 raise ValueError("invalid value for 'Parameter.kind' attribute") 2153 raise ValueError("invalid value for 'Parameter.kind' attribute")
1617 self._kind = kind 2154 self._kind = kind
1618 2155
1619 if default is not _empty: 2156 if default is not _empty:
1620 if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): 2157 if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
1621 msg = '{} parameters cannot have default values'.format(kind) 2158 msg = '{} parameters cannot have default values'.format(kind)
1622 raise ValueError(msg) 2159 raise ValueError(msg)
1623 self._default = default 2160 self._default = default
1624 self._annotation = annotation 2161 self._annotation = annotation
1625 2162
1626 if name is None: 2163 if name is _empty:
1627 if kind != _POSITIONAL_ONLY: 2164 raise ValueError('name is a required attribute for Parameter')
1628 raise ValueError("None is not a valid name for a " 2165
1629 "non-positional-only parameter") 2166 if not isinstance(name, str):
1630 self._name = name 2167 raise TypeError("name must be a str, not a {!r}".format(name))
1631 else: 2168
1632 name = str(name) 2169 if not name.isidentifier():
1633 if kind != _POSITIONAL_ONLY and not name.isidentifier(): 2170 raise ValueError('{!r} is not a valid parameter name'.format(name))
1634 msg = '{!r} is not a valid parameter name'.format(name) 2171
1635 raise ValueError(msg) 2172 self._name = name
1636 self._name = name 2173
1637 2174 def __reduce__(self):
1638 self._partial_kwarg = _partial_kwarg 2175 return (type(self),
2176 (self._name, self._kind),
2177 {'_default': self._default,
2178 '_annotation': self._annotation})
2179
2180 def __setstate__(self, state):
2181 self._default = state['_default']
2182 self._annotation = state['_annotation']
1639 2183
1640 @property 2184 @property
1641 def name(self): 2185 def name(self):
1642 return self._name 2186 return self._name
1643 2187
1644 @property 2188 @property
1645 def default(self): 2189 def default(self):
1646 return self._default 2190 return self._default
1647 2191
1648 @property 2192 @property
1649 def annotation(self): 2193 def annotation(self):
1650 return self._annotation 2194 return self._annotation
1651 2195
1652 @property 2196 @property
1653 def kind(self): 2197 def kind(self):
1654 return self._kind 2198 return self._kind
1655 2199
1656 def replace(self, *, name=_void, kind=_void, annotation=_void, 2200 def replace(self, *, name=_void, kind=_void,
1657 default=_void, _partial_kwarg=_void): 2201 annotation=_void, default=_void):
1658 '''Creates a customized copy of the Parameter.''' 2202 """Creates a customized copy of the Parameter."""
1659 2203
1660 if name is _void: 2204 if name is _void:
1661 name = self._name 2205 name = self._name
1662 2206
1663 if kind is _void: 2207 if kind is _void:
1664 kind = self._kind 2208 kind = self._kind
1665 2209
1666 if annotation is _void: 2210 if annotation is _void:
1667 annotation = self._annotation 2211 annotation = self._annotation
1668 2212
1669 if default is _void: 2213 if default is _void:
1670 default = self._default 2214 default = self._default
1671 2215
1672 if _partial_kwarg is _void: 2216 return type(self)(name, kind, default=default, annotation=annotation)
1673 _partial_kwarg = self._partial_kwarg
1674
1675 return type(self)(name, kind, default=default, annotation=annotation,
1676 _partial_kwarg=_partial_kwarg)
1677 2217
1678 def __str__(self): 2218 def __str__(self):
1679 kind = self.kind 2219 kind = self.kind
1680
1681 formatted = self._name 2220 formatted = self._name
1682 if kind == _POSITIONAL_ONLY:
1683 if formatted is None:
1684 formatted = ''
1685 formatted = '<{}>'.format(formatted)
1686 2221
1687 # Add annotation and default value 2222 # Add annotation and default value
1688 if self._annotation is not _empty: 2223 if self._annotation is not _empty:
1689 formatted = '{}:{}'.format(formatted, 2224 formatted = '{}:{}'.format(formatted,
1690 formatannotation(self._annotation)) 2225 formatannotation(self._annotation))
1691 2226
1692 if self._default is not _empty: 2227 if self._default is not _empty:
1693 formatted = '{}={}'.format(formatted, repr(self._default)) 2228 formatted = '{}={}'.format(formatted, repr(self._default))
1694 2229
1695 if kind == _VAR_POSITIONAL: 2230 if kind == _VAR_POSITIONAL:
1696 formatted = '*' + formatted 2231 formatted = '*' + formatted
1697 elif kind == _VAR_KEYWORD: 2232 elif kind == _VAR_KEYWORD:
1698 formatted = '**' + formatted 2233 formatted = '**' + formatted
1699 2234
1700 return formatted 2235 return formatted
1701 2236
1702 def __repr__(self): 2237 def __repr__(self):
1703 return '<{} at {:#x} {!r}>'.format(self.__class__.__name__, 2238 return '<{} at {:#x} "{}">'.format(self.__class__.__name__,
1704 id(self), self.name) 2239 id(self), self)
1705 2240
1706 def __hash__(self): 2241 def __hash__(self):
1707 hash_tuple = (self.name, int(self.kind), self._partial_kwarg) 2242 return hash((self.name, self.kind, self._annotation, self._default))
1708
1709 if self._annotation is not _empty:
1710 hash_tuple += (self._annotation,)
1711 if self._default is not _empty:
1712 hash_tuple += (self._default,)
1713
1714 return hash(hash_tuple)
1715 2243
1716 def __eq__(self, other): 2244 def __eq__(self, other):
1717 return (issubclass(other.__class__, Parameter) and 2245 return (issubclass(other.__class__, Parameter) and
1718 self._name == other._name and 2246 self._name == other._name and
1719 self._kind == other._kind and 2247 self._kind == other._kind and
1720 self._default == other._default and 2248 self._default == other._default and
1721 self._annotation == other._annotation) 2249 self._annotation == other._annotation)
1722 2250
1723 def __ne__(self, other): 2251 def __ne__(self, other):
1724 return not self.__eq__(other) 2252 return not self.__eq__(other)
1725 2253
1726 2254
1727 class BoundArguments: 2255 class BoundArguments:
1728 '''Result of `Signature.bind` call. Holds the mapping of arguments 2256 """Result of `Signature.bind` call. Holds the mapping of arguments
1729 to the function's parameters. 2257 to the function's parameters.
1730 2258
1731 Has the following public attributes: 2259 Has the following public attributes:
1732 2260
1733 * arguments : OrderedDict 2261 * arguments : OrderedDict
1734 An ordered mutable mapping of parameters' names to arguments' values. 2262 An ordered mutable mapping of parameters' names to arguments' values.
1735 Does not contain arguments' default values. 2263 Does not contain arguments' default values.
1736 * signature : Signature 2264 * signature : Signature
1737 The Signature object that created this instance. 2265 The Signature object that created this instance.
1738 * args : tuple 2266 * args : tuple
1739 Tuple of positional arguments values. 2267 Tuple of positional arguments values.
1740 * kwargs : dict 2268 * kwargs : dict
1741 Dict of keyword arguments values. 2269 Dict of keyword arguments values.
1742 ''' 2270 """
1743 2271
1744 def __init__(self, signature, arguments): 2272 def __init__(self, signature, arguments):
1745 self.arguments = arguments 2273 self.arguments = arguments
1746 self._signature = signature 2274 self._signature = signature
1747 2275
1748 @property 2276 @property
1749 def signature(self): 2277 def signature(self):
1750 return self._signature 2278 return self._signature
1751 2279
1752 @property 2280 @property
1753 def args(self): 2281 def args(self):
1754 args = [] 2282 args = []
1755 for param_name, param in self._signature.parameters.items(): 2283 for param_name, param in self._signature.parameters.items():
1756 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or 2284 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
1757 param._partial_kwarg):
1758 # Keyword arguments mapped by 'functools.partial'
1759 # (Parameter._partial_kwarg is True) are mapped
1760 # in 'BoundArguments.kwargs', along with VAR_KEYWORD &
1761 # KEYWORD_ONLY
1762 break 2285 break
1763 2286
1764 try: 2287 try:
1765 arg = self.arguments[param_name] 2288 arg = self.arguments[param_name]
1766 except KeyError: 2289 except KeyError:
1767 # We're done here. Other arguments 2290 # We're done here. Other arguments
1768 # will be mapped in 'BoundArguments.kwargs' 2291 # will be mapped in 'BoundArguments.kwargs'
1769 break 2292 break
1770 else: 2293 else:
1771 if param.kind == _VAR_POSITIONAL: 2294 if param.kind == _VAR_POSITIONAL:
1772 # *args 2295 # *args
1773 args.extend(arg) 2296 args.extend(arg)
1774 else: 2297 else:
1775 # plain argument 2298 # plain argument
1776 args.append(arg) 2299 args.append(arg)
1777 2300
1778 return tuple(args) 2301 return tuple(args)
1779 2302
1780 @property 2303 @property
1781 def kwargs(self): 2304 def kwargs(self):
1782 kwargs = {} 2305 kwargs = {}
1783 kwargs_started = False 2306 kwargs_started = False
1784 for param_name, param in self._signature.parameters.items(): 2307 for param_name, param in self._signature.parameters.items():
1785 if not kwargs_started: 2308 if not kwargs_started:
1786 if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or 2309 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
1787 param._partial_kwarg):
1788 kwargs_started = True 2310 kwargs_started = True
1789 else: 2311 else:
1790 if param_name not in self.arguments: 2312 if param_name not in self.arguments:
1791 kwargs_started = True 2313 kwargs_started = True
1792 continue 2314 continue
1793 2315
1794 if not kwargs_started: 2316 if not kwargs_started:
1795 continue 2317 continue
1796 2318
1797 try: 2319 try:
(...skipping 13 matching lines...) Expand all
1811 def __eq__(self, other): 2333 def __eq__(self, other):
1812 return (issubclass(other.__class__, BoundArguments) and 2334 return (issubclass(other.__class__, BoundArguments) and
1813 self.signature == other.signature and 2335 self.signature == other.signature and
1814 self.arguments == other.arguments) 2336 self.arguments == other.arguments)
1815 2337
1816 def __ne__(self, other): 2338 def __ne__(self, other):
1817 return not self.__eq__(other) 2339 return not self.__eq__(other)
1818 2340
1819 2341
1820 class Signature: 2342 class Signature:
1821 '''A Signature object represents the overall signature of a function. 2343 """A Signature object represents the overall signature of a function.
1822 It stores a Parameter object for each parameter accepted by the 2344 It stores a Parameter object for each parameter accepted by the
1823 function, as well as information specific to the function itself. 2345 function, as well as information specific to the function itself.
1824 2346
1825 A Signature object has the following public attributes and methods: 2347 A Signature object has the following public attributes and methods:
1826 2348
1827 * parameters : OrderedDict 2349 * parameters : OrderedDict
1828 An ordered mapping of parameters' names to the corresponding 2350 An ordered mapping of parameters' names to the corresponding
1829 Parameter objects (keyword-only arguments are in the same order 2351 Parameter objects (keyword-only arguments are in the same order
1830 as listed in `code.co_varnames`). 2352 as listed in `code.co_varnames`).
1831 * return_annotation : object 2353 * return_annotation : object
1832 The annotation for the return type of the function if specified. 2354 The annotation for the return type of the function if specified.
1833 If the function has no annotation for its return type, this 2355 If the function has no annotation for its return type, this
1834 attribute is not set. 2356 attribute is set to `Signature.empty`.
1835 * bind(*args, **kwargs) -> BoundArguments 2357 * bind(*args, **kwargs) -> BoundArguments
1836 Creates a mapping from positional and keyword arguments to 2358 Creates a mapping from positional and keyword arguments to
1837 parameters. 2359 parameters.
1838 * bind_partial(*args, **kwargs) -> BoundArguments 2360 * bind_partial(*args, **kwargs) -> BoundArguments
1839 Creates a partial mapping from positional and keyword arguments 2361 Creates a partial mapping from positional and keyword arguments
1840 to parameters (simulating 'functools.partial' behavior.) 2362 to parameters (simulating 'functools.partial' behavior.)
1841 ''' 2363 """
1842 2364
1843 __slots__ = ('_return_annotation', '_parameters') 2365 __slots__ = ('_return_annotation', '_parameters')
1844 2366
1845 _parameter_cls = Parameter 2367 _parameter_cls = Parameter
1846 _bound_arguments_cls = BoundArguments 2368 _bound_arguments_cls = BoundArguments
1847 2369
1848 empty = _empty 2370 empty = _empty
1849 2371
1850 def __init__(self, parameters=None, *, return_annotation=_empty, 2372 def __init__(self, parameters=None, *, return_annotation=_empty,
1851 __validate_parameters__=True): 2373 __validate_parameters__=True):
1852 '''Constructs Signature from the given list of Parameter 2374 """Constructs Signature from the given list of Parameter
1853 objects and 'return_annotation'. All arguments are optional. 2375 objects and 'return_annotation'. All arguments are optional.
1854 ''' 2376 """
1855 2377
1856 if parameters is None: 2378 if parameters is None:
1857 params = OrderedDict() 2379 params = OrderedDict()
1858 else: 2380 else:
1859 if __validate_parameters__: 2381 if __validate_parameters__:
1860 params = OrderedDict() 2382 params = OrderedDict()
1861 top_kind = _POSITIONAL_ONLY 2383 top_kind = _POSITIONAL_ONLY
2384 kind_defaults = False
1862 2385
1863 for idx, param in enumerate(parameters): 2386 for idx, param in enumerate(parameters):
1864 kind = param.kind 2387 kind = param.kind
2388 name = param.name
2389
1865 if kind < top_kind: 2390 if kind < top_kind:
1866 msg = 'wrong parameter order: {} before {}' 2391 msg = 'wrong parameter order: {!r} before {!r}'
1867 msg = msg.format(top_kind, param.kind) 2392 msg = msg.format(top_kind, kind)
1868 raise ValueError(msg) 2393 raise ValueError(msg)
1869 else: 2394 elif kind > top_kind:
2395 kind_defaults = False
1870 top_kind = kind 2396 top_kind = kind
1871 2397
1872 name = param.name 2398 if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD):
1873 if name is None: 2399 if param.default is _empty:
1874 name = str(idx) 2400 if kind_defaults:
1875 param = param.replace(name=name) 2401 # No default for this parameter, but the
2402 # previous parameter of the same kind had
2403 # a default
2404 msg = 'non-default argument follows default ' \
2405 'argument'
2406 raise ValueError(msg)
2407 else:
2408 # There is a default for this parameter.
2409 kind_defaults = True
1876 2410
1877 if name in params: 2411 if name in params:
1878 msg = 'duplicate parameter name: {!r}'.format(name) 2412 msg = 'duplicate parameter name: {!r}'.format(name)
1879 raise ValueError(msg) 2413 raise ValueError(msg)
2414
1880 params[name] = param 2415 params[name] = param
1881 else: 2416 else:
1882 params = OrderedDict(((param.name, param) 2417 params = OrderedDict(((param.name, param)
1883 for param in parameters)) 2418 for param in parameters))
1884 2419
1885 self._parameters = types.MappingProxyType(params) 2420 self._parameters = types.MappingProxyType(params)
1886 self._return_annotation = return_annotation 2421 self._return_annotation = return_annotation
1887 2422
1888 @classmethod 2423 @classmethod
1889 def from_function(cls, func): 2424 def from_function(cls, func):
1890 '''Constructs Signature for the given python function''' 2425 """Constructs Signature for the given python function."""
1891 2426
1892 if not isinstance(func, types.FunctionType): 2427 is_duck_function = False
1893 raise TypeError('{!r} is not a Python function'.format(func)) 2428 if not isfunction(func):
2429 if _signature_is_functionlike(func):
2430 is_duck_function = True
2431 else:
2432 # If it's not a pure Python function, and not a duck type
2433 # of pure function:
2434 raise TypeError('{!r} is not a Python function'.format(func))
1894 2435
1895 Parameter = cls._parameter_cls 2436 Parameter = cls._parameter_cls
1896 2437
1897 # Parameter information. 2438 # Parameter information.
1898 func_code = func.__code__ 2439 func_code = func.__code__
1899 pos_count = func_code.co_argcount 2440 pos_count = func_code.co_argcount
1900 arg_names = func_code.co_varnames 2441 arg_names = func_code.co_varnames
1901 positional = tuple(arg_names[:pos_count]) 2442 positional = tuple(arg_names[:pos_count])
1902 keyword_only_count = func_code.co_kwonlyargcount 2443 keyword_only_count = func_code.co_kwonlyargcount
1903 keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] 2444 keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
(...skipping 16 matching lines...) Expand all
1920 kind=_POSITIONAL_OR_KEYWORD)) 2461 kind=_POSITIONAL_OR_KEYWORD))
1921 2462
1922 # ... w/ defaults. 2463 # ... w/ defaults.
1923 for offset, name in enumerate(positional[non_default_count:]): 2464 for offset, name in enumerate(positional[non_default_count:]):
1924 annotation = annotations.get(name, _empty) 2465 annotation = annotations.get(name, _empty)
1925 parameters.append(Parameter(name, annotation=annotation, 2466 parameters.append(Parameter(name, annotation=annotation,
1926 kind=_POSITIONAL_OR_KEYWORD, 2467 kind=_POSITIONAL_OR_KEYWORD,
1927 default=defaults[offset])) 2468 default=defaults[offset]))
1928 2469
1929 # *args 2470 # *args
1930 if func_code.co_flags & 0x04: 2471 if func_code.co_flags & CO_VARARGS:
1931 name = arg_names[pos_count + keyword_only_count] 2472 name = arg_names[pos_count + keyword_only_count]
1932 annotation = annotations.get(name, _empty) 2473 annotation = annotations.get(name, _empty)
1933 parameters.append(Parameter(name, annotation=annotation, 2474 parameters.append(Parameter(name, annotation=annotation,
1934 kind=_VAR_POSITIONAL)) 2475 kind=_VAR_POSITIONAL))
1935 2476
1936 # Keyword-only parameters. 2477 # Keyword-only parameters.
1937 for name in keyword_only: 2478 for name in keyword_only:
1938 default = _empty 2479 default = _empty
1939 if kwdefaults is not None: 2480 if kwdefaults is not None:
1940 default = kwdefaults.get(name, _empty) 2481 default = kwdefaults.get(name, _empty)
1941 2482
1942 annotation = annotations.get(name, _empty) 2483 annotation = annotations.get(name, _empty)
1943 parameters.append(Parameter(name, annotation=annotation, 2484 parameters.append(Parameter(name, annotation=annotation,
1944 kind=_KEYWORD_ONLY, 2485 kind=_KEYWORD_ONLY,
1945 default=default)) 2486 default=default))
1946 # **kwargs 2487 # **kwargs
1947 if func_code.co_flags & 0x08: 2488 if func_code.co_flags & CO_VARKEYWORDS:
1948 index = pos_count + keyword_only_count 2489 index = pos_count + keyword_only_count
1949 if func_code.co_flags & 0x04: 2490 if func_code.co_flags & CO_VARARGS:
1950 index += 1 2491 index += 1
1951 2492
1952 name = arg_names[index] 2493 name = arg_names[index]
1953 annotation = annotations.get(name, _empty) 2494 annotation = annotations.get(name, _empty)
1954 parameters.append(Parameter(name, annotation=annotation, 2495 parameters.append(Parameter(name, annotation=annotation,
1955 kind=_VAR_KEYWORD)) 2496 kind=_VAR_KEYWORD))
1956 2497
2498 # Is 'func' is a pure Python function - don't validate the
2499 # parameters list (for correct order and defaults), it should be OK.
1957 return cls(parameters, 2500 return cls(parameters,
1958 return_annotation=annotations.get('return', _empty), 2501 return_annotation=annotations.get('return', _empty),
1959 __validate_parameters__=False) 2502 __validate_parameters__=is_duck_function)
1960 2503
1961 @classmethod 2504 @classmethod
1962 def from_builtin(cls, func): 2505 def from_builtin(cls, func):
1963 s = getattr(func, "__text_signature__", None) 2506 """Constructs Signature for the given builtin function."""
1964 if not s: 2507 return _signature_from_builtin(cls, func)
1965 return None 2508
1966 2509 @classmethod
1967 Parameter = cls._parameter_cls 2510 def from_callable(cls, obj):
1968 2511 """Constructs Signature for the given callable object."""
1969 if s.endswith("/)"): 2512 return _signature_from_callable(obj, sigcls=cls)
1970 kind = Parameter.POSITIONAL_ONLY
1971 s = s[:-2] + ')'
1972 else:
1973 kind = Parameter.POSITIONAL_OR_KEYWORD
1974
1975 s = "def foo" + s + ": pass"
1976
1977 try:
1978 module = ast.parse(s)
1979 except SyntaxError:
1980 return None
1981 if not isinstance(module, ast.Module):
1982 return None
1983
1984 f = module.body[0]
1985
1986 parameters = []
1987 empty = Parameter.empty
1988 invalid = object()
1989
1990 module = None
1991 module_dict = {}
1992 module_name = getattr(func, '__module__', None)
1993 if module_name:
1994 module = sys.modules.get(module_name, None)
1995 if module:
1996 module_dict = module.__dict__
1997 sys_module_dict = sys.modules
1998
1999 def parse_name(node):
2000 assert isinstance(node, ast.arg)
2001 if node.annotation != None:
2002 raise ValueError("Annotations are not currently supported")
2003 return node.arg
2004
2005 def wrap_value(s):
2006 try:
2007 value = eval(s, module_dict)
2008 except NameError:
2009 try:
2010 value = eval(s, sys_module_dict)
2011 except NameError:
2012 raise RuntimeError()
2013
2014 if isinstance(value, str):
2015 return ast.Str(value)
2016 if isinstance(value, (int, float)):
2017 return ast.Num(value)
2018 if isinstance(value, bytes):
2019 return ast.Bytes(value)
2020 if value in (True, False, None):
2021 return ast.NameConstant(value)
2022 raise RuntimeError()
2023
2024 class RewriteSymbolics(ast.NodeTransformer):
2025 def visit_Attribute(self, node):
2026 a = []
2027 n = node
2028 while isinstance(n, ast.Attribute):
2029 a.append(n.attr)
2030 n = n.value
2031 if not isinstance(n, ast.Name):
2032 raise RuntimeError()
2033 a.append(n.id)
2034 value = ".".join(reversed(a))
2035 return wrap_value(value)
2036
2037 def visit_Name(self, node):
2038 if not isinstance(node.ctx, ast.Load):
2039 raise ValueError()
2040 return wrap_value(node.id)
2041
2042 def p(name_node, default_node, default=empty):
2043 name = parse_name(name_node)
2044 if name is invalid:
2045 return None
2046 if default_node:
2047 try:
2048 default_node = RewriteSymbolics().visit(default_node)
2049 o = ast.literal_eval(default_node)
2050 except ValueError:
2051 o = invalid
2052 if o is invalid:
2053 return None
2054 default = o if o is not invalid else default
2055 parameters.append(Parameter(name, kind, default=default, annotation= empty))
2056
2057 # non-keyword-only parameters
2058 args = reversed(f.args.args)
2059 defaults = reversed(f.args.defaults)
2060 iter = itertools.zip_longest(args, defaults, fillvalue=None)
2061 for name, default in reversed(list(iter)):
2062 p(name, default)
2063
2064 # *args
2065 if f.args.vararg:
2066 kind = Parameter.VAR_POSITIONAL
2067 p(f.args.vararg, empty)
2068
2069 # keyword-only arguments
2070 kind = Parameter.KEYWORD_ONLY
2071 for name, default in zip(f.args.kwonlyargs, f.args.kw_defaults):
2072 p(name, default)
2073
2074 # **kwargs
2075 if f.args.kwarg:
2076 kind = Parameter.VAR_KEYWORD
2077 p(f.args.kwarg, empty)
2078
2079 return cls(parameters, return_annotation=cls.empty)
2080
2081 2513
2082 @property 2514 @property
2083 def parameters(self): 2515 def parameters(self):
2084 return self._parameters 2516 return self._parameters
2085 2517
2086 @property 2518 @property
2087 def return_annotation(self): 2519 def return_annotation(self):
2088 return self._return_annotation 2520 return self._return_annotation
2089 2521
2090 def replace(self, *, parameters=_void, return_annotation=_void): 2522 def replace(self, *, parameters=_void, return_annotation=_void):
2091 '''Creates a customized copy of the Signature. 2523 """Creates a customized copy of the Signature.
2092 Pass 'parameters' and/or 'return_annotation' arguments 2524 Pass 'parameters' and/or 'return_annotation' arguments
2093 to override them in the new copy. 2525 to override them in the new copy.
2094 ''' 2526 """
2095 2527
2096 if parameters is _void: 2528 if parameters is _void:
2097 parameters = self.parameters.values() 2529 parameters = self.parameters.values()
2098 2530
2099 if return_annotation is _void: 2531 if return_annotation is _void:
2100 return_annotation = self._return_annotation 2532 return_annotation = self._return_annotation
2101 2533
2102 return type(self)(parameters, 2534 return type(self)(parameters,
2103 return_annotation=return_annotation) 2535 return_annotation=return_annotation)
2104 2536
2537 def _hash_helper(self):
2538 return (tuple(param for param in self.parameters.values()
2539 if param.kind != _KEYWORD_ONLY),
2540 {param.name: param for param in self.parameters.values()
2541 if param.kind == _KEYWORD_ONLY},
2542 self._return_annotation)
2543
2105 def __hash__(self): 2544 def __hash__(self):
2106 hash_tuple = tuple(self.parameters.values()) 2545 params, kwo_params, return_annotation = self._hash_helper()
Yury Selivanov 2014/02/25 01:56:30 note to self: Add type(self) in the tuple?
2107 if self._return_annotation is not _empty: 2546 return hash((params, frozenset(kwo_params.items()), return_annotation))
2108 hash_tuple += (self._return_annotation,)
2109 return hash(hash_tuple)
2110 2547
2111 def __eq__(self, other): 2548 def __eq__(self, other):
2112 if (not issubclass(type(other), Signature) or 2549 return (isinstance(other, Signature) and
2113 self.return_annotation != other.return_annotation or 2550 self._hash_helper() == other._hash_helper())
2114 len(self.parameters) != len(other.parameters)):
2115 return False
2116
2117 other_positions = {param: idx
2118 for idx, param in enumerate(other.parameters.keys())}
2119
2120 for idx, (param_name, param) in enumerate(self.parameters.items()):
2121 if param.kind == _KEYWORD_ONLY:
2122 try:
2123 other_param = other.parameters[param_name]
2124 except KeyError:
2125 return False
2126 else:
2127 if param != other_param:
2128 return False
2129 else:
2130 try:
2131 other_idx = other_positions[param_name]
2132 except KeyError:
2133 return False
2134 else:
2135 if (idx != other_idx or
2136 param != other.parameters[param_name]):
2137 return False
2138
2139 return True
2140 2551
2141 def __ne__(self, other): 2552 def __ne__(self, other):
2142 return not self.__eq__(other) 2553 return not self.__eq__(other)
2143 2554
2144 def _bind(self, args, kwargs, *, partial=False): 2555 def _bind(self, args, kwargs, *, partial=False):
2145 '''Private method. Don't use directly.''' 2556 """Private method. Don't use directly."""
2146 2557
2147 arguments = OrderedDict() 2558 arguments = OrderedDict()
2148 2559
2149 parameters = iter(self.parameters.values()) 2560 parameters = iter(self.parameters.values())
2150 parameters_ex = () 2561 parameters_ex = ()
2151 arg_vals = iter(args) 2562 arg_vals = iter(args)
2152
2153 if partial:
2154 # Support for binding arguments to 'functools.partial' objects.
2155 # See 'functools.partial' case in 'signature()' implementation
2156 # for details.
2157 for param_name, param in self.parameters.items():
2158 if (param._partial_kwarg and param_name not in kwargs):
2159 # Simulating 'functools.partial' behavior
2160 kwargs[param_name] = param.default
2161 2563
2162 while True: 2564 while True:
2163 # Let's iterate through the positional arguments and corresponding 2565 # Let's iterate through the positional arguments and corresponding
2164 # parameters 2566 # parameters
2165 try: 2567 try:
2166 arg_val = next(arg_vals) 2568 arg_val = next(arg_vals)
2167 except StopIteration: 2569 except StopIteration:
2168 # No more positional arguments 2570 # No more positional arguments
2169 try: 2571 try:
2170 param = next(parameters) 2572 param = next(parameters)
(...skipping 15 matching lines...) Expand all
2186 parameters_ex = (param,) 2588 parameters_ex = (param,)
2187 break 2589 break
2188 elif (param.kind == _VAR_KEYWORD or 2590 elif (param.kind == _VAR_KEYWORD or
2189 param.default is not _empty): 2591 param.default is not _empty):
2190 # That's fine too - we have a default value for this 2592 # That's fine too - we have a default value for this
2191 # parameter. So, lets start parsing `kwargs`, starting 2593 # parameter. So, lets start parsing `kwargs`, starting
2192 # with the current parameter 2594 # with the current parameter
2193 parameters_ex = (param,) 2595 parameters_ex = (param,)
2194 break 2596 break
2195 else: 2597 else:
2598 # No default, not VAR_KEYWORD, not VAR_POSITIONAL,
2599 # not in `kwargs`
2196 if partial: 2600 if partial:
2197 parameters_ex = (param,) 2601 parameters_ex = (param,)
2198 break 2602 break
2199 else: 2603 else:
2200 msg = '{arg!r} parameter lacking default value' 2604 msg = '{arg!r} parameter lacking default value'
2201 msg = msg.format(arg=param.name) 2605 msg = msg.format(arg=param.name)
2202 raise TypeError(msg) from None 2606 raise TypeError(msg) from None
2203 else: 2607 else:
2204 # We have a positional argument to process 2608 # We have a positional argument to process
2205 try: 2609 try:
(...skipping 18 matching lines...) Expand all
2224 if param.name in kwargs: 2628 if param.name in kwargs:
2225 raise TypeError('multiple values for argument ' 2629 raise TypeError('multiple values for argument '
2226 '{arg!r}'.format(arg=param.name)) 2630 '{arg!r}'.format(arg=param.name))
2227 2631
2228 arguments[param.name] = arg_val 2632 arguments[param.name] = arg_val
2229 2633
2230 # Now, we iterate through the remaining parameters to process 2634 # Now, we iterate through the remaining parameters to process
2231 # keyword arguments 2635 # keyword arguments
2232 kwargs_param = None 2636 kwargs_param = None
2233 for param in itertools.chain(parameters_ex, parameters): 2637 for param in itertools.chain(parameters_ex, parameters):
2234 if param.kind == _POSITIONAL_ONLY:
2235 # This should never happen in case of a properly built
2236 # Signature object (but let's have this check here
2237 # to ensure correct behaviour just in case)
2238 raise TypeError('{arg!r} parameter is positional only, '
2239 'but was passed as a keyword'. \
2240 format(arg=param.name))
2241
2242 if param.kind == _VAR_KEYWORD: 2638 if param.kind == _VAR_KEYWORD:
2243 # Memorize that we have a '**kwargs'-like parameter 2639 # Memorize that we have a '**kwargs'-like parameter
2244 kwargs_param = param 2640 kwargs_param = param
2641 continue
2642
2643 if param.kind == _VAR_POSITIONAL:
2644 # Named arguments don't refer to '*args'-like parameters.
2645 # We only arrive here if the positional arguments ended
2646 # before reaching the last parameter before *args.
2245 continue 2647 continue
2246 2648
2247 param_name = param.name 2649 param_name = param.name
2248 try: 2650 try:
2249 arg_val = kwargs.pop(param_name) 2651 arg_val = kwargs.pop(param_name)
2250 except KeyError: 2652 except KeyError:
2251 # We have no value for this parameter. It's fine though, 2653 # We have no value for this parameter. It's fine though,
2252 # if it has a default value, or it is an '*args'-like 2654 # if it has a default value, or it is an '*args'-like
2253 # parameter, left alone by the processing of positional 2655 # parameter, left alone by the processing of positional
2254 # arguments. 2656 # arguments.
2255 if (not partial and param.kind != _VAR_POSITIONAL and 2657 if (not partial and param.kind != _VAR_POSITIONAL and
2256 param.default is _empty): 2658 param.default is _empty):
2257 raise TypeError('{arg!r} parameter lacking default value'. \ 2659 raise TypeError('{arg!r} parameter lacking default value'. \
2258 format(arg=param_name)) from None 2660 format(arg=param_name)) from None
2259 2661
2260 else: 2662 else:
2663 if param.kind == _POSITIONAL_ONLY:
2664 # This should never happen in case of a properly built
2665 # Signature object (but let's have this check here
2666 # to ensure correct behaviour just in case)
2667 raise TypeError('{arg!r} parameter is positional only, '
2668 'but was passed as a keyword'. \
2669 format(arg=param.name))
2670
2261 arguments[param_name] = arg_val 2671 arguments[param_name] = arg_val
2262 2672
2263 if kwargs: 2673 if kwargs:
2264 if kwargs_param is not None: 2674 if kwargs_param is not None:
2265 # Process our '**kwargs'-like parameter 2675 # Process our '**kwargs'-like parameter
2266 arguments[kwargs_param.name] = kwargs 2676 arguments[kwargs_param.name] = kwargs
2267 else: 2677 else:
2268 raise TypeError('too many keyword arguments') 2678 raise TypeError('too many keyword arguments')
2269 2679
2270 return self._bound_arguments_cls(self, arguments) 2680 return self._bound_arguments_cls(self, arguments)
2271 2681
2272 def bind(__bind_self, *args, **kwargs): 2682 def bind(*args, **kwargs):
2273 '''Get a BoundArguments object, that maps the passed `args` 2683 """Get a BoundArguments object, that maps the passed `args`
2274 and `kwargs` to the function's signature. Raises `TypeError` 2684 and `kwargs` to the function's signature. Raises `TypeError`
2275 if the passed arguments can not be bound. 2685 if the passed arguments can not be bound.
2276 ''' 2686 """
2277 return __bind_self._bind(args, kwargs) 2687 return args[0]._bind(args[1:], kwargs)
2278 2688
2279 def bind_partial(__bind_self, *args, **kwargs): 2689 def bind_partial(*args, **kwargs):
2280 '''Get a BoundArguments object, that partially maps the 2690 """Get a BoundArguments object, that partially maps the
2281 passed `args` and `kwargs` to the function's signature. 2691 passed `args` and `kwargs` to the function's signature.
2282 Raises `TypeError` if the passed arguments can not be bound. 2692 Raises `TypeError` if the passed arguments can not be bound.
2283 ''' 2693 """
2284 return __bind_self._bind(args, kwargs, partial=True) 2694 return args[0]._bind(args[1:], kwargs, partial=True)
2695
2696 def __reduce__(self):
2697 return (type(self),
2698 (tuple(self._parameters.values()),),
2699 {'_return_annotation': self._return_annotation})
2700
2701 def __setstate__(self, state):
2702 self._return_annotation = state['_return_annotation']
2703
2704 def __repr__(self):
2705 return '<{} at {:#x} "{}">'.format(self.__class__.__name__,
2706 id(self), self)
2285 2707
2286 def __str__(self): 2708 def __str__(self):
2287 result = [] 2709 result = []
2710 render_pos_only_separator = False
2288 render_kw_only_separator = True 2711 render_kw_only_separator = True
2289 for idx, param in enumerate(self.parameters.values()): 2712 for param in self.parameters.values():
2290 formatted = str(param) 2713 formatted = str(param)
2291 2714
2292 kind = param.kind 2715 kind = param.kind
2716
2717 if kind == _POSITIONAL_ONLY:
2718 render_pos_only_separator = True
2719 elif render_pos_only_separator:
2720 # It's not a positional-only parameter, and the flag
2721 # is set to 'True' (there were pos-only params before.)
2722 result.append('/')
2723 render_pos_only_separator = False
2724
2293 if kind == _VAR_POSITIONAL: 2725 if kind == _VAR_POSITIONAL:
2294 # OK, we have an '*args'-like parameter, so we won't need 2726 # OK, we have an '*args'-like parameter, so we won't need
2295 # a '*' to separate keyword-only arguments 2727 # a '*' to separate keyword-only arguments
2296 render_kw_only_separator = False 2728 render_kw_only_separator = False
2297 elif kind == _KEYWORD_ONLY and render_kw_only_separator: 2729 elif kind == _KEYWORD_ONLY and render_kw_only_separator:
2298 # We have a keyword-only parameter to render and we haven't 2730 # We have a keyword-only parameter to render and we haven't
2299 # rendered an '*args'-like parameter before, so add a '*' 2731 # rendered an '*args'-like parameter before, so add a '*'
2300 # separator to the parameters list ("foo(arg1, *, arg2)" case) 2732 # separator to the parameters list ("foo(arg1, *, arg2)" case)
2301 result.append('*') 2733 result.append('*')
2302 # This condition should be only triggered once, so 2734 # This condition should be only triggered once, so
2303 # reset the flag 2735 # reset the flag
2304 render_kw_only_separator = False 2736 render_kw_only_separator = False
2305 2737
2306 result.append(formatted) 2738 result.append(formatted)
2307 2739
2740 if render_pos_only_separator:
2741 # There were only positional-only parameters, hence the
2742 # flag was not reset to 'False'
2743 result.append('/')
2744
2308 rendered = '({})'.format(', '.join(result)) 2745 rendered = '({})'.format(', '.join(result))
2309 2746
2310 if self.return_annotation is not _empty: 2747 if self.return_annotation is not _empty:
2311 anno = formatannotation(self.return_annotation) 2748 anno = formatannotation(self.return_annotation)
2312 rendered += ' -> {}'.format(anno) 2749 rendered += ' -> {}'.format(anno)
2313 2750
2314 return rendered 2751 return rendered
2752
2753
2754 def signature(obj):
2755 """Get a signature object for the passed callable."""
2756 return Signature.from_callable(obj)
2757
2315 2758
2316 def _main(): 2759 def _main():
2317 """ Logic for inspecting an object given at command line """ 2760 """ Logic for inspecting an object given at command line """
2318 import argparse 2761 import argparse
2319 import importlib 2762 import importlib
2320 2763
2321 parser = argparse.ArgumentParser() 2764 parser = argparse.ArgumentParser()
2322 parser.add_argument( 2765 parser.add_argument(
2323 'object', 2766 'object',
2324 help="The object to be analysed. " 2767 help="The object to be analysed. "
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
2366 else: 2809 else:
2367 print('Line: {}'.format(lineno)) 2810 print('Line: {}'.format(lineno))
2368 2811
2369 print('\n') 2812 print('\n')
2370 else: 2813 else:
2371 print(getsource(obj)) 2814 print(getsource(obj))
2372 2815
2373 2816
2374 if __name__ == "__main__": 2817 if __name__ == "__main__":
2375 _main() 2818 _main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+