Я хочу, чтобы менеджер контекста перехватил исключение, распечатал трассировку стека и затем разрешил продолжить выполнение.
Я хочу знать, смогу ли я сделать это с помощью contextlib contextmanager decorator. Если нет, то как я могу это сделать?
Документация предлагает следующее:
В тот момент, когда генератор дает результат, выполняется блок, вложенный в оператор with. Затем генератор возобновляется после выхода из блока. Если в блоке возникает необработанное исключение, оно повторно вызывается внутри генератора в точке, где произошел выход. Таким образом, вы можете использовать оператор try… кроме… finally, чтобы перехватить ошибку (если она есть) или убедиться, что какая-то очистка произошла. Если исключение захвачено просто для того, чтобы зарегистрировать его или выполнить какое-либо действие (а не полностью его подавить), генератор должен повторно вызвать это исключение.
Итак, я пробую очевидный подход, к которому ведет меня документация:
import contextlib
import logging
@contextlib.contextmanager
def log_error():
try:
yield
except Exception as e:
logging.exception('hit exception')
finally:
print 'done with contextmanager'
def something_inside_django_app():
with log_error():
raise Exception('alan!')
something_inside_django_app()
print 'next block of code'
Это производит вывод
ERROR:root:hit exception
Traceback (most recent call last):
File "exception_test.py", line 8, in log_error
yield
File "exception_test.py", line 17, in something_inside_django_app
raise Exception('alan!')
Exception: alan!
done with contextmanager
next block of code
Это теряет важную информацию о том, откуда возникло исключение. Подумайте, что вы получите, когда вы настроите менеджер контекста на , а не и исключение:
Traceback (most recent call last):
File "exception_test.py", line 20, in <module>
something_inside_django_app()
File "exception_test.py", line 17, in something_inside_django_app
raise Exception('alan!')
Exception: alan!
Да, мне удалось сказать, что исключение было поднято из строки 17, большое спасибо, но предыдущий вызов в строке 20 потерял информацию. Как сделать так, чтобы менеджер контекста дал мне фактический полный стек вызовов, а не его усеченную версию? Напомним, я хочу выполнить два требования:
- имеет менеджер контекста python, подавляющий исключение, возникающее в коде, который он переносит
- распечатать трассировку стека, которая была бы сгенерирована этим кодом, если бы я не использовал менеджер контекста
Если это невозможно сделать с помощью декоратора, тогда я буду использовать другой стиль диспетчера контекста. Если это невозможно сделать с помощью менеджеров контекста, точка, я хотел бы знать, что такое хорошая питоновская альтернатива.