import time


def retry_call(func, ignore_exceptions, attempts=5, interval=1, interval_exponential_growth=1):
    """
    Attempt to call func repeatedly if one of provided exceptions is hit.
    Should different exception type be hit, such exception is raised.
    Should maximum number of attempts be hit, the last exception is raised.

    :param func: callable to run
    :type func: callable
    :param ignore_exceptions: One exception or iterable of exceptions under which the callable should be re-run
    :type ignore_exceptions: Exception or iterable of Exception
    :param attempts: Number of attempts. Must be larger or equal 1. Use float('inf') for infinite number of retries.
    :type attempts: int or float
    :param interval: Sleep time between re-runs
    :type interval: int or float
    :param interval_exponential_growth: Grow the interval exponentially using the provided base. If the call is not successful, the next attempt will take the the previous iterval value multiplied by exponential_growth seconds. If the growth is 2, the iterval will be: 1, 2, 4, 8, 16, ...
    :param interval_exponential_growth: int
    :return: Return value of the func
    """
    if attempts < 1:
        raise ValueError('Number of attempts must be larger or equal 1')
    while True:
        attempts -= 1
        try:
            return func()
        except ignore_exceptions:
            if attempts <= 0:
                raise
            time.sleep(interval)
            interval *= interval_exponential_growth