app/django/dispatch/robustapply.py
changeset 54 03e267d67478
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     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)