Re-raise исключение Python и сохранение трассировки стека
Я пытаюсь поймать исключение в потоке и повторно поднять его в основном потоке:
import threading
import sys
class FailingThread(threading.Thread):
def run(self):
try:
raise ValueError('x')
except ValueError:
self.exc_info = sys.exc_info()
failingThread = FailingThread()
failingThread.start()
failingThread.join()
print failingThread.exc_info
raise failingThread.exc_info[1]
В основном это работает и дает следующий результат:
(<type 'exceptions.ValueError'>, ValueError('x',), <traceback object at 0x1004cc320>)
Traceback (most recent call last):
File "test.py", line 16, in <module>
raise failingThread.exc_info[1]
Однако источник исключения указывает на строку 16, где произошел повторный рейз. Исходное исключение исходит из строки 7. Как мне изменить основной поток так, чтобы выход читал:
Traceback (most recent call last):
File "test.py", line 7, in <module>
Ответы
Ответ 1
Вам нужно использовать все три аргумента для повышения:
raise failingThread.exc_info[0], failingThread.exc_info[1], failingThread.exc_info[2]
передача объекта трассировки в качестве третьего аргумента сохраняет стек.
От help('raise')
:
Если присутствует третий объект, а не None
, он должен быть трассировкой объект (см. раздел Иерархия стандартного типа), и это вместо текущего местоположения вместо того, чтобы исключение. Если третий объект присутствует, а не объект трассировки или None
, исключение a TypeError
. трехмерная форма raise
полезна для повторного создания исключения прозрачно в предложении except, но raise
без выражений должно быть предпочтительнее, если бы исключение, подлежащее повторному поднятию, было наиболее недавно активное исключение в текущей области.
В этом конкретном случае вы не можете использовать версию выражения без выражения.
Ответ 2
Этот фрагмент кода работает как в python 2, так и в 3:
1 try:
----> 2 raise KeyError('Default key error message')
3 except KeyError as e:
4 e.args = ('Custom message when get re-raised',) #The comma is not a typo, it there to indicate that we're replacing the tuple that e.args pointing to with another tuple that contain the custom message.
5 raise
Ответ 3
Не могли бы вы написать это примерно так:
try:
raise ValueError('x')
except ValueError as ex:
self.exc_info = ex
а затем использовать stacktrace из исключения?