Мы используем библиотеку, которая представляет общее состояние сбоя (ресурс не найден), вызывая исключение (SnafuException
). Мы склонны обрабатывать это с помощью шаблона, который немного варьируется от использования к использованию:
try:
foo()
except SnafuException as se:
log.exception("message", exc_info=se)
raise FubarException("message")
Как я понимаю, установка exc_info = se не обязательна для log.exception, но эти сообщения может понизиться.
Это чисто и хорошо, но я сейчас нахожусь в ситуации, когда я хочу, чтобы вызывающая сторона сказала конкретной функции, как обрабатывать исключение.
def utility(data: Data,
handler: Callable[[SnafuException], Exception] = default_handler):
try:
work_in_progress = foo(data)
except SnafuException as se:
raise handler(se)
return finish(work_in_progress)
Проблема в написании default_handler
; ему нужно вернуть исключение , и я бы хотел, чтобы это возвращенное исключение имело в качестве родителя (контекст или причина) аргумент se
. Учитывая характер работы (мы - большая группа из 1041 человек, и есть другие команды, которые могут работать в тех же репозиториях, которыми мы обычно управляем), я хотел бы получить решение, которое где-то задокументировано.
Как мне написать return FubarException("message", cause=se)
?
Некоторые параметры могут быть в порядке, но я не доволен:
- Повышение изнутри обработчика. Это затруднит передачу лямбды в качестве обработчика.
- Назначение контекста вне обработчика. Это, вероятно, будет работать нормально, но мне кажется, что назначение контекста является частью работы обработчика, поэтому это должно происходить внутри обработчика.
- Буквально присваивая
handler_return_value.__cause__ = se
внутри обработчика. Это задокументировано в PEP 3134 , так что это хорошо. Но он использует атрибут protected / magi c, а PEP - с 2005 года, поэтому, если это «правильный» способ сделать это, я бы ожидал, что он уже задокументирован в другом месте. - Перемещение
try: ... except: ...
внутри функции-обработчика, которая будет принимать функцию "действия" foo
в качестве аргумента. Это, безусловно, позволило бы свести рассматриваемый паттерн настолько полно, насколько это возможно, но я боюсь, что он запутает основной поток выполнения, не будет достаточно гибким для использования во многих случаях и / или потребует большого количества лямбда-выражений.
Любой совет?