Source code for pydispatch.robustapply

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

import sys

if sys.hexversion >= 0x3000000:
    im_func = "__func__"
    im_self = "__self__"
    im_code = "__code__"
    func_code = "__code__"
else:
    im_func = "im_func"
    im_self = "im_self"
    im_code = "im_code"
    func_code = "func_code"


[docs]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__"): # 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, getattr(getattr(receiver, im_func), func_code), 1 if not hasattr(receiver, func_code): raise ValueError("unknown receiver type %s %s" % (receiver, type(receiver))) return receiver, getattr(receiver, func_code), 0
VAR_ARGS = 4 VAR_NAMES = 8
[docs]def robustApply(receiver, *arguments, **named): """Call receiver with arguments and an appropriate subset of named The effect of this wrapper is to allow for specifying a large number of parameters which may not exist in the final function via named parameters, and have those parameters ignored in the final call. """ receiver, codeObject, startIndex = function(receiver) has_varargs = bool(codeObject.co_flags & VAR_ARGS) has_varnames = bool(codeObject.co_flags & VAR_NAMES) posonly_count = getattr(codeObject, "co_posonlyargcount", 0) posnamed_arguments = codeObject.co_varnames[posonly_count : codeObject.co_argcount] named_onlyarguments = codeObject.co_varnames[ codeObject.co_argcount : len(codeObject.co_varnames) + (-1 if has_varnames else 0) + (-1 if has_varargs else 0) ] # Implements: You can't have a parameter in both args and keywords, # reporting an easily debugged message # Implements: You can't have a posonly arg in named (as a side effect of the above) for name in codeObject.co_varnames[ 0 : min((len(arguments), codeObject.co_argcount)) ]: if name in named: raise TypeError( """Argument %r specified both positionally and as a keyword""" """ for calling %r""" % (name, receiver) ) # Implements: You can only passed keyword parameters if the parameter exists and is # not a positional-only parameter or a varargs or varkeywords parameter. # Note that this silently drops TypeErrors for passing the name of the varargs or # varkeyword variables because it only allows through the valid arg-names for # the function if not has_varnames: acceptable = ( posnamed_arguments[len(arguments) - posonly_count :] + named_onlyarguments ) # fc does not have a **kwds type parameter, therefore # remove unacceptable arguments. named = {k: v for k, v in named.items() if k in acceptable} return receiver(*arguments, **named)