00001 """Robust apply mechanism
00002
00003 Provides a function "call", which can sort out
00004 what arguments a given callable object can take,
00005 and subset the given arguments to match only
00006 those which are acceptable.
00007 """
00008
00009 __version__ = "$Revision: 1.2 $"
00010
00011 def function( receiver ):
00012 """Get function-like callable object for given receiver
00013
00014 returns (function_or_method, codeObject, fromMethod)
00015
00016 If fromMethod is true, then the callable already
00017 has its first argument bound
00018 """
00019 if hasattr(receiver, '__call__'):
00020
00021
00022 if hasattr( receiver.__call__, 'im_func') or hasattr( receiver.__call__, 'im_code'):
00023 receiver = receiver.__call__
00024 if hasattr( receiver, 'im_func' ):
00025
00026 return receiver, receiver.im_func.func_code, 1
00027 elif not hasattr( receiver, 'func_code'):
00028 raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver)))
00029 return receiver, receiver.func_code, 0
00030
00031 def robustApply(receiver, *arguments, **named):
00032 """Call receiver with arguments and an appropriate subset of named
00033 """
00034 receiver, codeObject, startIndex = function( receiver )
00035 acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]
00036 for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:
00037 if named.has_key( name ):
00038 raise TypeError(
00039 """Argument %r specified both positionally and as a keyword for calling %r"""% (
00040 name, receiver,
00041 )
00042 )
00043 if not (codeObject.co_flags & 8):
00044
00045
00046 for arg in named.keys():
00047 if arg not in acceptable:
00048 del named[arg]
00049 return receiver(*arguments, **named)
00050
00051