вложение цикла повтора в попытку кроме блочного API Python

У меня есть следующий блок try except, который мне подходит:

try:
    r = requests.post(endpoint,data=json.dumps(report_params),headers=headers)
    r.raise_for_status()
except requests.exceptions.HTTPError as errhttp:
    print ("Http Error:",errhttp)
    mbody = "The process encountered the following HTTP error: " + str(errhttp)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.ConnectionError as errconn:
    print ("Error Connecting:",errconn)
    mbody = "The process encountered the following connection error: " + str(errconn)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.Timeout as errtimeout:
    print ("Timeout Error:",errtimeout)
    mbody = "The process timed out after 3 tries and gave the error: " + str(errtimeout)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.RequestException as err:
    print ("No idea what the hell happened",err)
    mbody = "The process encountered the following unexpected error: " + str(err)
    sendmail(fromaddr, toaddr, msubject, mbody)

Я хотел бы добавить цикл повторных попыток или функцию, которая повторяет 3 раза при ошибке подключения или ошибке тайм-аута

Я нашел кое-что на SO, что должно работать:

tries = 3
for i in range(tries):
    try:
        do_the_thing()
    except KeyError as e:
        if i < tries - 1: # i is zero indexed
            continue
        else:
            raise
    break

Я все еще учусь пробовать, кроме блоков, и поэтому не очень хорошо в них разбираюсь. Как я мог поместить что-то вроде этого цикла в блок выше, чтобы он выглядел так:

try:
    r = requests.post(endpoint,data=json.dumps(report_params),headers=headers)
    r.raise_for_status()
except requests.exceptions.HTTPError as errhttp:
    print ("Http Error:",errhttp)
    mbody = "The process encountered the following HTTP error: " + str(errhttp)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.ConnectionError as errconn:

#### RETRY 3 TIMES AND IF SUCCESSFUL, CONTINUE TO NEXT EXCEPT STATEMENT.  IF UNSUCCESSFUL, SEND THE EMAIL

    print ("Error Connecting:",errconn)
    mbody = "The process failed to connect after 3 tries and gave the following error: " + str(errconn)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.Timeout as errtimeout:

#### RETRY 3 TIMES AND IF SUCCESSFUL, CONTINUE TO NEXT EXCEPT STATEMENT.  IF UNSUCCESSFUL, SEND THE EMAIL

    print ("Timeout Error:",errtimeout)
    mbody = "The process timed out after 3 tries and gave the error: " + str(errtimeout)
    sendmail(fromaddr, toaddr, msubject, mbody)
except requests.exceptions.RequestException as err:
    print ("No idea what the hell happened",err)
    mbody = "The process encountered the following unexpected error: " + str(err)
    sendmail(fromaddr, toaddr, msubject, mbody)

Спасибо!


person zabada    schedule 05.05.2021    source источник
comment
Вы хотите повторить вызов requests.post(endpoint,... три раза?   -  person wwii    schedule 05.05.2021
comment
да! извините за то, что не прояснил это.   -  person zabada    schedule 05.05.2021
comment
Является ли Python: трижды попробуйте выполнить функцию, пока все не выйдут из строя что вы пытаетесь сделать?   -  person wwii    schedule 05.05.2021
comment
Я пытаюсь сделать это с помощью базового Python. поскольку я не знаю, установлены ли на наших серверах некоторые из этих пакетов.   -  person zabada    schedule 05.05.2021
comment
В принятом ответе используется functools, который является базовым python. Но отражает ли эти вопросы и ответы суть того, что вам нужно?   -  person wwii    schedule 05.05.2021
comment
Я считаю, что это так, глядя на это, но я никогда не использовал обертки и не знаю, как их вкладывать. вот мой главный вопрос - как вложить цикл и продолжить его в случае успеха.   -  person zabada    schedule 05.05.2021
comment
Позвольте нам продолжить это обсуждение в чате.   -  person zabada    schedule 05.05.2021


Ответы (1)


Для ConnectionError и Timeout оберните try / except в цикл while и отслеживайте количество попыток в предложении except. вернуть результат в случае успеха или повторно вызвать исключение, если предел достигнут. Поместите все это в функцию.

def retry(max_tries=3):
    n = 0
    while True:
        try:
            r = requests.post(endpoint,data=json.dumps(report_params),headers=headers)
            r.raise_for_status()
            return r
        except (ConnectionError,Timeout) as err:
            n += 1
            if n < max_tries:
                continue
            raise 

Чтобы использовать его, вызовите функцию в блоке try / except. В предложении except создавайте сообщения в зависимости от типа возникшего исключения.

try:
    r = retry()
except (HTTPError,RequestException,ConnectionError,Timeout) as err:
    print(err)
    # craft a message based on type of error:
    if isinstance(err,ConnectionError):
        # msg = ...
        pass
    elif isinstance(err,Timeout):
        # msg = ...
        pass
    elif isinstance(err,HTTPError):
        # msg = ...
        pass
    if isinstance(err,RequestException):
        # msg = ...
        pass

Или вы можете захотеть поместить всю обработку сообщения в функцию.

class Special(Exception):
    pass

def retry(max_tries=3):
    n = 0
    msg = ''
    while True:
        try:
            r = requests.post(endpoint,data=json.dumps(report_params),headers=headers)
            r.raise_for_status()
            return r
        except (ConnectionError,Timeout) as err:
            # three tries
            n += 1
            if n < max_tries:
                continue
            # craft a message based on type of error:
            if isinstance(err,ConnectionError):
                msg = f'{type(err)} occurred: {str(err)}'
                pass
            elif isinstance(err,Timeout):
                # msg = ...
                pass
            raise
        except (HTTPError,RequestException) as err:
            # craft a message based on type of error:
            if isinstance(err,HTTPError):
                # msg = ...
                pass
            if isinstance(err,RequestException):
                # msg = ...
                pass
        finally:
            raise Special(msg)
    

Упрощение использования

try:
    r = retry()
except Special as err:
    print(err.args)
    # send email with err.args

Идеи, заимствованные из:
есть ли питонический способ попробовать что-то максимальное количество раз?
Функция повтора в Python
Python: трижды попробуйте выполнить функцию, пока все не завершатся.

person wwii    schedule 05.05.2021