Decorator that validates task arguments:
     -  Checks the argspec for the input function
     -  Validates that all arguments have been specified with non-None values
     -  Aborts with helpful errors

    One caveat: this decorator *MUST* be the innermost decorator because other
    decorators will typically replace the declared args with *args and **kwargs.

def with_validation(func):
    """
    Decorator that validates task arguments:
     -  Checks the argspec for the input function
     -  Validates that all arguments have been specified with non-None values
     -  Aborts with helpful errors

    One caveat: this decorator *MUST* be the innermost decorator because other
    decorators will typically replace the declared args with *args and **kwargs.
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        assert_valid_arguments(func, *args, **kwargs)
        return func(*args, **kwargs)
    return wrapper