Source code for devctrl.gui.task.run.device_action

from .base import TaskRunWidget
from ....task import DeviceActionTask
from ....utility.threading import ThreadWithExceptionSupport, Queue
from ....devices.device_manager import DeviceManager

from typing import Callable, Optional
from PyQt6.QtCore import QTimer
from PyQt6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout
import logging
log = logging.getLogger(__name__)



[docs] class DeviceActionTaskRunWidget(TaskRunWidget): """Widget for :class:`.DeviceActionTask` that runs the configured device action in a separate thread. The device must be managed by a py:class:`device manager <.DeviceManager>`. The device manager can be assigned to the static py:attr:`.DEVICE_MAMANGER` variable, or be passed in the constructor of the widget. The action is run in a separate thread to make sure the GUI does not hang when a longer operation is performed. """ DEVICE_MANAGER: Optional[DeviceManager] = None
[docs] def __init__(self, task: DeviceActionTask, device_manager: Optional[DeviceManager]=None, parent=None): super().__init__(task, parent) if device_manager is not None: self.devmg = device_manager elif self.DEVICE_MANAGER is not None: self.devmg = self.DEVICE_MANAGER else: raise ValueError(f"A device manager must be either given to the constructor or be assigned to `DeviceActionTaskRunWidget.DEVICE_MANAGER`, but both are None.") l = QVBoxLayout() self.setLayout(l) self.w_label = QLabel(f"") l.addWidget(self.w_label) self._thread: Optional[ThreadWithExceptionSupport] = None self._ex_queue: Queue = Queue()
[docs] def start_task(self) -> bool: self.w_label.setText(f"Getting SMTP settings") device = self.devmg.get_device(self.task.device_key) try: func = getattr(device, self.task.device_parameter) except AttributeError as e: raise AttributeError(f"Task is misconfigured: The device {device.get_device_type_name()} does not have attribute '{self.task.device_parameter}'.") if self.task.arguments: args_str = ", "+ ", ".join(self.task.arguments) else: args_str = "" self.w_label.setText(f"Running: {device.get_device_name()}.{self.task.device_parameter}({args_str})") log.debug(f"Running: {device.get_device_name()}.{self.task.device_parameter}({args_str})") self._thread = ThreadWithExceptionSupport(queue=self._ex_queue, target=func, args=self.task.arguments) self._thread.run() return True
[docs] def update_task(self) -> Optional[bool]: """Check if thread is still running""" if self._thread is None: raise RuntimeError(f"DeviceAction thread not running") if self._thread.is_alive(): return None else: return True
[docs] def stop_task(self) -> bool: if self._thread is None: raise RuntimeError(f"DeviceAction thread not running") errs = False while not self._ex_queue.empty(): ex = self._ex_queue.get() log.error(f"Exception occured while performing device action: {type(ex)}: {ex}") errs = True if self._thread.is_alive(): self._thread.join() self._thread = None return not errs