Python:异常装饰器。如何保留堆栈跟踪 [英] Python: Exception decorator. How to preserve stacktrace
问题描述
然而,当我在包装器中引发自定义异常时,我希望stacktrace指向引发原始WebFault异常的函数。到目前为止,我已经提出了正确的异常(动态解析消息并实例化异常类)。 我的问题:如何保留堆栈跟踪指向引发WebFault异常的原始功能?
从functools导入包裹
def try_except(fn):
def wrapped(* args,** kwargs):
try:
fn(* args, ** kwargs)
除了异常,e:
parser = exceptions.ExceptionParser()
raise_exception = parser.get_raised_exception_class_name(e)
exception = getattr(exceptions,raise_exception)
raise exception(parser.get_message(e))
return wrap(fn)(wrapped)
在Python 2.x中, raise
的一个鲜为人知的功能是可以使用不止一个参数: raise
的三参数形式接受异常类型,异常实例和追溯。您可以使用 sys.exc_info()
获取回溯,该返回异常类型(异常实例和追溯)返回(不巧)。
(将异常类型和异常实例视为两个独立参数的原因是异常类之前的工件)。
所以:
import sys
class MyError(Exception):
pass
def try_except(fn):
def wrapped(* args,** kwargs):
try:
return fn(* args,** kwargs)
除了异常,e:
et,ei,tb = sys.exc_info()
raise MyError,MyError(e),tb
return wrapped
def bottom ):
1/0
@try_except
def middle():
bottom()
def top():
middle()
>>> top()
追溯(最近的最后一次调用):
文件< stdin>,第1行,< module>
文件tmp.py,第24行,顶部
middle()
文件tmp.py,第10行,包装
return fn(* args,* * kwargs)
文件tmp.py,第21行,中间
bottom()
文件tmp.py,第17行,底部
1/0
__main __。MyError:整数除或模数为零
在Python 3中,这改变了一点。在那里,追溯附加到异常实例,而且它们有一个 with_traceback
方法:
raise MyError(e).with_traceback(tb)
另一方面Python 3也有例外链接,这在许多情况下更有意义;要使用它,您只需使用:
从e
中提取MyError(e)$ / code >
I am writing a decorator to apply to a function. It should catch any exception, and then raise a custom exception based on the original exception message. (This is because suds throws a generic WebFault exception, from whose message I parse the exception thrown by the web service and raise a Python exception to mirror it.)
However, when I raise the custom exception in the wrapper, I want the stacktrace to point to the function that raised the original WebFault exception. What I have so far raises the correct exception (it dynamically parses the message and instantiates the exception class). My question: How can I preserve the stacktrace to point to the original function that raised the WebFault exception?
from functools import wraps
def try_except(fn):
def wrapped(*args, **kwargs):
try:
fn(*args, **kwargs)
except Exception, e:
parser = exceptions.ExceptionParser()
raised_exception = parser.get_raised_exception_class_name(e)
exception = getattr(exceptions, raised_exception)
raise exception(parser.get_message(e))
return wraps(fn)(wrapped)
In Python 2.x, a little-known feature of raise
is that it can be used with more than just one argument: the three-argument form of raise
takes the exception type, the exception instance and the traceback. You can get at the traceback with sys.exc_info()
, which returns (not coincidentally) the exception type, the exception instance and the traceback.
(The reason this treats the exception type and the exception instance as two separate arguments is an artifact from the days before exception classes.)
So:
import sys
class MyError(Exception):
pass
def try_except(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception, e:
et, ei, tb = sys.exc_info()
raise MyError, MyError(e), tb
return wrapped
def bottom():
1 / 0
@try_except
def middle():
bottom()
def top():
middle()
>>> top()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tmp.py", line 24, in top
middle()
File "tmp.py", line 10, in wrapped
return fn(*args, **kwargs)
File "tmp.py", line 21, in middle
bottom()
File "tmp.py", line 17, in bottom
1 / 0
__main__.MyError: integer division or modulo by zero
In Python 3, this changed a little. There, the tracebacks are attached to the exception instance instead, and they have a with_traceback
method:
raise MyError(e).with_traceback(tb)
On the other hand Python 3 also has exception chaining, which makes more sense in many cases; to use that, you would just use:
raise MyError(e) from e
这篇关于Python:异常装饰器。如何保留堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!