[英]How to limit python traceback to specific files
我寫了很多使用外部庫的Python代碼。 我經常寫一個bug,當我運行代碼時,我會在Python控制台中獲得一個很長的回溯。 99.999999%的時間是由於我的代碼中的編碼錯誤,而不是因為包中的錯誤。 但是跟蹤一直到程序包代碼中的錯誤行,要么需要大量滾動回溯來查找我編寫的代碼,要么回溯是如此深入到我自己的代碼所沒有的包中。甚至出現在追溯中。
有沒有辦法“黑盒子”包裝代碼,或以某種方式只顯示我的代碼中的追溯線? 我希望能夠向系統指定我想要追溯的目錄或文件。
為了打印自己的堆棧跟蹤,您需要自己處理所有未處理的異常; 這就是sys.excepthook
如何變得方便。
此函數的簽名是sys.excepthook(type, value, traceback)
,其作用是:
此函數打印出
sys.stderr
的給定回溯和異常。
因此,只要您可以使用追溯並且僅提取您關心的部分,您應該沒問題。 測試框架經常這樣做; 它們具有自定義assert
函數,這些函數通常不會出現在回溯中,換句話說,它們會跳過屬於測試框架的幀。 此外,在這些情況下,測試通常也由測試框架啟動。
最終得到一個如下所示的回溯:
[ custom assert code ]
+ ... [ code under test ] ...
+ [ test runner code ]
您可以在代碼中添加全局:
__mycode = True
然后識別幀:
def is_mycode(tb):
globals = tb.tb_frame.f_globals
return globals.has_key('__mycode')
length
提取length
幀
def mycode_traceback_levels(tb): length = 0 while tb and is_mycode(tb): tb = tb.tb_next length += 1 return length
def handle_exception(type, value, tb):
# 1. skip custom assert code, e.g.
# while tb and is_custom_assert_code(tb):
# tb = tb.tb_next
# 2. only display your code
length = mycode_traceback_levels(tb)
print ''.join(traceback.format_exception(type, value, tb, length))
安裝處理程序:
sys.excepthook = handle_exception
您可以調整length
以添加一個或多個級別,如果您仍然需要有關失敗在您自己的代碼之外的位置的一些信息。
正如其他人建議的那樣,你可以使用sys.excepthook
:
此函數打印出sys.stderr的給定回溯和異常。
當引發異常並且未被捕獲時,解釋器使用三個參數調用sys.excepthook ,異常類,異常實例和回溯對象。 在交互式會話中,這發生在控制返回到提示之前; 在Python程序中,這發生在程序退出之前。 可以通過為sys.excepthook分配另一個三參數函數來自定義這種頂級異常的處理 。
(強調我的)
可以根據指定的目錄過濾extract_tb
(或traceback
模塊中的類似函數)提取的traceback
。
兩個可以提供幫助的功能:
from os.path import join, abspath
from traceback import extract_tb, format_list, format_exception_only
def spotlight(*show):
''' Return a function to be set as new sys.excepthook.
It will SHOW traceback entries for files from these directories. '''
show = tuple(join(abspath(p), '') for p in show)
def _check_file(name):
return name and name.startswith(show)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
def shadow(*hide):
''' Return a function to be set as new sys.excepthook.
It will HIDE traceback entries for files from these directories. '''
hide = tuple(join(abspath(p), '') for p in hide)
def _check_file(name):
return name and not name.startswith(hide)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
它們都使用traceback.extract_tb
。 它返回“從traceback對象中提取的”預處理“堆棧跟蹤條目”列表 ; 所有這些都是traceback.FrameSummary
(一個命名的元組)的實例。 每個traceback.FrameSummary
對象都有一個filename
字段,用於存儲相應文件的絕對路徑。 我們檢查它是否以作為單獨函數參數提供的任何目錄路徑開始,以確定我們是否需要排除該條目(或保留它)。
這是一個例子 :
標准庫中的enum
模塊不允許重用密鑰,
import enum
enum.Enum('Faulty', 'a a', module=__name__)
產量
Traceback (most recent call last):
File "/home/vaultah/so/shadows/main.py", line 23, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
File "/home/vaultah/cpython/Lib/enum.py", line 243, in __call__
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
File "/home/vaultah/cpython/Lib/enum.py", line 342, in _create_
classdict[member_name] = member_value
File "/home/vaultah/cpython/Lib/enum.py", line 72, in __setitem__
raise TypeError('Attempted to reuse key: %r' % key)
TypeError: Attempted to reuse key: 'a'
我們可以將堆棧跟蹤條目限制為我們的代碼(在/home/vaultah/so/shadows/main.py中 )。
import sys, enum
sys.excepthook = spotlight('/home/vaultah/so/shadows')
enum.Enum('Faulty', 'a a', module=__name__)
和
import sys, enum
sys.excepthook = shadow('/home/vaultah/cpython/Lib')
enum.Enum('Faulty', 'a a', module=__name__)
給出相同的結果:
File "/home/vaultah/so/shadows/main.py", line 22, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
TypeError: Attempted to reuse key: 'a'
有一種方法可以排除所有站點目錄(安裝第三方軟件包的位置 - 請參閱site.getsitepackages
)
import sys, site, jinja2
sys.excepthook = shadow(*site.getsitepackages())
jinja2.Template('{%}')
# jinja2.exceptions.TemplateSyntaxError: unexpected '}'
# Generates ~30 lines, but will only display 4
注意:不要忘記從SYS .__ excepthook__恢復sys.excepthook。 不幸的是,您將無法使用上下文管理器“修補”它。
traceback.extract_tb(tb)將以格式(file,line_no,type,error_statement)返回錯誤幀元組,您可以使用它來格式化回溯。 另請參閱https://pymotw.com/2/sys/exceptions.html
import sys
import traceback
def handle_exception(ex_type, ex_info, tb):
print ex_type, ex_info, traceback.extract_tb(tb)
sys.excepthook = handle_exception
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.