1

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)

10
  • You could put the exception in a list, return that, and then read it from there. Commented Mar 10, 2021 at 14:01
  • Also, if you want the main function to read the exception, then you shouldn't use try and except in exe_func. Just let it raise, and main will handle the exception Commented Mar 10, 2021 at 14:02
  • Can you provide a minimal reproducible example? I'm not sure I understand what you mean by I'd like to capture the value of exc object inside the exc_func method and I can't run this code. Do you mean exc.args? Commented Mar 10, 2021 at 14:05
  • @Tomerikoo edited the question. Let me know if that makes sense. Commented Mar 10, 2021 at 14:28
  • "it's a C lib that raises this exception" In that case showing Python code is not helpful. Does the intermediate exception even exist as a Python object? Commented Mar 10, 2021 at 14:36

1 Answer 1

1

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:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.