1

My understanding is that: Normally, when an error happens, it's thrown down through all the calling functions, and then displayed in the console. Now there's some packages that do their own error handling, especially GUI related packages often don't show errors at all but just continue excecution.

How can we override such behaviour in general? When I write GUI functions, I would like to see the errors! I found this post where it's explained how to do it for the case of Tkinter. How can this be done in Matplotlib?

Example code:

import matplotlib.pyplot as plt

def onclick(event):
    print(event.x, event.y)
    raise ValueError('SomeError') # this error is thrown but isn't displayed

fig = plt.figure(5)
fig.clf()

try: # if figure was open before, try to disconnect the button
    fig.canvas.mpl_disconnect(cid_button)
except:
    pass  
cid_button = fig.canvas.mpl_connect('button_press_event', onclick)
Community
  • 1
  • 1
poppie
  • 549
  • 5
  • 14

1 Answers1

1

Indeed, when the python interpreter encounters an exception that is never caught, it will print a so-called traceback to stdout before exciting. However, GUI packages usually catch and swallow all exceptions, in order to prevent the python interpreter from exciting. You would like to display that traceback somewhere, but in case of GUI applications, you will have to decide where to show that traceback. The standard library has a module that helps you working with such traceback, aptly named traceback. Then, you will have to catch the exception before the GUI toolkit does it. I do not know a general way to insert a callback error handler, but you can manually add error handling to each of your callbacks. The best way to do this is to write a function decorator that you then apply to your callback.

import traceback, functools

def print_errors_to_stdout(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kw):
        try:
            return fun(*args,**kw)
        except Exception:
            traceback.print_exc()
            raise
    return wrapper

@print_errors_to_stdout
def onclick(event):
    print(event.x, event.y)
    raise ValueError('SomeError')

The decorator print_errors_to_stdout takes a function and returns a new function that embeds the original function in a try ... except block and in case of an exception prints the traceback to stdout with the help of traceback.print_exc(). (The wrapper itself is decorated with functools.wraps such that the generated wrapper function, among other things, keeps the docstring of the original function). If you would like to show the traceback somewhere else traceback.format_exc() would give you a string that you could then show/store somwhere. The decorator also reraises the exception, such that the GUI toolkit still gets a chance to take it's own actions, typically just swallowing the exception.

burnpanck
  • 1,955
  • 1
  • 12
  • 36