I'm working on a mail-sending library, and I want to be able to catch exceptions produced by the senders (SMTP, Google AppEngine, etc.) and wrap them in easily catchable exceptions specific to my library (ConnectionError, MessageSendError, etc.), with the original traceback intact so it can be debugged. What is the best way to do this in Python 2?
Exception wrapping is when you catch an exception, wrap it in a different exception and throw that exception. Here is an example: try{ dao.readPerson(); } catch (SQLException sqlException) { throw new MyException("error text", sqlException); }
Most importantly don't fail silently so don't wrap the exceptions in your own exception and then ignore them. Better to allow them to bubble up and find them in the web server log for example.
In general, when a Python script encounters a situation that it cannot cope with, it raises an exception. An exception is a Python object that represents an error. When a Python script raises an exception, it must either handle the exception immediately otherwise it terminates and quits.
The simplest way would be to reraise with the old trace object. The following example shows this:
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
Check the documentation of the raise statement for details of the three parameters. My example would print:
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
For completeness, in Python 3 you'd use the raise MyException(...) from e
syntax.
Use raise_from
from the future.utils
package.
Relevant example copied below:
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)
Within that package, raise_from
is implemented as follows:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With