Python:异常装饰器。如何保留堆栈跟踪 [英] Python: Exception decorator. How to preserve stacktrace

查看:206
本文介绍了Python:异常装饰器。如何保留堆栈跟踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个装饰器来应用于一个功能。它应该捕获任何异常,然后根据原始异常消息引发自定义异常。 (这是因为suds抛出一个通用的WebFault异常,从该消息中我解析了Web服务引发的异常并引发了一个Python异常来反映它。)



然而,当我在包装器中引发自定义异常时,我希望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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆