在Python中包装异常

问题描述 投票:25回答:3

我正在处理一个邮件发送库,我希望能够捕获发件人(SMTP,Google AppEngine等)产生的异常,并将它们包含在特定于我的库(ConnectionError,MessageSendError等)的容易捕获的异常中。 。),原始回溯完好无损,因此可以进行调试。在Python 2中执行此操作的最佳方法是什么?

python exception
3个回答
26
投票

最简单的方法是使用旧的跟踪对象重新加载。以下示例显示了这一点:

import sys

def a():
    def b():
        raise AssertionError("1")
    b()

try:
    a()
except AssertionError: # some specific exception you want to wrap
    trace = sys.exc_info()[2]
    raise Exception("error description"), None, trace

有关这三个参数的详细信息,请查看raise statement的文档。我的例子将打印:

Traceback (most recent call last):
  File "C:\...\test.py", line 9, in <module>
    a()
  File "C:\...\test.py", line 6, in a
    b()
  File "C:\...\test.py", line 5, in b
    raise AssertionError("1")
Exception: error description

为了完整起见,在Python 3中你将使用raise MyException(...) from e syntax


2
投票

这个答案可能有点迟了,但你可以将函数包装在python decorator中。

这是一个简单的cheatsheet如何不同的装饰。

以下是一些如何执行此操作的示例代码。只需更改decorator即可以您需要的不同方式捕获不同的错误。

def decorator(wrapped_function):
    def _wrapper(*args, **kwargs):
        try:
            # do something before the function call
            result = wrapped_function(*args, **kwargs)
            # do something after the function call
        except TypeError:
            print("TypeError")
        except IndexError:
            print("IndexError")
        # return result
    return _wrapper


@decorator
def type_error():
    return 1 / 'a'

@decorator
def index_error():
    return ['foo', 'bar'][5]


type_error()
index_error()

1
投票

使用raise_fromfuture.utils package

相关示例复制如下:

from future.utils import raise_from

class FileDatabase:
    def __init__(self, filename):
        try:
            self.file = open(filename)
        except IOError as exc:
            raise_from(DatabaseError('failed to open'), exc)

在该软件包中,raise_from实现如下:

def raise_from(exc, cause):
    """
    Equivalent to:

        raise EXCEPTION from CAUSE

    on Python 3. (See PEP 3134).
    """
    # Is either arg an exception class (e.g. IndexError) rather than
    # instance (e.g. IndexError('my message here')? If so, pass the
    # name of the class undisturbed through to "raise ... from ...".
    if isinstance(exc, type) and issubclass(exc, Exception):
        e = exc()
        # exc = exc.__name__
        # execstr = "e = " + _repr_strip(exc) + "()"
        # myglobals, mylocals = _get_caller_globals_and_locals()
        # exec(execstr, myglobals, mylocals)
    else:
        e = exc
    e.__suppress_context__ = False
    if isinstance(cause, type) and issubclass(cause, Exception):
        e.__cause__ = cause()
        e.__suppress_context__ = True
    elif cause is None:
        e.__cause__ = None
        e.__suppress_context__ = True
    elif isinstance(cause, BaseException):
        e.__cause__ = cause
        e.__suppress_context__ = True
    else:
        raise TypeError("exception causes must derive from BaseException")
    e.__context__ = sys.exc_info()[1]
    raise e
© www.soinside.com 2019 - 2024. All rights reserved.