app/django/dispatch/robustapply.py
author Sverre Rabbelier <srabbelier@gmail.com>
Thu, 09 Oct 2008 23:48:20 +0000
changeset 294 1fdaab4a6ef2
parent 54 03e267d67478
permissions -rw-r--r--
Refactor existing code to use the new access module Instead of ending up with many different ways to do access control, we end up having only one centralized place wher access control is done. Patch by: Sverre Rabbelier Reviewed by: Pawel Solyga, Augie Fackler, Todd Larsen Reviewed at: http://codereviews.googleopensourceprograms.com/1601 Review id: 1601

"""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.
"""

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__'):
        # receiver is a class instance; assume it is callable.
        # 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, receiver.im_func.func_code, 1
    elif not hasattr( receiver, 'func_code'):
        raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver)))
    return receiver, 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 named.has_key( name ):
            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)