Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make silent exceptions louder in tkinter?

Tags:

If I run the following code from a terminal, I get a helpful error message in the terminal:

import Tkinter as tk  master = tk.Tk()  def callback():     raise UserWarning("Exception!")  b = tk.Button(master, text="This will raise an exception", command=callback) b.pack()  tk.mainloop() 

However, if I run it without a terminal (say, by double-clicking an icon), the error message is suppressed.

In my real, more complicated Tkinter application, I like that the GUI is a little crash-resistant. I don't like that my users have a hard time giving me useful feedback to fix the resulting unexpected behavior.

How should I handle this? Is there a standard way to expose tracebacks or stderror or whatnot in a Tkinter application? I'm looking for something more elegant than putting try/except everywhere.

EDIT: Jochen Ritzel gave an excellent answer below that pops up a warning box, and mentioned attaching it to a class. Just to make this explicit:

import Tkinter as tk import traceback, tkMessageBox  class App:     def __init__(self, master):         master.report_callback_exception = self.report_callback_exception         self.frame = tk.Frame(master)         self.frame.pack()         b = tk.Button(             self.frame, text="This will cause an exception",             command=self.cause_exception)         b.pack()      def cause_exception(self):         a = []         a.a = 0 #A traceback makes this easy to catch and fix      def report_callback_exception(self, *args):         err = traceback.format_exception(*args)         tkMessageBox.showerror('Exception', err)  root = tk.Tk() app = App(root) root.mainloop() 

My remaining confusion: Jochen mentions the possibility of having different exception reporting functions in different frames. I don't yet see how to do that. Is this obvious?

like image 991
Andrew Avatar asked Jan 22 '11 22:01

Andrew


2 Answers

There is report_callback_exception to do this:

import traceback import tkMessageBox  # You would normally put that on the App class def show_error(self, *args):     err = traceback.format_exception(*args)     tkMessageBox.showerror('Exception',err) # but this works too tk.Tk.report_callback_exception = show_error 

If you didn't import Tkinter as tk, then do

Tkinter.Tk.report_callback_exception = show_error 
like image 158
Jochen Ritzel Avatar answered Oct 11 '22 11:10

Jochen Ritzel


First a followup: Just today, a patch on the CPython tracker for the tkinter.Tk.report_callback_exception docstring made it clear that Jochen's solution is intended. The patch also (and primarily) stopped tk from crashing on callback exceptions when run under pythonw on Windows.

Second: here is a bare-bones beginning of a solution to making stderr function with no console (this should really be a separate SO question).

import sys, tkinter  root = tkinter.Tk()  class Stderr(tkinter.Toplevel):     def __init__(self):         self.txt = tkinter.Text(root)         self.txt.pack()     def write(self, s):         self.txt.insert('insert', s)  sys.stderr = Stderr()  1/0 # traceback appears in window 

More is needed to keep the popup window hidden until needed and then make it visible.

like image 28
Terry Jan Reedy Avatar answered Oct 11 '22 11:10

Terry Jan Reedy