Python:如何消除库代码中的堆栈追踪?
当我从标准库中遇到运行时异常时,几乎总是我自己代码的问题,而不是库里的问题。有没有办法截断异常的堆栈跟踪,这样就不会显示库包的内部信息呢?
举个例子,我希望得到这样的结果:
Traceback (most recent call last):
File "./lmd3-mkhead.py", line 71, in <module>
main()
File "./lmd3-mkhead.py", line 66, in main
create()
File "./lmd3-mkhead.py", line 41, in create
headver1[depotFile]=rev
TypeError: Data values must be of type string or None.
而不是这样的:
Traceback (most recent call last):
File "./lmd3-mkhead.py", line 71, in <module>
main()
File "./lmd3-mkhead.py", line 66, in main
create()
File "./lmd3-mkhead.py", line 41, in create
headver1[depotFile]=rev
File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 276, in __setitem__
_DeadlockWrap(wrapF) # self.db[key] = value
File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/dbutils.py", line 68, in DeadlockWrap
return function(*_args, **_kwargs)
File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 275, in wrapF
self.db[key] = value
TypeError: Data values must be of type string or None.
更新:添加了一个 答案,感谢Alex的提示。
5 个回答
1
你可能需要用到 Traceback库。这里有一个例子,可能对你有帮助:
import traceback
try:
your_main()
except:
lines = traceback.format_exc()
print lines[:lines.find('File "/usr')]
(当然,如果在库外发生了异常,这个方法就不管用了,而且可能不完全符合你的需求,但这是一种使用Traceback库的方法)
12
Python的标准库里有一个叫做traceback的模块,它可以让你在出现错误时以你喜欢的方式显示错误信息。你可以在try
/except
语句的except
部分使用这个功能,或者在你设置的一个函数中使用这个功能,这个函数叫做sys.excepthook,当错误一直传播到最外层时会被调用;文档中是这么说的:
在交互式会话中,这个过程发生在控制权返回到提示符之前;在Python程序中,这个过程发生在程序退出之前。你可以通过给sys.excepthook赋值一个其他的三参数函数来定制这种顶层异常的处理方式。
这里有一个简单的例子:
>>> import sys
>>> import traceback
>>> def f(n):
... if n<=0: raise ZeroDivisionError
... f(n-1)
...
>>> def excepthook(type, value, tb):
... traceback.print_exception(type, value, tb, 3)
...
>>> sys.excepthook = excepthook
>>> f(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
File "<stdin>", line 3, in f
ZeroDivisionError
如你所见,不需要使用try
/except
,你就可以轻松限制错误信息的显示层级,比如只显示前面三层——尽管我们知道在错误发生时实际上有9层嵌套。
如果你想要的功能比简单限制层级更复杂,那你需要调用traceback.format_exception,这个函数会给你一个包含多行信息的列表,而不是直接打印出来。然后你可以从这个列表中“修剪”掉那些你不想在错误信息中看到的模块的行,最后把剩下的行输出(通常是输出到sys.stderr
,不过随你喜欢!)。
5
感谢Alex的提示,这里是代码:
def trimmedexceptions(type, value, tb, pylibdir=None, lev=None):
"""trim system packages from the exception printout"""
if pylibdir is None:
import traceback, distutils.sysconfig
pylibdir = distutils.sysconfig.get_python_lib(1,1)
nlev = trimmedexceptions(type, value, tb, pylibdir, 0)
traceback.print_exception(type, value, tb, nlev)
else:
fn = tb.tb_frame.f_code.co_filename
if tb.tb_next is None or fn.startswith(pylibdir):
return lev
else:
return trimmedexceptions(type, value, tb.tb_next, pylibdir, lev+1)
import sys
sys.excepthook=trimmedexceptions
# --- test code ---
def f1(): f2()
def f2(): f3()
def f3():
import xmlrpclib
proxy = xmlrpclib.ServerProxy('http://nosuchserver')
proxy.f()
f1()
这段代码会产生这样的堆栈跟踪信息:
Traceback (most recent call last):
File "./tsttraceback.py", line 47, in <module>
f1()
File "./tsttraceback.py", line 40, in f1
def f1(): f2()
File "./tsttraceback.py", line 41, in f2
def f2(): f3()
File "./tsttraceback.py", line 45, in f3
proxy.f()
gaierror: [Errno -2] Name or service not known