[Django]-Python catch previous exception in broad handler

0👍

The good practice is to raise your own exception (here it is APIException) and attach the original exception.

You can take a look at six.raise_from (if you want a Python 2/3 compatible solution):

Raise an exception from a context. On Python 3, this is equivalent to raise exc_value from exc_value_from. On Python 2, which does not support exception chaining, it is equivalent to raise exc_value.

You can also create your own exception class which can do the chaining.

class APIException(Exception):
    def __init__(self, msg, exc_from=None):
        self.exc_from = exc_from
        if exc_from:
            msg += ': raise from {0}'.format(str(exc_from))
        super(APIException, self).__init__(self, msg)

# demo

def do_stuff():
    raise KeyError('bad key')


def main():
    try:
        do_stuff()
    except KeyError as exc:
        raise APIException('error in main', exc)


try:
    main()
except APIException as exc:
    print(str(exc))

Of course, instead of printing/logging your APIException error message you can log your original message:

try:
    main()
except APIException as exc:
    print(str(exc.exc_from))

Edit: Use class hierarchy for exceptions

But, if do_stuff() is part of your API, it’s a better practice to do the exception handling inside this function and throw your own exception which can inherit APIException.

class APIException(Exception):
    pass


class BadStuffError(APIException):
    pass


def do_stuff():
    try:
        # ...
        raise KeyError('bad key')
    except KeyError as exc:
        raise BadStuffError('bad stuff: ' + exc.args[0])



def main():
    do_stuff()


try:
    main()
except APIException as exc:
    print(str(exc))

This solution is the best, IMO.

0👍

Since you are using Python 3, you can simply raise the APIException:

try:
    do_stuff()
except KeyError as exc:
    raise APIException() from exc

Then in your exception handler, if exc is the APIException, you can access the original exception with exc.__context__.

def exception_handler(exc):
    logger.log(exc.__context__)
    return Response({"message": "try again sam"}, status_code=400)

The from exc is not actually needed to be able to access __context__, but it makes it clear that the KeyError was converted to APIException, rather than APIException being raised during the handling of KeyError.
See the exception docs for more info.

Leave a comment