Поймать исключение в ContextManager? - PullRequest
0 голосов
/ 30 октября 2018

Можно ли перехватить исключение в менеджере контекста?

Справочная информация: метод get_data_from_remote_system() подключается к удаленной системе каждые пять минут и получает данные.

Иногда сеть не работает.

Я хочу подавить сообщение об исключении на 30 минут. Через 30 минут я хочу увидеть исключение.

Я не хочу ловить все исключения. Лишь некоторые. В этом случае socket.timeout.

Есть ли способ написать менеджер контактов, который реализует это, и в результате использование этого менеджера контекста выглядит следующим образом?

with suppress_exception(exceptions=[socket.timeout], minutes=30):
    get_data_from_remote_system()

1 Ответ

0 голосов
/ 30 октября 2018

Да, я не знал, что если вы вернете True в __exit__(), то исключение не будет возбуждено.

Теперь suppress_exception() контекстный менеджер прост:

class suppress_exception(object):
    def __init__(self, exceptions_to_catch, minutes=30):
        self.exceptions_to_catch = exceptions_to_catch
        self.timedelta = datetime.timedelta(minutes=minutes)
        code = sys._getframe().f_back.f_code
        self.cache_key = 'suppress_exception_' + code.co_filename + str(sys._getframe().f_back.f_lineno)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        datetime_of_first_failure = cache.get(self.cache_key)
        now = datetime.datetime.now()
        if not type:
            cache.delete(self.cache_key)
            if datetime_of_first_failure:
                logging.info('Fine again. First failure was %s. Duration (first failure until ok): %s' % (
                    datetime_of_first_failure, now - datetime_of_first_failure))
            return
        if not issubclass(type, self.exceptions_to_catch):
            # Thils will raise an exception
            return
        if not datetime_of_first_failure:
            cache.set(self.cache_key, now)
            datetime_of_first_failure = now
        log_method = logging.warn
        if datetime_of_first_failure + self.timedelta > now:
            log_method = logging.info
        log_method('%s %s (datetime_of_first_failure=%s)' % (type.__name__, value, datetime_of_first_failure))
        return True
...