我怎样才能跳过"从异常进入堆栈框架?

时间:2016-09-23 00:26:13

标签: python python-3.x debugging exception

有一个被提升的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;进入最初提出exceptionZeroDivisionError)的框架。

self._value完成self._value.__traceback__后仍可使用原始例外。

1 个答案:

答案 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__

因此,在他们弄清楚如何将所有这些状态跨越流程边界之前,这实际上是不可能的。