Skip to content
Snippets Groups Projects
Commit 71b16c97 authored by Christoph Schmidt's avatar Christoph Schmidt
Browse files

Updated to v0.2.0. Errors are now caught and displayed in the control thread.

parent 5c6e14a4
No related branches found
No related tags found
No related merge requests found
...@@ -28,3 +28,7 @@ class ChildProcess3(cmp.CProcess): ...@@ -28,3 +28,7 @@ class ChildProcess3(cmp.CProcess):
@test_call2.setter(emit_to='bar') @test_call2.setter(emit_to='bar')
def test_call2(self, value: int): def test_call2(self, value: int):
self.my_value = value self.my_value = value
@cmp.CProcess.register_signal()
def exception_call(self, value: int):
return value/0
\ No newline at end of file
...@@ -17,3 +17,6 @@ class ChildProcessControl3(cmp.CProcessControl): ...@@ -17,3 +17,6 @@ class ChildProcessControl3(cmp.CProcessControl):
print(a) print(a)
#print(f"{os.getpid()} -> call_without_mp with {a}, {b}, {c}!") #print(f"{os.getpid()} -> call_without_mp with {a}, {b}, {c}!")
@cmp.CProcessControl.register_function()
def exception_call(self, a):
pass
...@@ -39,7 +39,7 @@ class Form(QDialog): ...@@ -39,7 +39,7 @@ class Form(QDialog):
self.lineedit.setFocus() self.lineedit.setFocus()
self.setWindowTitle('Upper') self.setWindowTitle('Upper')
# self.lineedit.returnPressed.connect(lambda: child_con.call_without_mp(1, 2, c=3)) # self.lineedit.returnPressed.connect(lambda: child_con.call_without_mp(1, 2, c=3))
self.lineedit.returnPressed.connect(lambda: child_con.test_call(1)) self.lineedit.returnPressed.connect(lambda: child_con.exception_call(1))
def updateUI(self, text): def updateUI(self, text):
......
import traceback
class CException:
def __init__(self, parent_name: str, function_name: str, exception: Exception):
self.parent_name = parent_name
self.function_name: str = function_name
self.exception = exception
self.traceback_list: list[str] = traceback.format_exception(
type(self.exception),
value=self.exception,
tb=self.exception.__traceback__)
self.additional_info: str = ""
def traceback_short(self) -> str:
return "".join(self.traceback_list[-2:len(self.traceback_list)])
def traceback(self) -> str:
return "".join(self.traceback_list)
def set_additional_info(self, additional_info: str):
self.additional_info = additional_info
...@@ -118,6 +118,15 @@ class CProcess(CBase, Process): ...@@ -118,6 +118,15 @@ class CProcess(CBase, Process):
result = cmp.CResultRecord(func_name, signal_name, res) result = cmp.CResultRecord(func_name, signal_name, res)
self.state_queue.put(result) self.state_queue.put(result)
def _put_exception_to_queue(self, func_name, exc):
self._internal_logger.debug(f"Error executing {func_name}.")
tb_str = traceback.format_exception(type(exc), value=exc, tb=exc.__traceback__)
tb_join = "".join(tb_str[-2:len(tb_str)])
result = cmp.CException(self.name, func_name, exc, )
result.set_additional_info(tb_join)
self.state_queue.put(result)
@staticmethod @staticmethod
def register_signal(postfix=None, signal_name: str = None): def register_signal(postfix=None, signal_name: str = None):
_postfix = postfix.strip() if postfix is not None else None _postfix = postfix.strip() if postfix is not None else None
...@@ -138,9 +147,15 @@ class CProcess(CBase, Process): ...@@ -138,9 +147,15 @@ class CProcess(CBase, Process):
self._internal_logger.debug(f"Constructing signal name for function '{func.__name__}': {sign}") self._internal_logger.debug(f"Constructing signal name for function '{func.__name__}': {sign}")
else: else:
sign = None sign = None
try:
res = func(self, *args, **kwargs) res = func(self, *args, **kwargs)
self._put_result_to_queue(func_name, sign, res) self._put_result_to_queue(func_name, sign, res)
return res return res
except Exception as e:
self._internal_logger.error(f"Error in function {func_name}: {e} ({type(e)})")
self._put_exception_to_queue(func.__name__, e)
return None
return get_signature return get_signature
......
...@@ -5,20 +5,23 @@ import os ...@@ -5,20 +5,23 @@ import os
import re import re
import signal import signal
import time import time
import traceback
from multiprocessing import Queue, Process, Value from multiprocessing import Queue, Process, Value
from typing import Type from typing import Type
from PySide6.QtCore import QObject, QThreadPool, Signal from PySide6.QtCore import QObject, QThreadPool, Signal
from PySide6.QtGui import QWindow from PySide6.QtGui import QWindow
from PySide6.QtWidgets import QWidget from PySide6.QtWidgets import QWidget, QMessageBox
from rich.logging import RichHandler from rich.logging import RichHandler
import cmp import cmp
from cmp import CException
from cmp.CBase import CBase from cmp.CBase import CBase
class CProcessControl(CBase, QObject): class CProcessControl(CBase, QObject):
on_exception_raised = Signal(object, name='on_exception_raised')
def __init__(self, parent: QObject = None, def __init__(self, parent: QObject = None,
signal_class: QObject = None, signal_class: QObject = None,
internal_log: bool = False, internal_log: bool = False,
...@@ -60,6 +63,9 @@ class CProcessControl(CBase, QObject): ...@@ -60,6 +63,9 @@ class CProcessControl(CBase, QObject):
self.internal_log_level = internal_log_level self.internal_log_level = internal_log_level
self.logger, self.logger_handler = self.create_new_logger(f"{self.__class__.__name__}({os.getpid()})") self.logger, self.logger_handler = self.create_new_logger(f"{self.__class__.__name__}({os.getpid()})")
self.on_exception_raised.connect(self.display_exception)
self.msg_box = QMessageBox()
# ================================================================================================================== # ==================================================================================================================
# #
# ================================================================================================================== # ==================================================================================================================
...@@ -107,6 +113,12 @@ class CProcessControl(CBase, QObject): ...@@ -107,6 +113,12 @@ class CProcessControl(CBase, QObject):
res.emit_signal(self._signal_class) res.emit_signal(self._signal_class)
except Exception as e: except Exception as e:
self._internal_logger.error(f"Error while emitting {res} in {self.__class__.__name__}: {e}") self._internal_logger.error(f"Error while emitting {res} in {self.__class__.__name__}: {e}")
elif isinstance(res, cmp.CException):
self._internal_logger.error(f"Received exception: {res}")
try:
self.on_exception_raised.emit(res)
except Exception as e:
self._internal_logger.error(f"Error while emitting exception: {e}")
else: else:
self._internal_logger.error(f"Received unknown result {res}!") self._internal_logger.error(f"Received unknown result {res}!")
...@@ -118,6 +130,23 @@ class CProcessControl(CBase, QObject): ...@@ -118,6 +130,23 @@ class CProcessControl(CBase, QObject):
self.state_queue.close() self.state_queue.close()
self.cmd_queue.close() self.cmd_queue.close()
def display_exception(self, e: cmp.CException):
# Create a message box
try:
self.msg_box = QMessageBox()
self.msg_box.setIcon(QMessageBox.Critical)
self.msg_box.setText(f"Error executing {e.function_name} in {e.parent_name}")
self.msg_box.setInformativeText(f"Error: {e.exception}")
self.msg_box.setWindowTitle("Error")
self.msg_box.setDetailedText(e.traceback_short())
self.msg_box.setStandardButtons(QMessageBox.Ok)
self.msg_box.show()
self._internal_logger.error(f"Error executing {e.function_name} in {e.parent_name}: {e.exception}\n"
f"{e.traceback()}")
except Exception as e:
self._internal_logger.error(f"Error while displaying exception: {e}")
def execute_function(self, func: callable, signal: Signal = None): def execute_function(self, func: callable, signal: Signal = None):
self.register_function(signal)(func)(self) self.register_function(signal)(func)(self)
......
...@@ -6,6 +6,7 @@ from rich.logging import RichHandler ...@@ -6,6 +6,7 @@ from rich.logging import RichHandler
from .CCommandRecord import CCommandRecord from .CCommandRecord import CCommandRecord
from .CResultRecord import CResultRecord from .CResultRecord import CResultRecord
from .CException import CException
from .CProcess import CProcess from .CProcess import CProcess
from .CProcessControl import CProcessControl from .CProcessControl import CProcessControl
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment