BonPrinter v1.2.0
Thermal Printer tool
Loading...
Searching...
No Matches
app_err_handler.py
Go to the documentation of this file.
1"""!
2********************************************************************************
3@file app_err_handler.py
4@brief Error handler to catch all unexpected exceptions to prevent application crashes
5********************************************************************************
6"""
7
8# Source: https://timlehr.com/python-exception-hooks-with-qt-message-box/
9
10import sys
11import traceback
12import logging
13from typing import Optional, Any, TYPE_CHECKING
14from types import TracebackType
15
16from Source.version import __title__
17from Source.Util.app_data import reset_config_dialog
18from Source.Util.gui_toolkit import APPLICATION, SIGNAL, OBJECT, config_window, open_message_box
19
20from Source.Model.language import L_CLOSE, L_REPAIR, L_UNEXP_ERROR
21
22if TYPE_CHECKING:
23 from Source.Controller.main_window import MainWindow
24
25log = logging.getLogger(__title__)
26
27
28class UncaughtHook(OBJECT):
29 """!
30 @brief Global exception handler. Overrides system exception hook to catch all unexpected errors.
31 """
32 exception_caught = SIGNAL(object)
33
34 def __init__(self, *args: Any, **kwargs: Any) -> None:
35 log.debug("Initializing Exception Handler")
36
37 super().__init__(*args, **kwargs)
38
39 self.main_window_controller: "MainWindow | None" = None
40 self.crash_arrived = False
41
42 # this registers the exception_hook() function as hook with the Python interpreter
43 sys.excepthook = self.exception_hook
44
45 # connect signal to execute the message box function always on main thread
47
48 def show_exception_box(self, s_log_msg: str) -> None:
49 """!
50 @brief Displays the error message box
51 @param s_log_msg : the error message to be displayed in details section
52 """
53 # check if QApplication instance is available
54 self.crash_arrived = True
55 if (APPLICATION is not None) and (APPLICATION.instance() is not None):
56 b_close = (self.main_window_controller is not None) and self.main_window_controller.test_mode
57 l_close_text = L_CLOSE
59 text = self.main_window_controller.model.c_language.get_language_text(L_UNEXP_ERROR)
60 repair_text = self.main_window_controller.model.c_language.get_language_text(L_REPAIR)
61 close_text = self.main_window_controller.model.c_language.get_language_text(l_close_text)
62 else:
63 text = L_UNEXP_ERROR[0]
64 repair_text = L_REPAIR[0]
65 close_text = l_close_text[0]
66 choice, _ = open_message_box(self.main_window_controller,
67 "Error", f"{text}\t\t\t\t",
68 btn_close=close_text,
69 btn_special=repair_text,
70 detailed_text=s_log_msg,
71 execute=not b_close)
72 if b_close:
73 sys.exit(1)
74 if choice:
75 reset_config_dialog(self.main_window_controller)
77 config_window(self.main_window_controller, show=False)
78 else:
79 log.error("Can't show Exception Display - No QApplication instance available.")
80
81 def exception_hook(self, exc_type: type[BaseException], exc_value: BaseException, exc_traceback: Optional[TracebackType] = None) -> None:
82 """!
83 @brief Custom exception hook. It is triggered each time an uncaught exception occurs.
84 @param exc_type : exception type
85 @param exc_value : exception value
86 @param exc_traceback : exception traceback
87 """
88 if issubclass(exc_type, KeyboardInterrupt):
89 # ignore keyboard interrupt to support console application
90 sys.__excepthook__(exc_type, exc_value, exc_traceback)
91 else:
92 log_msg = "\n".join([f"{exc_type.__name__}: {exc_value}",
93 "".join(traceback.format_tb(exc_traceback))])
94 log.error(log_msg)
95
96 # trigger message box show
97 self.exception_caught.emit(log_msg)
98
99 def set_main_window_controller(self, main_window_controller: "MainWindow") -> None:
100 """!
101 @brief Sets the main window controller in order to unblock the UI after a critical exception is caught.
102 @param main_window_controller : main window controller
103 """
104 self.main_window_controller = main_window_controller
None __init__(self, *Any args, **Any kwargs)
None set_main_window_controller(self, "MainWindow" main_window_controller)
Sets the main window controller in order to unblock the UI after a critical exception is caught.
None exception_hook(self, type[BaseException] exc_type, BaseException exc_value, Optional[TracebackType] exc_traceback=None)
Custom exception hook.