Search code examples
pythonpython-3.5python-decoratorsfunctools

Accessing keyword argument of decorated function inside the decorator fails in Python 3


kwargs is empty in the following code. How to access timeout keyword arg of the decorated function?

import functools
def retriable(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        timeout = kwargs['timeout']
        criteria_satisfied = func(*args, **kwargs)
        while not criteria_satisfied and timeout > 0:
            time.sleep(5)
            timeout -= 5
            criteria_satisfied = func(*args, **kwargs)
        return criteria_satisfied
    return wrapper

@retriable
def decorated(ip, timeout=60):
    ... some logic
    return True 

decorated(ip)

Solution

  • The solution was to make decorator with arguments. Which would return another decorator over the function and would populate the created closure with the argument value.

    import functools
    def retriable_with_arg(timeout):
        def retriable(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                alive_timeout = timeout
                criteria_satisfied = func(*args, **kwargs)
                while not criteria_satisfied and alive_timeout > 0:
                    time.sleep(5)
                    alive_timeout -= 5
                    criteria_satisfied = func(*args, **kwargs)
                return criteria_satisfied
         return wrapper
    return retriable
    
    @retriable(timeout=60)
    def decorated(ip, timeout=60):
        ... some logic
        return True 
    
    decorated(ip)