J-b*_*bob 29 python debugging traceback
我写了很多使用外部库的Python代码.我经常写一个bug,当我运行代码时,我会在Python控制台中获得一个很长的回溯.99.999999%的时间是由于我的代码中的编码错误,而不是因为包中的错误.但是回溯一直到程序包代码中的错误行,要么需要大量滚动回溯来查找我编写的代码,要么回溯是如此深入到我自己的代码所没有的包中.甚至出现在追溯中.
有没有办法"黑盒子"包装代码,或以某种方式只显示我的代码中的追溯线?我希望能够向系统指定我想要追溯的目录或文件.
dno*_*zay 15
为了打印自己的堆栈跟踪,您需要自己处理所有未处理的异常; 这就是sys.excepthook
方便的方式.
该功能的签名是sys.excepthook(type, value, traceback)
,它的工作是:
此函数打印出给定的回溯和异常
sys.stderr
.
因此,只要您可以使用追溯并且仅提取您关心的部分,您应该没问题.测试框架经常这样做; 它们具有assert
通常不会出现在回溯中的自定义函数,换句话说,它们会跳过属于测试框架的框架.此外,在这些情况下,测试通常也由测试框架启动.
最终得到一个如下所示的回溯:
[ custom assert code ]
+ ... [ code under test ] ...
+[ test runner code ]
您可以在代码中添加全局:
__mycode = True
Run Code Online (Sandbox Code Playgroud)
然后识别帧:
def is_mycode(tb):
globals = tb.tb_frame.f_globals
return globals.has_key('__mycode')
Run Code Online (Sandbox Code Playgroud)
length
提取length
帧
def mycode_traceback_levels(tb):
length = 0
while tb and is_mycode(tb):
tb = tb.tb_next
length += 1
return length
Run Code Online (Sandbox Code Playgroud)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))
Run Code Online (Sandbox Code Playgroud)
安装处理程序:
sys.excepthook = handle_exception
Run Code Online (Sandbox Code Playgroud)
length
如果您仍需要有关故障在您自己的代码之外的位置的信息,则可以调整以添加一个或多个级别.
另见https://gist.github.com/dnozay/b599a96dc2d8c69b84c6
正如其他人建议的那样,您可以使用sys.excepthook
:
此函数将给定的回溯和异常打印到sys.stderr。
当异常被引发并未被捕获时,解释器使用三个参数调用sys.excepthook,异常类、异常实例和回溯对象。在交互式会话中,这发生在控制返回到提示之前;在 Python 程序中,这发生在程序退出之前。可以通过将另一个三参数函数分配给sys.excepthook 来自定义此类顶级异常的处理。
(强调我的)
可以根据指定的目录过滤由extract_tb
(或从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
Run Code Online (Sandbox Code Playgroud)
他们都使用traceback.extract_tb
. 它返回“从回溯对象中提取的“预处理”堆栈跟踪条目列表”;它们都是traceback.FrameSummary
(命名元组)的实例。每个traceback.FrameSummary
对象都有一个filename
字段,用于存储相应文件的绝对路径。我们检查它是否以作为单独函数参数提供的任何目录路径开头,以确定我们是否需要排除该条目(或保留它)。
这是一个例子:
enum
标准库中的模块不允许重复使用密钥,
import enum
enum.Enum('Faulty', 'a a', module=__name__)
Run Code Online (Sandbox Code Playgroud)
产量
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
Run Code Online (Sandbox Code Playgroud)
我们可以将堆栈跟踪条目限制在我们的代码中(在/home/vaultah/so/shadows/main.py 中)。
import sys, enum
sys.excepthook = spotlight('/home/vaultah/so/shadows')
enum.Enum('Faulty', 'a a', module=__name__)
Run Code Online (Sandbox Code Playgroud)
和
import sys, enum
sys.excepthook = shadow('/home/vaultah/cpython/Lib')
enum.Enum('Faulty', 'a a', module=__name__)
Run Code Online (Sandbox Code Playgroud)
给出相同的结果:
import enum
enum.Enum('Faulty', 'a a', module=__name__)
Run Code Online (Sandbox Code Playgroud)
有一种方法可以排除所有站点目录(安装了 3rd 方软件包的地方 - 请参阅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
Run Code Online (Sandbox Code Playgroud)
注意:不要忘了恢复sys.excepthook从SYS .__ excepthook__。不幸的是,您将无法使用上下文管理器“修补恢复”它。
归档时间: |
|
查看次数: |
2230 次 |
最近记录: |