|
1 """Robust apply mechanism |
|
2 |
|
3 Provides a function "call", which can sort out |
|
4 what arguments a given callable object can take, |
|
5 and subset the given arguments to match only |
|
6 those which are acceptable. |
|
7 """ |
|
8 |
|
9 def function( receiver ): |
|
10 """Get function-like callable object for given receiver |
|
11 |
|
12 returns (function_or_method, codeObject, fromMethod) |
|
13 |
|
14 If fromMethod is true, then the callable already |
|
15 has its first argument bound |
|
16 """ |
|
17 if hasattr(receiver, '__call__'): |
|
18 # receiver is a class instance; assume it is callable. |
|
19 # Reassign receiver to the actual method that will be called. |
|
20 if hasattr( receiver.__call__, 'im_func') or hasattr( receiver.__call__, 'im_code'): |
|
21 receiver = receiver.__call__ |
|
22 if hasattr( receiver, 'im_func' ): |
|
23 # an instance-method... |
|
24 return receiver, receiver.im_func.func_code, 1 |
|
25 elif not hasattr( receiver, 'func_code'): |
|
26 raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) |
|
27 return receiver, receiver.func_code, 0 |
|
28 |
|
29 def robustApply(receiver, *arguments, **named): |
|
30 """Call receiver with arguments and an appropriate subset of named |
|
31 """ |
|
32 receiver, codeObject, startIndex = function( receiver ) |
|
33 acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] |
|
34 for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: |
|
35 if named.has_key( name ): |
|
36 raise TypeError( |
|
37 """Argument %r specified both positionally and as a keyword for calling %r"""% ( |
|
38 name, receiver, |
|
39 ) |
|
40 ) |
|
41 if not (codeObject.co_flags & 8): |
|
42 # fc does not have a **kwds type parameter, therefore |
|
43 # remove unacceptable arguments. |
|
44 for arg in named.keys(): |
|
45 if arg not in acceptable: |
|
46 del named[arg] |
|
47 return receiver(*arguments, **named) |