1

In my Tkinter Python application, I tried to use sys.excepthook to handle uncaught exceptions, but my handler was never called. The stack trace still printed out.

How can I handle uncaught exceptions in a Tkinter application?

Here's a trivial example that shows what I tried:

import Tkinter as tk
import tkMessageBox
import traceback
import sys

class MyApp(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.button_frame = tk.Frame(self)
        self.button_frame.pack(side='top')
        self.button_run = tk.Button(
            self.button_frame, text="Run", command=self.run
        )
        self.button_run.grid(row=0, column=1, sticky='W')

    def run(self):
        tkMessageBox.showinfo('Info', 'The process is running.')
        raise RuntimeError('Tripped.')

def main():
    root = tk.Tk()  # parent widget

    MyApp(root).pack(fill='both', expand=True)

    def handle_exception(exc_type, exc_value, exc_traceback):
        message = ''.join(traceback.format_exception(exc_type,
                                                     exc_value,
                                                     exc_traceback))
        tkMessageBox.showerror('Error', message)

    sys.excepthook = handle_exception

    root.mainloop()  # enter Tk event loop

if __name__ == '__main__':
    main()
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • Possible duplicate of [How can I make silent exceptions louder in tkinter?](https://stackoverflow.com/questions/4770993/how-can-i-make-silent-exceptions-louder-in-tkinter) – Stevoisiak May 10 '18 at 15:27

1 Answers1

8

I stepped through the code after the exception is raised, and found that it gets caught by report_callback_exception(). Some more searching led me to a post that shows how to override report_callback_exception(). Here is my example with the new handler. Don't forget the second line in __init__() where you actually register the handler.

import Tkinter as tk
import tkMessageBox
import traceback

class MyApp(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        parent.report_callback_exception = self.report_callback_exception
        self.parent = parent
        self.button_frame = tk.Frame(self)
        self.button_frame.pack(side='top')
        self.button_run = tk.Button(
            self.button_frame, text="Run", command=self.run
        )
        self.button_run.grid(row=0, column=1, sticky='W')

    def run(self):
        tkMessageBox.showinfo('Info', 'The process is running.')
        raise RuntimeError('Tripped.')

    def report_callback_exception(self, exc_type, exc_value, exc_traceback):
        message = ''.join(traceback.format_exception(exc_type,
                                                     exc_value,
                                                     exc_traceback))
        tkMessageBox.showerror('Error', message)

def main():
    root = tk.Tk()  # parent widget

    MyApp(root).pack(fill='both', expand=True)

    root.mainloop()  # enter Tk event loop

if __name__ == '__main__':
    main()
Community
  • 1
  • 1
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286