<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 async def retry_async(func, attempts=5, sleeptime_callback=calculate_sleep_time, retry_exceptions=Exception, args=(), kwargs=None, sleeptime_kwargs=None):
 """Retry ``func``, where ``func`` is an awaitable. Args: func (function):
 an awaitable function. attempts (int, optional):
 the number of attempts to make. Default is 5. sleeptime_callback (function, optional):
 the function to use to determine how long to sleep after each attempt. Defaults to ``calculateSleepTime``. retry_exceptions (list or exception, optional):
 the exception(s) to retry on. Defaults to ``Exception``. args (list, optional):
 the args to pass to ``function``. Defaults to () kwargs (dict, optional):
 the kwargs to pass to ``function``. Defaults to {}. sleeptime_kwargs (dict, optional):
 the kwargs to pass to ``sleeptime_callback``. If None, use {}. Defaults to None. Returns: object: the value from a successful ``function`` call Raises: Exception: the exception from a failed ``function`` call, either outside of the retry_exceptions, or one of those if we pass the max ``attempts``. """

    kwargs = kwargs or {}
    attempt = 1
    while True:
        try:
            return await func(*args, **kwargs)
        except retry_exceptions:
            attempt += 1
            if attempt > attempts:
                log.warning("retry_async: {}: too many retries!".format(func.__name__))
                raise
            sleeptime_kwargs = sleeptime_kwargs or {}
            sleep_time = sleeptime_callback(attempt, **sleeptime_kwargs)
            log.debug("retry_async: {}: sleeping {} seconds before retry".format(func.__name__, sleep_time))
            await asyncio.sleep(sleep_time)