a generic auto-retry function  @wrapper - decorator

    :param Exception exception_t: exception (or tuple of exceptions) to auto retry
    :param int retries: max retries before it raises the Exception (defaults to 3)
    :param int_or_float sleepSeconds: base sleep seconds between retries (defaults to 1)
    :param int back_of_factor: factor to back off on each retry (defaults to 1)
    :param str msg: message to append to logs
    :param int auto_log: (0 | 1 | 2) logs (exception) failures if > 0 logs (info) retries also if > 1
    :param bool raise_on_failure: if True will re-raise exception when retries are exhausted (defaults to True)
    :returns:
        function result if successful (on first place or after retrying)
        the *last* retry Exception if not successful, check not isinstance(result , Exception) to see if it managed to succeed

def auto_retry(exception_t, retries=3, sleepSeconds=1, back_of_factor=1, msg='', auto_log=1, raise_on_failure=True):
    """a generic auto-retry function  @wrapper - decorator

    :param Exception exception_t: exception (or tuple of exceptions) to auto retry
    :param int retries: max retries before it raises the Exception (defaults to 3)
    :param int_or_float sleepSeconds: base sleep seconds between retries (defaults to 1)
    :param int back_of_factor: factor to back off on each retry (defaults to 1)
    :param str msg: message to append to logs
    :param int auto_log: (0 | 1 | 2) logs (exception) failures if > 0 logs (info) retries also if > 1
    :param bool raise_on_failure: if True will re-raise exception when retries are exhausted (defaults to True)
    :returns:
        function result if successful (on first place or after retrying)
        the *last* retry Exception if not successful, check not isinstance(result , Exception) to see if it managed to succeed
    """
    def wrapper(func):
        def fun_call(*args, **kwargs):
            tries = 0
            while tries < retries:
                try:
                    return func(*args, **kwargs)
                except exception_t as e:
                    tries += 1
                    sleep_seconds = sleepSeconds * tries * back_of_factor
                    if auto_log > 0:
                        ermsg = auto_retry_msg_frmt.format(class_name_str(e, True), e, tries, retries, sleep_seconds, func.__name__, args, kwargs, msg)
                    if tries < retries:
                        if auto_log > 1:
                            LOG.info(ermsg)
                        time.sleep(sleep_seconds)
                    else:
                        if auto_log > 0:
                            LOG.exception(ermsg)
                        if raise_on_failure:
                            raise
                        return e
        return fun_call
    return wrapper