def supported_filters(
    support_keys=[],
    optional_support_keys=[],
    ignore_support_keys=[],
):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **filters):
            wrapped_func = get_wrapped_func(func)
            argspec = inspect.getargspec(wrapped_func)
            wrapped_args = argspec.args
            args_defaults = argspec.defaults
            # wrapped_must_args are positional args caller must pass in.
            if args_defaults:
                wrapped_must_args = wrapped_args[:-len(args_defaults)]
            else:
                wrapped_must_args = wrapped_args[:]
            # make sure any positional args without default value in
            # decorated function should appear in args or filters.
            if len(args) < len(wrapped_must_args):
                remain_args = wrapped_must_args[len(args):]
                for remain_arg in remain_args:
                    if remain_arg not in filters:
                        raise exception.InvalidParameter(
                            'function missing declared arg %s '
                            'while caller sends args %s' % (
                                remain_arg, args
                            )
                        )
            # make sure args should be no more than positional args
            # declared in decorated function.
            if len(args) > len(wrapped_args):
                raise exception.InvalidParameter(
                    'function definition args %s while the caller '
                    'sends args %s' % (
                        wrapped_args, args
                    )
                )
            # exist_args are positional args caller has given.
            exist_args = dict(zip(wrapped_args, args)).keys()
            must_support_keys = set(support_keys)
            all_support_keys = must_support_keys | set(optional_support_keys)
            wrapped_supported_keys = set(filters) | set(exist_args)
            unsupported_keys = (
                set(filters) - set(wrapped_args) -
                all_support_keys - set(ignore_support_keys)
            )
            # unsupported_keys are the keys that are not in support_keys,
            # optional_support_keys, ignore_support_keys and are not passed in
            # by positional args. It means the decorated function may
            # not understand these parameters.
            if unsupported_keys:
                raise exception.InvalidParameter(
                    'filter keys %s are not supported for %s' % (
                        list(unsupported_keys), wrapped_func
                    )
                )
            # missing_keys are the keys that must exist but missing in
            # both positional args or kwargs.
            missing_keys = must_support_keys - wrapped_supported_keys
            if missing_keys:
                raise exception.InvalidParameter(
                    'filter keys %s not found for %s' % (
                        list(missing_keys), wrapped_func
                    )
                )
            # We filter kwargs to eliminate ignore_support_keys in kwargs
            # passed to decorated function.
            filtered_filters = dict([
                (key, value)
                for key, value in filters.items()
                if key not in ignore_support_keys
            ])
            return func(*args, **filtered_filters)
        return wrapper
    return decorator
Decorator to check kwargs keys.
dataset/ETHPy150Open openstack/compass-core/compass/db/api/utils.py/supported_filters