Handle the exception raised in traceback.py when suggest

Abstract

When an Exception diffuse, the module traceback will try to format the exception text and print it. For some exception type, it will try to give the suggestion. However, sometimes it doesn’t seem to be going well: an new exception raised when suggest.

This idea is to give a new way to deal with it.

Current

In TracebackException, the exception become the text. The current initialization order is first add the __notes__ then suggest. It means that using add_note to the Exception in suggesting is useless. If we change the turn of the initialization, it will work.

Change

We can easily change the turn about it:

        try:
            self.__notes__ = getattr(exc_value, '__notes__', None)
        except Exception as e:
            self.__notes__ = [
                f'Ignored error getting __notes__: {_safe_string(e, '__notes__', repr)}']

Move to the above of the code below:

        if lookup_lines:
            self._load_lines()

Handle new exception

When TracebackException calls _compute_suggestion_error, if there is new exception raised from it, it will has the __context__ or __cause__ which is the original exception. So we need to remove it from the new exception:

def _remove_exc(exc, original_exc, _seen=None):
    if _seen is None:
        _seen = set()
    if not exc or id(exc) in _seen:
        return
    _seen.add(id(exc))
    if exc.__context__:
        if exc.__context__ is original_exc:
            exc.__context__ = None
        else:
            _remove_exc(exc.__context__, original_exc, _seen)
    if exc.__cause__:
        if exc.__cause__ is original_exc:
            exc.__cause__ = None
        else:
            _remove_exc(exc.__cause__, original_exc, _seen)

This function is to ensure that we can handle the new exception cleanly.

Then, we can add the note about the new exception in original exception:

original_exc_value.add_note("Exception ignored in ...")

Due to that now there is an exception that needs to be handled, all of the new exception should change to warning.

We can create a new TracebackException for the new exception. If it also raise an exception, we can add the message: “<handle error failed>”. The message can be more detailed, for example, which module and the traceback information.

Specially, if there is an exception which means that the design of the function or method violates its semantics, we can specifically do with it.