| 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) |
|---|