Eziz Durdyyev
Eziz Durdyyev

Reputation: 1158

Determine whether *args is providing a specific named argument from a decorator

I have a decorator, and in that decorator I want to check if the decorated function has an argument with the name query. If it exists I want to detect its position in *args like this: args[1]. I want to perform this in wrapper function. I want to do something like this:

def some_decorator(func):
    @wraps(func)
    def wrapper_func(*args, **kwargs):
        ind = 0
        query = ''
        for arg in args:
            if arg.__name__ == 'query'
                query = 'Found'
                break
            ind +=1
        if query == 'Found':
            query = args[ind]
    return wrapper_func

For clarity, I use it like this:

@some_decorator
def find_all(self, some_arg, query=None):
    pass

The thing is, I use the decorator also for other functions, with different signatures that may or may not have query argument. I hope this clarifies things.

Upvotes: 0

Views: 360

Answers (2)

Green Cloak Guy
Green Cloak Guy

Reputation: 24691

If I'm understanding you correctly, then I think you can use the inspect module:

import inspect
...
def some_decorator(func):
    def wrapper_func(*args, **kwargs):
        # get function signature using inspect.signature()
        signature = inspect.signature(func)
        # find the subset of arguments that are positional-only
        positional_args = [name for name in signature.parameters 
                           if signature.parameters[name].kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)]
        # This should give us the names of args that *may* be positional. 
        # They should also be in the proper order, since positional-or-keyword args
        # cannot precede positional-only args.
        # Now, we can search for a positional arg named 'query', get an index...
        try:
            query_idx = positional_args.index('query')
        except ValueError:
            query_idx = -1
        # ... and extract the corresponding value passed for that in *args
        if 0 <= query_idx < len(args):
            query = args[query_idx]
        else:
            query = None
        # then do something with that
        ...
    return wrapper_func

Upvotes: 2

CCebrian
CCebrian

Reputation: 75

You could try with array.index()

query = ''

try:
    idx = args.index('query')
except ValueError:
    idx = -1

if idx != -1:
   query = args[idx]

Upvotes: -1

Related Questions