tadalendas
tadalendas

Reputation: 1541

Retrieve Python exception object

I have a piece of code that I don't control and while running it raises an error. I'd like to capture the value of exc object inside the exc_func method.

As you can see exc_func raises two exceptions, one of which is handled. What I care about is the value of the exc object, but so far have little luck retrieving it. The value does not exist in exc_traceback object and the exception message is not very helpful.

import traceback
import sys


def exc_func():
    try:
        a = 1
        a.length()
    except Exception as exc:
        exc.with_not_existing()
        

def main():
    try:
        exc_func()
    except Exception as exc:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        tb_walk = traceback.walk_tb(exc_traceback)
        # Need this in order to pickle traceback
        tb_summary = traceback.StackSummary.extract(tb_walk, capture_locals=True)


if __name__ == '__main__':
    main()

EDIT: For instance, the exc object in main is AttributeError("'AttributeError' object has no attribute 'with_not_existing'"). What I really want to see is the exc object inside exc_func. Just to be clear, I need the exc object itself, something like traceback.format_exc() is not helpful in my case, due to the nature of the exception (it's a C lib that raises this exception)

Upvotes: 1

Views: 170

Answers (1)

MisterMiyagi
MisterMiyagi

Reputation: 52169

When an exception is raised during handling another exception, the initial exception is stored as the __context__. It can be extracted when handling the new exception.

try:
    exc_func()
except Exception as exc:
    parent = exc.__context__  # the previously handled exception
    print(type(parent), parent)

Note that an exception handler may also explicitly chain exceptions via __cause__.

Built-in Exceptions

[...]
When raising (or re-raising) an exception in an except or finally clause __context__ is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.

The raise statement

[...]
The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). [...]
A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

Upvotes: 1

Related Questions