def assertPublicAPISignatures(self, baseinst, inst): def get_public_apis(inst): methods = {} def findmethods(object): return inspect.ismethod(object) or inspect.isfunction(object) for (name, value) in inspect.getmembers(inst, findmethods): if name.startswith("_"): continue methods[name] = value return methods baseclass = baseinst.__class__.__name__ basemethods = get_public_apis(baseinst) implmethods = get_public_apis(inst) extranames = [] for name in sorted(implmethods.keys()): if name not in basemethods: extranames.append(name) self.assertEqual([], extranames, "public APIs not listed in base class %s" % baseclass) for name in sorted(implmethods.keys()): baseargs = utils.getargspec(basemethods[name]) implargs = utils.getargspec(implmethods[name]) self.assertEqual( baseargs, implargs, "%s args don't match base class %s" % (name, baseclass))
def assertPublicAPISignatures(self, baseinst, inst): def get_public_apis(inst): methods = {} def findmethods(object): return inspect.ismethod(object) or inspect.isfunction(object) for (name, value) in inspect.getmembers(inst, findmethods): if name.startswith("_"): continue methods[name] = value return methods baseclass = baseinst.__class__.__name__ basemethods = get_public_apis(baseinst) implmethods = get_public_apis(inst) extranames = [] for name in sorted(implmethods.keys()): if name not in basemethods: extranames.append(name) self.assertEqual([], extranames, "public APIs not listed in base class %s" % baseclass) for name in sorted(implmethods.keys()): baseargs = utils.getargspec(basemethods[name]) implargs = utils.getargspec(implmethods[name]) self.assertEqual(baseargs, implargs, "%s args don't match base class %s" % (name, baseclass))
def _get_argspecs(cls): """Return a dict of method_name->argspec for every method of cls.""" argspecs = {} # getmembers returns all members, including members inherited from # the base class. It's redundant for us to test these, but as # they'll always pass it's not worth the complexity to filter them out. for (name, method) in inspect.getmembers(cls, inspect.ismethod): # Subclass __init__ methods can usually be legitimately different if name == '__init__': continue while hasattr(method, '__wrapped__'): # This is a wrapped function. The signature we're going to # see here is that of the wrapper, which is almost certainly # going to involve varargs and kwargs, and therefore is # unlikely to be what we want. If the wrapper manupulates the # arguments taken by the wrapped function, the wrapped function # isn't what we want either. In that case we're just stumped: # if it ever comes up, add more knobs here to work round it (or # stop using a dynamic language). # # Here we assume the wrapper doesn't manipulate the arguments # to the wrapped function and inspect the wrapped function # instead. method = getattr(method, '__wrapped__') argspecs[name] = utils.getargspec(method) return argspecs
def refresh_cache(f): """Decorator to update the instance_info_cache Requires context and instance as function args """ argspec = utils.getargspec(f) @functools.wraps(f) def wrapper(self, context, *args, **kwargs): try: # get the instance from arguments (or raise ValueError) instance = kwargs.get('instance') if not instance: instance = args[argspec.args.index('instance') - 2] except ValueError: msg = _('instance is a required argument to use @refresh_cache') raise Exception(msg) with lockutils.lock('refresh_cache-%s' % instance.uuid): # We need to call the wrapped function with the lock held to ensure # that it can call _get_instance_nw_info safely. res = f(self, context, *args, **kwargs) update_instance_cache_with_nw_info(self, context, instance, nw_info=res) # return the original function's return value return res return wrapper
def validate_args(fn, *args, **kwargs): """Check that the supplied args are sufficient for calling a function. >>> validate_args(lambda a: None) Traceback (most recent call last): ... MissingArgs: Missing argument(s): a >>> validate_args(lambda a, b, c, d: None, 0, c=1) Traceback (most recent call last): ... MissingArgs: Missing argument(s): b, d :param fn: the function to check :param arg: the positional arguments supplied :param kwargs: the keyword arguments supplied """ argspec = utils.getargspec(fn) num_defaults = len(argspec.defaults or []) required_args = argspec.args[:len(argspec.args) - num_defaults] if six.get_method_self(fn) is not None: required_args.pop(0) missing = [arg for arg in required_args if arg not in kwargs] missing = missing[len(args):] return missing