def __call__(self, f): argspec = misc.getargspec(f) self.arg_names = argspec[0] self.have_varargs = (argspec[1] is not None) and not self.add_varargs assert ((len(self.constraints) == len(self.arg_names) and not self.have_varargs) or (len(self.constraints) == len(self.arg_names) + 1 and self.have_varargs)) if self.add_varargs: # add varargs to the signature and use decorator.FunctionMaker # directly to create the decorated function orig_signature = inspect.getargspec(f) assert orig_signature.varargs is None signature = orig_signature._replace(varargs='args') evaldict = self.wrapper.__globals__.copy() evaldict['_call_'] = self.wrapper evaldict['_func_'] = f return decorator.FunctionMaker.create( '%s%s' % (f.__name__, inspect.formatargspec(*signature)), 'return _call_(_func_, %(shortsignature)s)', evaldict, undecorated=f, __wrapped__=f, doc=f.__doc__) else: return decorator.decorator(self.wrapper, f)
def call(args, kwargs, funcs, name=None): """ Search funcs for a function with parameters such that args and kwargs can be applied, and call the first suitable function that is found. """ for f in funcs: n = len(args) # get argument names and the number of default arguments of f argspec = misc.getargspec(f) names = argspec[0] varargs = argspec[1] ndef = len(argspec[3]) if argspec[3] else 0 # names of the default arguments not overridden by positional arguments npos = max(len(names) - ndef, n) defargs = names[npos:] # check if the number of positional arguments fits, and if the # remaining parameters can be filled with keyword and default # arguments. # alternatively, a suitable function with varargs is also accepted. if ((n <= len(names) and set(kwargs) | set(defargs) == set(names[n:])) or (n >= len(names) and varargs is not None)): # call f with all original arguments return f(*args, **kwargs) # no overload found, generate a comprehensible error message if name is None: name = inspect.stack()[1][3] # format arg spec for each candidate formatargspec = lambda f: inspect.formatargspec(*misc.getargspec(f)) candidates = (' %s%s' % (name, formatargspec(f)) for f in funcs) # formatargspec() doesn't seem to care that the first argument mixes # asterisks and argument names argx = ['*'] * len(args) kwargx = ['*'] * len(kwargs) formatvalue = lambda v: '=%s' % v args_used = inspect.formatargspec(argx + list(kwargs.keys()), defaults=kwargx, formatvalue=formatvalue) message = ("no suitable overload found for %s%s, candidates are:\n%s" % (name, args_used, '\n'.join(candidates))) raise TypeError(message)
def unit_to_string(unit): # can't do anything for units that didn't go through @store (or @accept) assert hasattr(unit, '_name') argnames = misc.getargspec(unit._function)[0] args = [ misc.bytestring(a) if isinstance(a, bytearray) else a for a in unit._args ] # (ab)use inspect module to format the arguments used formatted = inspect.formatargspec(args=argnames, defaults=args) return unit._name + formatted