From: Advaith Menon Date: Fri, 30 Jan 2026 21:04:14 +0000 (-0500) Subject: Add exception handling X-Git-Url: https://git.devinivas.org/?a=commitdiff_plain;h=c4c3adf8652f6cf90b62767469c4be7570bbd2f6;p=4180kiosk.git Add exception handling --- diff --git a/ohdisp/exception_dialog.py b/ohdisp/exception_dialog.py new file mode 100644 index 0000000..3ef0e8f --- /dev/null +++ b/ohdisp/exception_dialog.py @@ -0,0 +1,31 @@ +import os +import sys +import threading + +import tkinter as tk +from tkinter import messagebox +from tkinter.font import Font + + +class ExceptionDialog(tk.Toplevel): + def __init__(self, parent, txt, *args, **kwargs): + super().__init__(parent, *args, **kwargs); + + self.title("Unhandled Exception"); + self.attributes("-topmost", True); + self.wm_protocol("WM_DELETE_WINDOW", self.destroy) + + sb = tk.Scrollbar(self); + sb.pack(side='right', fill='y') + + te = tk.Text(self); + te.insert('end', txt); + te.pack(side='top', fill='both', expand=True) + + te['yscrollcommand'] = sb.set + sb['command'] = te.yview + + quit_btn = tk.Button(self, text="Quit", + command=self.destroy, + padx=5, pady=5) + quit_btn.pack(side='right') diff --git a/ohdisp/model.py b/ohdisp/model.py index f59f418..7246cea 100644 --- a/ohdisp/model.py +++ b/ohdisp/model.py @@ -1,14 +1,20 @@ import time +import traceback import datetime import os import subprocess +import sys +import _thread import tkinter as tk +from tkinter import messagebox from tkinter.font import Font import urllib3 import pyttsx3 +from .exception_dialog import ExceptionDialog + class QueueModel(object): def __init__(self, config, *args, **kwargs): self._cfg = config; @@ -25,7 +31,23 @@ class QueueModel(object): return result; - def thread(self, tk_parent): + def thread(self, tk_parent, root): + """Wraps the original thread with exception handling""" + try: + self._thread(tk_parent); + except Exception as e: + err = traceback.format_exception(e); + if root: + tl = ExceptionDialog(root, "\n".join(err)) + root.wait_window(tl); + else: + messagebox.showerror('Unhandled Exception in Polling Thread', + "\n".join(err) + ("\n\n" + "The application will now quit.")); + print("Crashing application\n" + "\n".join(err), file=sys.stderr); + _thread.interrupt_main(); + + def _thread(self, tk_parent): n_students = 0 cur_students = []; self.build_elements(cur_students, tk_parent); diff --git a/ohdisp/views.py b/ohdisp/views.py index 490fb06..cfb35c0 100644 --- a/ohdisp/views.py +++ b/ohdisp/views.py @@ -1,10 +1,14 @@ import os +import sys import threading import tkinter as tk +from tkinter import messagebox from tkinter.font import Font from .model import QueueModel +from .exception_dialog import ExceptionDialog + from PIL import ImageTk, Image @@ -27,7 +31,7 @@ class TADisplayFrame(tk.Frame): fg=self._cnf.style.title__fgcolor); self._title.pack(side='top', anchor='n', fill='x'); - self._frame = StudentCheckoffFrame(self, self._cnf); + self._frame = StudentCheckoffFrame(self, self._cnf, root=parent); self._frame.pack(side='right', fill="both"); self._frame = TAPictureFrame(self, self._cnf); self._frame.pack(side='top', fill='both', expand=1); @@ -60,7 +64,7 @@ class TAPictureFrame(tk.Frame): class StudentCheckoffFrame(tk.Frame): - def __init__(self, parent, config, *args, **kwargs): + def __init__(self, parent, config, *args, root=None, **kwargs): super().__init__(parent, *args, **kwargs); self._cnf = config; @@ -85,7 +89,7 @@ class StudentCheckoffFrame(tk.Frame): self._actualframe.pack(side='top', fill='both', expand=1); t = threading.Thread(target=self._model.thread, - args=(self._actualframe,), + args=(self._actualframe, root), daemon=True) t.start() @@ -103,3 +107,11 @@ class Root(tk.Tk): def fullscreen(self): self.attributes("-fullscreen", True); + + def report_callback_exception(self, *args): + err = traceback.format_exception(*args); + tl = ExceptionDialog(self, "\n".join(err)) + self.wait_window(tl); + self.destroy(); + print("Exiting application\n" + err, file=sys.stderr); + exit();