Повторно вызвать исключение Python и сохранить трассировку стека - PullRequest
52 голосов
/ 06 января 2012

Я пытаюсь перехватить исключение в потоке и повторно вызвать его в основном потоке:

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>

Ответы [ 3 ]

51 голосов
/ 06 января 2012

В Python 2 вам нужно использовать все три аргумента для поднятия:

raise failingThread.exc_info[0], failingThread.exc_info[1], failingThread.exc_info[2]

Передача объекта трассировки в качестве третьего аргумента сохраняет стек.

С help('raise'):

Если присутствует третий объект, а не None, это должно быть отслеживание объект (см. раздел Стандартная иерархия типов ), и это заменить вместо текущего местоположения в качестве места, где исключение произошло. Если третий объект присутствует, а не объект трассировки или None, исключение TypeError. форма с тремя выражениями raise полезна для повторного вызова исключения прозрачно в предложении кроме, но raise без выражений должно быть предпочтительным, если исключение для повторного возбуждения было наиболее недавно активное исключение в текущей области.

В данном конкретном случае вы не можете использовать версию без выражения.

Для Python 3 (согласно комментариям):

raise failingThread.exc_info[1].with_traceback(failingThread.exc_info[2])

или вы можете просто связать исключения, используя raise ... from ..., но это вызывает цепочечное исключение с исходным контекстом, присоединенным в атрибуте причиной , и это может или не может быть тем, что вы хотите.

1 голос
/ 14 сентября 2016

Этот фрагмент кода работает в 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's there to indicate that we're replacing the tuple that e.args pointing to with another tuple that contain the custom message.
      5     raise
0 голосов
/ 06 января 2012

Не могли бы вы написать это примерно так:

try:
    raise ValueError('x')
except ValueError as ex:
    self.exc_info = ex

и затем использовать трассировку стека из исключения?

...