12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- """Robust apply mechanism
- Provides a function "call", which can sort out
- what arguments a given callable object can take,
- and subset the given arguments to match only
- those which are acceptable.
- """
- import sys
- if sys.hexversion >= 0x3000000:
- im_func = '__func__'
- im_self = '__self__'
- im_code = '__code__'
- func_code = '__code__'
- else:
- im_func = 'im_func'
- im_self = 'im_self'
- im_code = 'im_code'
- func_code = 'func_code'
- def function(receiver):
- """Get function-like callable object for given receiver
- returns (function_or_method, codeObject, fromMethod)
- If fromMethod is true, then the callable already
- has its first argument bound
- """
- if hasattr(receiver, '__call__'):
- # Reassign receiver to the actual method that will be called.
- if hasattr(receiver.__call__, im_func) or hasattr(receiver.__call__,
- im_code):
- receiver = receiver.__call__
- if hasattr(receiver, im_func):
- # an instance-method...
- return receiver, getattr(getattr(receiver, im_func), func_code), 1
- elif not hasattr(receiver, func_code):
- raise ValueError('unknown receiver type %s %s' % (receiver,
- type(receiver)))
- return receiver, getattr(receiver, func_code), 0
- def robustApply(receiver, *arguments, **named):
- """Call receiver with arguments and an appropriate subset of named
- """
- receiver, codeObject, startIndex = function(receiver)
- acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]
- for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:
- if name in named:
- raise TypeError(
- """Argument %r specified both positionally and as a keyword"""
- """ for calling %r""" % (name, receiver)
- )
- if not (codeObject.co_flags & 8):
- # fc does not have a **kwds type parameter, therefore
- # remove unacceptable arguments.
- for arg in named.keys():
- if arg not in acceptable:
- del named[arg]
- return receiver(*arguments, **named)
|