[英]How can I "jump" into stackframe from 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)
現在要調試問題,我想“跳”到最初引發exception
的框架( ZeroDivisionError
)。
原始異常在self._value
下仍然可用self._value.__traceback__
完成。
呼叫pm
(或post_mortem
)調用是從價值領域sys.exc_info
,並默認調用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
。
> /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']
請注意,我們在同一位置有一個新的 pdb 提示,這是最初引發異常的地方。 如果我們需要更進一步,讓我們用__context__
嘗試一下:
(Pdb) c
(Pdb) pdb.post_mortem(main_ex.__context__.__traceback__)
> /tmp/foo.py(7)top()
-> raise Exception('this always fails')
如果需要,請繼續重復,直到到達所需的目標上下文/回溯。
現在對於多處理情況,我不知道會產生如此大的差異,因為這個問題暗示了一些一般性的東西(如何從異常“跳轉”到堆棧幀?),但事實證明, multiprocessing
的細節使所有的區別。
在 Python 3.4 中,一種解決方法是將回溯顯示為字符串; 由於回溯實際上有多少內容,如 Python 跟蹤器上的問題 13831 中所討論的那樣,傳達所有被證明是困難的,因此進行了黑客攻擊以將__cause__
屬性帶入當前異常,但它不是完整的__traceback__
因為它只有字符串表示,正如我所懷疑的那樣。
無論如何,這就是會發生的事情:
(Pdb) !import pdb
(Pdb) !self._value.__cause__
RemoteTraceback('\n"""\nTraceback (most recent call last):...',)
(Pdb) !type(self._value.__cause__)
<class 'multiprocessing.pool.RemoteTraceback'>
(Pdb) !self._value.__cause__.__traceback__
(Pdb) !self._value.__cause__.__context__
所以這實際上是不可能的,除非他們弄清楚如何跨越流程邊界使所有這些狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.