0001"""Robust apply mechanism.
0002
0003Provides a function 'call', which can sort out what arguments a given
0004callable object can take, and subset the given arguments to match only
0005those which are acceptable.
0006"""
0007
0008def function(receiver):
0009 """Get function-like callable object for given receiver.
0010
0011 returns (function_or_method, codeObject, fromMethod)
0012
0013 If fromMethod is true, then the callable already has its first
0014 argument bound.
0015 """
0016 if hasattr(receiver, '__call__'):
0017
0018
0019 c = receiver.__call__
0020 if hasattr(c, 'im_func') or hasattr(c, 'im_code'):
0021 receiver = c
0022 if hasattr(receiver, 'im_func'):
0023
0024 return receiver, receiver.im_func.func_code, 1
0025 elif not hasattr(receiver, 'func_code'):
0026 raise ValueError(
0027 'unknown reciever type %s %s' % (receiver, type(receiver)))
0028 return receiver, receiver.func_code, 0
0029
0030
0031def robust_apply(receiver, signature, *arguments, **named):
0032 """Call receiver with arguments and appropriate subset of named.
0033 ``signature`` is the callable used to determine the call signature
0034 of the receiver, in case ``receiver`` is a callable wrapper of the
0035 actual receiver."""
0036 signature, code_object, startIndex = function(signature)
0037 acceptable = code_object.co_varnames[
0038 startIndex + len(arguments):
0039 code_object.co_argcount
0040 ]
0041 for name in code_object.co_varnames[
0042 startIndex:startIndex + len(arguments)
0043 ]:
0044 if named.has_key(name):
0045 raise TypeError(
0046 'Argument %r specified both positionally '
0047 'and as a keyword for calling %r'
0048 % (name, signature)
0049 )
0050 if not (code_object.co_flags & 8):
0051
0052
0053 for arg in named.keys():
0054 if arg not in acceptable:
0055 del named[arg]
0056 return receiver(*arguments, **named)