有一个被提升的exception
我想跳进那个框架。为了更好地解释我的意思,我写了这个mwe:
假设我有以下代码:
from multiprocessing import Pool
import sys
# Setup debugger
def raiseDebugger(*args):
""" http://code.activestate.com/recipes/65287-automatically-start-the-
debugger-on-an-exception/ """
import traceback, pdb
traceback.print_exception(*args)
pdb.pm()
sys.excepthook = raiseDebugger
# Now start with the question
def faulty(i):
return 1 / i
with Pool() as pool:
pool.map(faulty, range(6))
毫不奇怪导致:
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 119, in worker
result = (True, func(*args, **kwds))
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar
return list(map(*args))
File "test2.py", line 19, in faulty
return 1 / i
ZeroDivisionError: division by zero
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test2.py", line 23, in <module>
pool.map(faulty, range(6))
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 260, in map
return self._map_async(func, iterable, mapstar, chunksize).get()
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 608, in get
raise self._value
ZeroDivisionError: division by zero
> /home/bin/conda/lib/python3.5/multiprocessing/pool.py(608)get()
-> raise self._value
(Pdb)
现在要调试我想要的问题&#34;跳跃&#34;进入最初提出exception
(ZeroDivisionError
)的框架。
self._value
完成self._value.__traceback__
后仍可使用原始例外。
答案 0 :(得分:1)
geom_histogram
(或pm
)调用的调用来自sys.exc_info
的值字段,post_mortem
的默认调用是在post_mortem
上完成的这个价值。但是,如果要访问基础对象,则需要访问其__traceback__
。鉴于此代码示例:
__context__
运行代码。 import pdb
import sys
import traceback
def top():
value = 1
raise Exception('this always fails')
def bottom():
try:
top()
except Exception as bot_ex:
x = {}
return x['nothing']
try:
bottom()
except Exception as main_ex:
pdb.post_mortem()
类似于main_ex
。
self._value
请注意,我们在同一位置有一个新的pdb提示符,这是最初引发异常的位置。如果我们需要更进一步,让我们用> /tmp/foo.py(14)bottom()
-> return x['nothing']
(Pdb) main_ex
KeyError('nothing',)
(Pdb) pdb.post_mortem(main_ex.__traceback__)
> /tmp/foo.py(14)bottom()
-> return x['nothing']
来尝试:
__context__
如果需要,请继续重复,直到达到所需的目标上下文/回溯。
现在对于多处理情况,我不知道会产生这么大的差异,因为这个问题意味着一般性(我如何从异常“跳转”到堆栈框架中?),但事实证明{ {1}}发挥了重要作用。
在Python 3.4中,我们做了一个解决方法,只是将traceback显示为一个字符串;由于回溯实际上有多少东西,如Python跟踪器上的issue 13831中所讨论的那样,传达所有被证明是困难的东西,所以反而做了一个hack来将(Pdb) c
(Pdb) pdb.post_mortem(main_ex.__context__.__traceback__)
> /tmp/foo.py(7)top()
-> raise Exception('this always fails')
属性带入当前异常,但它不是完整的multiprocessing
,因为它只有字符串表示,正如我所怀疑的那样。
无论如何,这是可能发生的事情:
__cause__
因此,在他们弄清楚如何将所有这些状态跨越流程边界之前,这实际上是不可能的。