Повтор Python с использованием цепкости без декоратора

Я пытаюсь сделать попытку, используя цепкость (без декоратора). Мой код выглядит как описано здесь.

import logging
from tenacity import retry
import tenacity


def print_msg():
    try:
        logging.info('Hello')
        logging.info("World")
        raise Exception('Test error')
    except Exception as e:
        logging.error('caught error')
        raise e


if __name__ == '__main__':
    logging.basicConfig(
        format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
        datefmt='%d-%m-%Y:%H:%M:%S',
        level=logging.INFO)
    logging.info('Starting')
    try:
        r = tenacity.Retrying(
            tenacity.stop_after_attempt(2),
            tenacity.wait_incrementing(start=10, increment=100, max=1000),
            reraise=True
        )
        try:
            r.call(print_msg)
        except Exception:
            logging.error('Test error 2')
    except Exception:
        logging.error('Received Exception')

При выполнении вышеуказанного кода. Вывод выглядит как ниже без повторов

/Users/dmanna/PycharmProjects/demo/venv/bin/python /Users/dmanna/PycharmProjects/demo/retrier.py
25-11-2018:00:29:47,140 INFO     [retrier.py:21] Starting
25-11-2018:00:29:47,140 INFO     [retrier.py:8] Hello
25-11-2018:00:29:47,140 INFO     [retrier.py:9] World
25-11-2018:00:29:47,140 ERROR    [retrier.py:12] caught error
25-11-2018:00:29:47,141 ERROR    [retrier.py:31] Test error 2

Process finished with exit code 0

Может кто-нибудь сообщить мне, что происходит не так, как я не вижу повторов в приведенном выше коде?

3 ответа

Здесь ответили Перекрестный ответ

Хм, я не думаю, что вы используете API здесь правильно:

r = tenacity.Retrying(
            tenacity.stop_after_attempt(2),
            tenacity.wait_incrementing(start=10, increment=100, max=1000),
            reraise=True
        )

Это переводится как:

r = tenacity.Retrying(
            sleep=tenacity.stop_after_attempt(2),
            stop=tenacity.wait_incrementing(start=10, increment=100, max=1000),
            reraise=True
        )

Который не собирается делать то, что вы хотите.

Ты хочешь:

r = tenacity.Retrying(
            stop=tenacity.stop_after_attempt(2),
            wait=tenacity.wait_incrementing(start=10, increment=100, max=1000),
            reraise=True
        )

Примечание для пользователей Python 3.4+ (который поддерживает аннотации): для явного принудительного повторения попытки в Tenacity обычно используется аннотирование его простым @retry а затем поднять специальное исключение TryAgain.

@retry
def do_something():
    result = something_else()
    if result == 23:
       raise TryAgain

Этот подход, аналогичный ответу для Python 2.7 на этой странице, также можно реализовать:

import tenacity

def do_something():
    result = something_else()
    if result == 23:
       raise TryAgain

r = tenacity.Retrying(
        stop=tenacity.stop_after_attempt(2),
        wait=tenacity.wait_incrementing(start=10, increment=100, max=1000)
    )
r.wraps(do_something)

Дополнительные сведения см. В документации API о том, следует ли повторить попытку или об источнике, определяющем аннотации.

не используя упорство и не без декоратора, но выслушайте меня: вот хитрый способ повторять функции на лету без необходимости украшать какое-либо определение функции с помощью@retry. У меня возникла проблема: пара пакетов вызывала проблемы, а один из классов был слишком запутанным, чтобы пытаться перезаписать методы класса с наследованием:

      def retry(times=2, wait=1, method=''):
    def outer_wrapper(function):
        @functools.wraps(function)
        def inner_wrapper(*args, **kwargs):
            final_excep = None
            for i in range(times):
                final_excep = None
                try:
                    res = function(*args, **kwargs)
                    return res
                except Exception as e:
                    final_excep = e
                    print(f'error with {method}: {e}')
                    time.sleep(wait * (i/2))
                    pass

            if final_excep is not None:
                return False
        return inner_wrapper

    return outer_wrapper

def resilient_function(func, *args, **kwargs):
    return run_sheet_function(functools.partial(func, *args, **kwargs))

@retry(times=3, wait=3, method='run sheet function')
def run_sheet_function(func):
    return func()


##original function call
df = spread.sheet_to_df(index=0, start_row=2, formula_columns=['Monthly Service']) 
##new call
df = resilient_function(spread.sheet_to_df, index=0, start_row=2, formula_columns=['Monthly Service'])
Другие вопросы по тегам