0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

refactor: cleanup, added device_signal for signal inputs

This commit is contained in:
2024-10-21 13:00:55 +02:00
parent 0350833f36
commit 6fb20552ff
13 changed files with 288 additions and 235 deletions

View File

@ -217,7 +217,7 @@ DEVICES = [
FakeDevice("bpm4i"), FakeDevice("bpm4i"),
FakeDevice("bpm3a"), FakeDevice("bpm3a"),
FakeDevice("bpm3i"), FakeDevice("bpm3i"),
FakeDevice("eiger"), FakeDevice("eiger", readout_priority=ReadoutPriority.ASYNC),
FakeDevice("waveform1d"), FakeDevice("waveform1d"),
FakeDevice("async_device", readout_priority=ReadoutPriority.ASYNC), FakeDevice("async_device", readout_priority=ReadoutPriority.ASYNC),
Positioner("test", limits=[-10, 10], read_value=2.0), Positioner("test", limits=[-10, 10], read_value=2.0),

View File

@ -99,7 +99,7 @@ class FilterIO:
_handlers = {QLineEdit: LineEditFilterHandler, QComboBox: ComboBoxFilterHandler} _handlers = {QLineEdit: LineEditFilterHandler, QComboBox: ComboBoxFilterHandler}
@staticmethod @staticmethod
def set_selection(widget, selection: list, ignore_errors=False): def set_selection(widget, selection: list, ignore_errors=True):
""" """
Retrieve value from the widget instance. Retrieve value from the widget instance.
@ -118,7 +118,7 @@ class FilterIO:
return None return None
@staticmethod @staticmethod
def check_input(widget, text: str, ignore_errors=False): def check_input(widget, text: str, ignore_errors=True):
""" """
Check if the input text is in the filtered selection. Check if the input text is in the filtered selection.

View File

@ -5,7 +5,6 @@ import enum
from bec_lib.device import ComputedSignal, Device, Positioner, ReadoutPriority, Signal from bec_lib.device import ComputedSignal, Device, Positioner, ReadoutPriority, Signal
from bec_lib.logger import bec_logger from bec_lib.logger import bec_logger
from qtpy.QtCore import Property, Slot from qtpy.QtCore import Property, Slot
from typeguard import typechecked
from bec_widgets.utils import ConnectionConfig from bec_widgets.utils import ConnectionConfig
from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.bec_widget import BECWidget
@ -25,11 +24,12 @@ class BECDeviceFilter(enum.Enum):
class DeviceInputConfig(ConnectionConfig): class DeviceInputConfig(ConnectionConfig):
device_filter: list[BECDeviceFilter] | None = None device_filter: list[BECDeviceFilter] = []
readout_filter: list[ReadoutPriority] | None = None readout_filter: list[ReadoutPriority] = []
devices: list[str] | None = None devices: list[str] = []
default: str | None = None default: str | None = None
arg_name: str | None = None arg_name: str | None = None
apply_filter: bool = True
class DeviceInputBase(BECWidget): class DeviceInputBase(BECWidget):
@ -47,10 +47,10 @@ class DeviceInputBase(BECWidget):
} }
_filter_handler = { _filter_handler = {
BECDeviceFilter.DEVICE: "include_device", BECDeviceFilter.DEVICE: "filter_to_device",
BECDeviceFilter.POSITIONER: "include_positioner", BECDeviceFilter.POSITIONER: "filter_to_positioner",
BECDeviceFilter.SIGNAL: "include_signal", BECDeviceFilter.SIGNAL: "filter_to_signal",
BECDeviceFilter.COMPUTED_SIGNAL: "include_computed_signal", BECDeviceFilter.COMPUTED_SIGNAL: "filter_to_computed_signal",
ReadoutPriority.MONITORED: "readout_monitored", ReadoutPriority.MONITORED: "readout_monitored",
ReadoutPriority.BASELINE: "readout_baseline", ReadoutPriority.BASELINE: "readout_baseline",
ReadoutPriority.ASYNC: "readout_async", ReadoutPriority.ASYNC: "readout_async",
@ -66,7 +66,7 @@ class DeviceInputBase(BECWidget):
if isinstance(config, dict): if isinstance(config, dict):
config = DeviceInputConfig(**config) config = DeviceInputConfig(**config)
self.config = config self.config = config
super().__init__(client=client, config=config, gui_id=gui_id) super().__init__(client=client, config=config, gui_id=gui_id, theme_update=True)
self.get_bec_shortcuts() self.get_bec_shortcuts()
self._device_filter = [] self._device_filter = []
self._readout_filter = [] self._readout_filter = []
@ -82,7 +82,7 @@ class DeviceInputBase(BECWidget):
Args: Args:
device (str): Default name. device (str): Default name.
""" """
if self.validate_device(device, raise_on_false=True) is True: if self.validate_device(device) is True:
WidgetIO.set_value(widget=self, value=device) WidgetIO.set_value(widget=self, value=device)
self.config.default = device self.config.default = device
else: else:
@ -91,9 +91,13 @@ class DeviceInputBase(BECWidget):
@Slot() @Slot()
def update_devices_from_filters(self): def update_devices_from_filters(self):
"""Update the devices based on the current filter selection """Update the devices based on the current filter selection
in self.device_filter and self.readout_filter.""" in self.device_filter and self.readout_filter. If apply_filter is False,
it will not apply the filters, store the filter settings and return.
"""
self.config.device_filter = self.device_filter self.config.device_filter = self.device_filter
self.config.readout_filter = self.readout_filter self.config.readout_filter = self.readout_filter
if self.apply_filter is False:
return
all_dev = self.dev.enabled_devices all_dev = self.dev.enabled_devices
# Filter based on device class # Filter based on device class
devs = [dev for dev in all_dev if self._check_device_filter(dev)] devs = [dev for dev in all_dev if self._check_device_filter(dev)]
@ -109,16 +113,37 @@ class DeviceInputBase(BECWidget):
Args: Args:
devices (list[str]): List of devices. devices (list[str]): List of devices.
""" """
valid_dev = [] self.apply_filter = False
all_dev_names = [dev.name for dev in self.dev.enabled_devices] self.devices = devices
for device in devices:
if device not in all_dev_names:
continue
valid_dev.append(device)
self.devices = valid_dev
### QtProperties ### ### QtProperties ###
@Property(
"QStringList",
doc="List of devices. If updated, it will disable the apply filters property.",
)
def devices(self) -> list[str]:
"""
Get the list of devices for the applied filters.
Returns:
list[str]: List of devices.
"""
return self._devices
@devices.setter
def devices(self, value: list):
valid_dev = []
all_dev_names = [dev.name for dev in self.dev.enabled_devices]
for dev in value:
if dev in all_dev_names:
valid_dev.append(dev)
self._devices = valid_dev
self.config.devices = valid_dev
FilterIO.set_selection(widget=self, selection=valid_dev)
# QTimer.singleShot(200, lambda: FilterIO.set_selection(widget=self, selection=valid_dev))
@Property(str) @Property(str)
def default(self): def default(self):
"""Get the default device name. If set through this property, it will update only if the device is within the filtered selection.""" """Get the default device name. If set through this property, it will update only if the device is within the filtered selection."""
@ -126,30 +151,52 @@ class DeviceInputBase(BECWidget):
@default.setter @default.setter
def default(self, value: str): def default(self, value: str):
if self.validate_device(value, raise_on_false=False) is False: def set_default():
return if self.validate_device(value) is False:
self.set_device(value) return
self.set_device(value)
set_default()
# QTimer.singleShot(200, set_default)
@Property(bool) @Property(bool)
def include_device(self): def apply_filter(self):
"""Apply the filters on the devices."""
return self.config.apply_filter
@apply_filter.setter
def apply_filter(self, value: bool):
def apply_filters():
self.config.apply_filter = value
self.update_devices_from_filters()
apply_filters()
# QTimer.singleShot(200, apply_filters)
@Property(bool)
def filter_to_device(self):
"""Include devices in filters.""" """Include devices in filters."""
return BECDeviceFilter.DEVICE in self.device_filter return BECDeviceFilter.DEVICE in self.device_filter
@include_device.setter @filter_to_device.setter
def include_device(self, value: bool): def filter_to_device(self, value: bool):
if value is True and BECDeviceFilter.DEVICE not in self.device_filter: def set_filter():
self._device_filter.append(BECDeviceFilter.DEVICE) if value is True and BECDeviceFilter.DEVICE not in self.device_filter:
if value is False and BECDeviceFilter.DEVICE in self.device_filter: self._device_filter.append(BECDeviceFilter.DEVICE)
self._device_filter.remove(BECDeviceFilter.DEVICE) if value is False and BECDeviceFilter.DEVICE in self.device_filter:
self.update_devices_from_filters() self._device_filter.remove(BECDeviceFilter.DEVICE)
self.update_devices_from_filters()
set_filter()
# QTimer.singleShot(200, set_filter)
@Property(bool) @Property(bool)
def include_positioner(self): def filter_to_positioner(self):
"""Include devices of type Positioner in filters.""" """Include devices of type Positioner in filters."""
return BECDeviceFilter.POSITIONER in self.device_filter return BECDeviceFilter.POSITIONER in self.device_filter
@include_positioner.setter @filter_to_positioner.setter
def include_positioner(self, value: bool): def filter_to_positioner(self, value: bool):
if value is True and BECDeviceFilter.POSITIONER not in self.device_filter: if value is True and BECDeviceFilter.POSITIONER not in self.device_filter:
self._device_filter.append(BECDeviceFilter.POSITIONER) self._device_filter.append(BECDeviceFilter.POSITIONER)
if value is False and BECDeviceFilter.POSITIONER in self.device_filter: if value is False and BECDeviceFilter.POSITIONER in self.device_filter:
@ -157,12 +204,12 @@ class DeviceInputBase(BECWidget):
self.update_devices_from_filters() self.update_devices_from_filters()
@Property(bool) @Property(bool)
def include_signal(self): def filter_to_signal(self):
"""Include devices of type Signal in filters.""" """Include devices of type Signal in filters."""
return BECDeviceFilter.SIGNAL in self.device_filter return BECDeviceFilter.SIGNAL in self.device_filter
@include_signal.setter @filter_to_signal.setter
def include_signal(self, value: bool): def filter_to_signal(self, value: bool):
if value is True and BECDeviceFilter.SIGNAL not in self.device_filter: if value is True and BECDeviceFilter.SIGNAL not in self.device_filter:
self._device_filter.append(BECDeviceFilter.SIGNAL) self._device_filter.append(BECDeviceFilter.SIGNAL)
if value is False and BECDeviceFilter.SIGNAL in self.device_filter: if value is False and BECDeviceFilter.SIGNAL in self.device_filter:
@ -170,12 +217,12 @@ class DeviceInputBase(BECWidget):
self.update_devices_from_filters() self.update_devices_from_filters()
@Property(bool) @Property(bool)
def include_computed_signal(self): def filter_to_computed_signal(self):
"""Include devices of type ComputedSignal in filters.""" """Include devices of type ComputedSignal in filters."""
return BECDeviceFilter.COMPUTED_SIGNAL in self.device_filter return BECDeviceFilter.COMPUTED_SIGNAL in self.device_filter
@include_computed_signal.setter @filter_to_computed_signal.setter
def include_computed_signal(self, value: bool): def filter_to_computed_signal(self, value: bool):
if value is True and BECDeviceFilter.COMPUTED_SIGNAL not in self.device_filter: if value is True and BECDeviceFilter.COMPUTED_SIGNAL not in self.device_filter:
self._device_filter.append(BECDeviceFilter.COMPUTED_SIGNAL) self._device_filter.append(BECDeviceFilter.COMPUTED_SIGNAL)
if value is False and BECDeviceFilter.COMPUTED_SIGNAL in self.device_filter: if value is False and BECDeviceFilter.COMPUTED_SIGNAL in self.device_filter:
@ -249,22 +296,6 @@ class DeviceInputBase(BECWidget):
### Python Methods and Properties ### ### Python Methods and Properties ###
@property
def devices(self) -> list[str]:
"""
Get the list of devices for the applied filters.
Returns:
list[str]: List of devices.
"""
return self._devices
@devices.setter
def devices(self, value: list[str]):
self._devices = value
self.config.devices = value
FilterIO.set_selection(widget=self, selection=value)
@property @property
def device_filter(self) -> list[object]: def device_filter(self) -> list[object]:
"""Get the list of filters to apply on the devices.""" """Get the list of filters to apply on the devices."""
@ -283,7 +314,6 @@ class DeviceInputBase(BECWidget):
"""Get the available readout priority filters.""" """Get the available readout priority filters."""
return [entry for entry in ReadoutPriority] return [entry for entry in ReadoutPriority]
@typechecked
def set_device_filter( def set_device_filter(
self, filter_selection: str | BECDeviceFilter | list[str] | list[BECDeviceFilter] self, filter_selection: str | BECDeviceFilter | list[str] | list[BECDeviceFilter]
): ):
@ -299,11 +329,11 @@ class DeviceInputBase(BECWidget):
if isinstance(filter_selection, str) or isinstance(filter_selection, BECDeviceFilter): if isinstance(filter_selection, str) or isinstance(filter_selection, BECDeviceFilter):
filters = [self._filter_handler.get(filter_selection)] filters = [self._filter_handler.get(filter_selection)]
if filters is None or any([entry is None for entry in filters]): if filters is None or any([entry is None for entry in filters]):
raise ValueError(f"Device filter {filter_selection} is not in the device list.") logger.warning(f"Device filter {filter_selection} is not in the device filter list.")
return
for entry in filters: for entry in filters:
setattr(self, entry, True) setattr(self, entry, True)
@typechecked
def set_readout_priority_filter( def set_readout_priority_filter(
self, filter_selection: str | ReadoutPriority | list[str] | list[ReadoutPriority] self, filter_selection: str | ReadoutPriority | list[str] | list[ReadoutPriority]
): ):
@ -319,30 +349,27 @@ class DeviceInputBase(BECWidget):
if isinstance(filter_selection, str) or isinstance(filter_selection, ReadoutPriority): if isinstance(filter_selection, str) or isinstance(filter_selection, ReadoutPriority):
filters = [self._filter_handler.get(filter_selection)] filters = [self._filter_handler.get(filter_selection)]
if filters is None or any([entry is None for entry in filters]): if filters is None or any([entry is None for entry in filters]):
raise ValueError( logger.warning(
f"Readout priority filter {filter_selection} is not in the readout priority list." f"Readout priority filter {filter_selection} is not in the readout priority list."
) )
return
for entry in filters: for entry in filters:
setattr(self, entry, True) setattr(self, entry, True)
def _check_device_filter(self, device: Device | Signal | ComputedSignal | Positioner) -> bool: def _check_device_filter(self, device: Device | Signal | ComputedSignal | Positioner) -> bool:
"""If filters are defined, return True. Else return if the device complies to all active filters. """Check if filter for device type is applied or not.
Args: Args:
device(Device | Signal | ComputedSignal | Positioner): Device object. device(Device | Signal | ComputedSignal | Positioner): Device object.
""" """
if len(self.device_filter) == 0:
return True
return all(isinstance(device, self._device_handler[entry]) for entry in self.device_filter) return all(isinstance(device, self._device_handler[entry]) for entry in self.device_filter)
def _check_readout_filter(self, device: Device | Signal | ComputedSignal | Positioner) -> bool: def _check_readout_filter(self, device: Device | Signal | ComputedSignal | Positioner) -> bool:
"""If filters are defined, return True. Else return if the device complies to all active filters. """Check if filter for readout priority is applied or not.
Args: Args:
device(Device | Signal | ComputedSignal | Positioner): Device object. device(Device | Signal | ComputedSignal | Positioner): Device object.
""" """
if len(self.readout_filter) == 0:
return True
return device.readout_priority in self.readout_filter return device.readout_priority in self.readout_filter
def get_device_object(self, device: str) -> object: def get_device_object(self, device: str) -> object:
@ -363,7 +390,7 @@ class DeviceInputBase(BECWidget):
) )
return dev return dev
def validate_device(self, device: str, raise_on_false: bool = False) -> bool: def validate_device(self, device: str) -> bool:
""" """
Validate the device if it is present in the filtered device selection. Validate the device if it is present in the filtered device selection.
@ -372,5 +399,4 @@ class DeviceInputBase(BECWidget):
""" """
if device in self.devices: if device in self.devices:
return True return True
if raise_on_false is True: return False
raise ValueError(f"Device {device} is not in filtered selection.")

View File

@ -1,6 +1,6 @@
import enum from bec_lib.device import Signal
from bec_lib.logger import bec_logger from bec_lib.logger import bec_logger
from ophyd import Kind
from qtpy.QtCore import Property, Slot from qtpy.QtCore import Property, Slot
from bec_widgets.utils import ConnectionConfig from bec_widgets.utils import ConnectionConfig
@ -11,14 +11,6 @@ from bec_widgets.utils.widget_io import WidgetIO
logger = bec_logger.logger logger = bec_logger.logger
class BECSignalFilter(str, enum.Enum):
"""Filter for the device signals."""
HINTED = "5"
NORMAL = "1"
CONFIG = "2"
class DeviceSignalInputBaseConfig(ConnectionConfig): class DeviceSignalInputBaseConfig(ConnectionConfig):
"""Configuration class for DeviceSignalInputBase.""" """Configuration class for DeviceSignalInputBase."""
@ -37,9 +29,9 @@ class DeviceSignalInputBase(BECWidget):
""" """
_filter_handler = { _filter_handler = {
BECSignalFilter.HINTED: "include_hinted_signals", Kind.hinted: "include_hinted_signals",
BECSignalFilter.NORMAL: "include_normal_signals", Kind.normal: "include_normal_signals",
BECSignalFilter.CONFIG: "include_config_signals", Kind.config: "include_config_signals",
} }
def __init__(self, client=None, config=None, gui_id: str = None): def __init__(self, client=None, config=None, gui_id: str = None):
@ -69,7 +61,7 @@ class DeviceSignalInputBase(BECWidget):
Args: Args:
signal (str): signal name. signal (str): signal name.
""" """
if self.validate_signal(signal, raise_on_false=False) is True: if self.validate_signal(signal) is True:
WidgetIO.set_value(widget=self, value=signal) WidgetIO.set_value(widget=self, value=signal)
self.config.default = signal self.config.default = signal
else: else:
@ -80,52 +72,61 @@ class DeviceSignalInputBase(BECWidget):
@Slot(str) @Slot(str)
def set_device(self, device: str | None): def set_device(self, device: str | None):
""" """
Set the device. Set the device. If device is not valid, device will be set to None which happpens
Args: Args:
device(str): device name. device(str): device name.
""" """
if device is None: if self.validate_device(device) is False:
self._device = None self._device = None
if self.validate_device(device, raise_on_false=False) is True:
self._device = device
self.update_signals_from_filters()
else: else:
logger.warning(f"Device {device} not found in device_manager.") self._device = device
self.update_signals_from_filters()
@Slot() @Slot()
def update_signals_from_filters(self): def update_signals_from_filters(self):
"""Update the filters for the device signals based on list in self.signal_filter. """Update the filters for the device signals based on list in self.signal_filter.
In addition, store the hinted, normal and config signals in separate lists to allow In addition, store the hinted, normal and config signals in separate lists to allow
customisation within QLineEdit.""" customisation within QLineEdit.
Note:
Signal and ComputedSignals have no signals. The naming convention follows the device name.
"""
self.config.signal_filter = self.signal_filter self.config.signal_filter = self.signal_filter
# pylint: disable=protected-access # pylint: disable=protected-access
self._hinted_signals = [] self._hinted_signals = []
self._normal_signals = [] self._normal_signals = []
self._config_signals = [] self._config_signals = []
if self._device is None: if self.validate_device(self._device) is False:
self._device = None
self.config.device = self._device
return return
device = self.get_device_object(self._device) device = self.get_device_object(self._device)
# See above convention for Signals and ComputedSignals
if isinstance(device, Signal):
self._signals = [self._device]
FilterIO.set_selection(widget=self, selection=[self._device])
return
device_info = device._info["signals"] device_info = device._info["signals"]
if BECSignalFilter.HINTED in self.signal_filter or len(self.signal_filter) == 0: if Kind.hinted in self.signal_filter:
hinted_signals = [ hinted_signals = [
signal signal
for signal, signal_info in device_info.items() for signal, signal_info in device_info.items()
if (signal_info.get("kind_str", None) == BECSignalFilter.HINTED) if (signal_info.get("kind_str", None) == str(Kind.hinted.value))
] ]
self._hinted_signals = hinted_signals self._hinted_signals = hinted_signals
if BECSignalFilter.NORMAL in self.signal_filter or len(self.signal_filter) == 0: if Kind.normal in self.signal_filter:
normal_signals = [ normal_signals = [
signal signal
for signal, signal_info in device_info.items() for signal, signal_info in device_info.items()
if (signal_info.get("kind_str", None) == BECSignalFilter.NORMAL) if (signal_info.get("kind_str", None) == str(Kind.normal.value))
] ]
self._normal_signals = normal_signals self._normal_signals = normal_signals
if BECSignalFilter.CONFIG in self.signal_filter or len(self.signal_filter) == 0: if Kind.config in self.signal_filter:
config_signals = [ config_signals = [
signal signal
for signal, signal_info in device_info.items() for signal, signal_info in device_info.items()
if (signal_info.get("kind_str", None) == BECSignalFilter.CONFIG) if (signal_info.get("kind_str", None) == str(Kind.config.value))
] ]
self._config_signals = config_signals self._config_signals = config_signals
self._signals = self._hinted_signals + self._normal_signals + self._config_signals self._signals = self._hinted_signals + self._normal_signals + self._config_signals
@ -143,8 +144,6 @@ class DeviceSignalInputBase(BECWidget):
@device.setter @device.setter
def device(self, value: str): def device(self, value: str):
"""Set the device and update the filters, only allow devices present in the devicemanager.""" """Set the device and update the filters, only allow devices present in the devicemanager."""
if self.validate_device(value) is False:
return
self._device = value self._device = value
self.config.device = value self.config.device = value
self.update_signals_from_filters() self.update_signals_from_filters()
@ -152,40 +151,40 @@ class DeviceSignalInputBase(BECWidget):
@Property(bool) @Property(bool)
def include_hinted_signals(self): def include_hinted_signals(self):
"""Include hinted signals in filters.""" """Include hinted signals in filters."""
return BECSignalFilter.HINTED in self.signal_filter return Kind.hinted in self.signal_filter
@include_hinted_signals.setter @include_hinted_signals.setter
def include_hinted_signals(self, value: bool): def include_hinted_signals(self, value: bool):
if value: if value:
self._signal_filter.append(BECSignalFilter.HINTED) self._signal_filter.append(Kind.hinted)
else: else:
self._signal_filter.remove(BECSignalFilter.HINTED) self._signal_filter.remove(Kind.hinted)
self.update_signals_from_filters() self.update_signals_from_filters()
@Property(bool) @Property(bool)
def include_normal_signals(self): def include_normal_signals(self):
"""Include normal signals in filters.""" """Include normal signals in filters."""
return BECSignalFilter.NORMAL in self.signal_filter return Kind.normal in self.signal_filter
@include_normal_signals.setter @include_normal_signals.setter
def include_normal_signals(self, value: bool): def include_normal_signals(self, value: bool):
if value: if value:
self._signal_filter.append(BECSignalFilter.NORMAL) self._signal_filter.append(Kind.normal)
else: else:
self._signal_filter.remove(BECSignalFilter.NORMAL) self._signal_filter.remove(Kind.normal)
self.update_signals_from_filters() self.update_signals_from_filters()
@Property(bool) @Property(bool)
def include_config_signals(self): def include_config_signals(self):
"""Include config signals in filters.""" """Include config signals in filters."""
return BECSignalFilter.CONFIG in self.signal_filter return Kind.config in self.signal_filter
@include_config_signals.setter @include_config_signals.setter
def include_config_signals(self, value: bool): def include_config_signals(self, value: bool):
if value: if value:
self._signal_filter.append(BECSignalFilter.CONFIG) self._signal_filter.append(Kind.config)
else: else:
self._signal_filter.remove(BECSignalFilter.CONFIG) self._signal_filter.remove(Kind.config)
self.update_signals_from_filters() self.update_signals_from_filters()
### Properties and Methods ### ### Properties and Methods ###
@ -232,7 +231,7 @@ class DeviceSignalInputBase(BECWidget):
for entry in filters: for entry in filters:
setattr(self, entry, True) setattr(self, entry, True)
def get_device_object(self, device: str) -> object: def get_device_object(self, device: str) -> object | None:
""" """
Get the device object based on the device name. Get the device object based on the device name.
@ -245,10 +244,11 @@ class DeviceSignalInputBase(BECWidget):
self.validate_device(device) self.validate_device(device)
dev = getattr(self.dev, device.lower(), None) dev = getattr(self.dev, device.lower(), None)
if dev is None: if dev is None:
raise ValueError(f"Device {device} is not found in devicemanager {self.dev}.") logger.warning(f"Device {device} not found in devicemanager.")
return None
return dev return dev
def validate_device(self, device: str, raise_on_false: bool = False) -> bool: def validate_device(self, device: str | None, raise_on_false: bool = False) -> bool:
""" """
Validate the device if it is present in current BEC instance. Validate the device if it is present in current BEC instance.
@ -261,7 +261,7 @@ class DeviceSignalInputBase(BECWidget):
raise ValueError(f"Device {device} not found in devicemanager.") raise ValueError(f"Device {device} not found in devicemanager.")
return False return False
def validate_signal(self, signal: str, raise_on_false: bool = False) -> bool: def validate_signal(self, signal: str) -> bool:
""" """
Validate the signal if it is present in the device signals. Validate the signal if it is present in the device signals.
@ -270,8 +270,4 @@ class DeviceSignalInputBase(BECWidget):
""" """
if signal in self.signals: if signal in self.signals:
return True return True
if raise_on_false is True:
raise ValueError(
f"Signal {signal} not found for device {self.device} and filtered selection {self.signal_filter}."
)
return False return False

View File

@ -36,7 +36,7 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
readout_priority_filter: ( readout_priority_filter: (
str | ReadoutPriority | list[str] | list[ReadoutPriority] | None str | ReadoutPriority | list[str] | list[ReadoutPriority] | None
) = None, ) = None,
device_list: list[str] | None = None, available_devices: list[str] | None = None,
default: str | None = None, default: str | None = None,
arg_name: str | None = None, arg_name: str | None = None,
): ):
@ -49,24 +49,29 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
self.setMinimumSize(QSize(100, 0)) self.setMinimumSize(QSize(100, 0))
self._is_valid_input = False self._is_valid_input = False
self._accent_colors = get_accent_colors() self._accent_colors = get_accent_colors()
# Set readout priority filter and device filter. # We do not consider the config that is passed here, this produced problems
# If value is set directly in init, this overrules value from the config # with QtDesigner, since config and input arguments may differ and resolve properly
readout_priority_filter = ( # Implementing this logic and config recoverage is postponed.
readout_priority_filter # Set available devices if passed
if readout_priority_filter is not None if available_devices is not None:
else self.config.readout_filter self.set_available_devices(available_devices)
) # Set readout priority filter default is all
if readout_priority_filter is not None: if readout_priority_filter is not None:
self.set_readout_priority_filter(readout_priority_filter) self.set_readout_priority_filter(readout_priority_filter)
device_filter = device_filter if device_filter is not None else self.config.device_filter else:
self.set_readout_priority_filter(
[
ReadoutPriority.MONITORED,
ReadoutPriority.BASELINE,
ReadoutPriority.ASYNC,
ReadoutPriority.CONTINUOUS,
ReadoutPriority.ON_REQUEST,
]
)
# Device filter default is None
if device_filter is not None: if device_filter is not None:
self.set_device_filter(device_filter) self.set_device_filter(device_filter)
device_list = device_list if device_list is not None else self.config.devices # Set default device if passed
if device_list is not None:
self.set_available_devices(device_list)
else:
self.update_devices_from_filters()
default = default if default is not None else self.config.default
if default is not None: if default is not None:
self.set_device(default) self.set_device(default)

View File

@ -1,7 +1,8 @@
from bec_lib.device import ReadoutPriority from bec_lib.device import ReadoutPriority
from qtpy.QtCore import QSize from bec_lib.logger import bec_logger
from qtpy.QtCore import QSize, Signal, Slot
from qtpy.QtGui import QPainter, QPaintEvent, QPen from qtpy.QtGui import QPainter, QPaintEvent, QPen
from qtpy.QtWidgets import QCompleter, QLineEdit, QSizePolicy from qtpy.QtWidgets import QApplication, QCompleter, QLineEdit, QSizePolicy
from bec_widgets.utils.colors import get_accent_colors from bec_widgets.utils.colors import get_accent_colors
from bec_widgets.widgets.base_classes.device_input_base import ( from bec_widgets.widgets.base_classes.device_input_base import (
@ -10,6 +11,8 @@ from bec_widgets.widgets.base_classes.device_input_base import (
DeviceInputConfig, DeviceInputConfig,
) )
logger = bec_logger.logger
class DeviceLineEdit(DeviceInputBase, QLineEdit): class DeviceLineEdit(DeviceInputBase, QLineEdit):
""" """
@ -39,39 +42,46 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
readout_priority_filter: ( readout_priority_filter: (
str | ReadoutPriority | list[str] | list[ReadoutPriority] | None str | ReadoutPriority | list[str] | list[ReadoutPriority] | None
) = None, ) = None,
device_list: list[str] | None = None, available_devices: list[str] | None = None,
default: str | None = None, default: str | None = None,
arg_name: str | None = None, arg_name: str | None = None,
): ):
self._is_valid_input = False
self._accent_colors = get_accent_colors()
super().__init__(client=client, config=config, gui_id=gui_id) super().__init__(client=client, config=config, gui_id=gui_id)
QLineEdit.__init__(self, parent=parent) QLineEdit.__init__(self, parent=parent)
self._is_valid_input = False
self.completer = QCompleter(self) self.completer = QCompleter(self)
self.setCompleter(self.completer) self.setCompleter(self.completer)
if arg_name is not None: if arg_name is not None:
self.config.arg_name = arg_name self.config.arg_name = arg_name
self.arg_name = arg_name self.arg_name = arg_name
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.setMinimumSize(QSize(100, 0)) self.setMinimumSize(QSize(100, 0))
self._accent_colors = get_accent_colors()
# Set readout priority filter and device filter. # We do not consider the config that is passed here, this produced problems
# If value is set directly in init, this overrules value from the config # with QtDesigner, since config and input arguments may differ and resolve properly
readout_priority_filter = ( # Implementing this logic and config recoverage is postponed.
readout_priority_filter # Set available devices if passed
if readout_priority_filter is not None if available_devices is not None:
else self.config.readout_filter self.set_available_devices(available_devices)
) # Set readout priority filter default is all
if readout_priority_filter is not None: if readout_priority_filter is not None:
self.set_readout_priority_filter(readout_priority_filter) self.set_readout_priority_filter(readout_priority_filter)
device_filter = device_filter if device_filter is not None else self.config.device_filter else:
self.set_readout_priority_filter(
[
ReadoutPriority.MONITORED,
ReadoutPriority.BASELINE,
ReadoutPriority.ASYNC,
ReadoutPriority.CONTINUOUS,
ReadoutPriority.ON_REQUEST,
]
)
# Device filter default is None
if device_filter is not None: if device_filter is not None:
self.set_device_filter(device_filter) self.set_device_filter(device_filter)
device_list = device_list if device_list is not None else self.config.devices # Set default device if passed
if device_list is not None:
self.set_available_devices(device_list)
else:
self.update_devices_from_filters()
default = default if default is not None else self.config.default
if default is not None: if default is not None:
self.set_device(default) self.set_device(default)
self.textChanged.connect(self.check_validity) self.textChanged.connect(self.check_validity)
@ -92,16 +102,19 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
Args: Args:
event (PySide6.QtGui.QPaintEvent) : Paint event. event (PySide6.QtGui.QPaintEvent) : Paint event.
""" """
# logger.info(f"Received paint event: {event} in {self.__class__}")
super().paintEvent(event) super().paintEvent(event)
painter = QPainter(self)
pen = QPen()
pen.setWidth(2)
if self._is_valid_input is False and self.isEnabled() is True: if self._is_valid_input is False and self.isEnabled() is True:
painter = QPainter(self)
pen = QPen()
pen.setWidth(2)
pen.setColor(self._accent_colors.emergency) pen.setColor(self._accent_colors.emergency)
painter.setPen(pen) painter.setPen(pen)
painter.drawRect(self.rect().adjusted(1, 1, -1, -1)) painter.drawRect(self.rect().adjusted(1, 1, -1, -1))
painter.end()
@Slot(str)
def check_validity(self, input_text: str) -> None: def check_validity(self, input_text: str) -> None:
""" """
Check if the current value is a valid device name. Check if the current value is a valid device name.
@ -116,9 +129,10 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
if __name__ == "__main__": # pragma: no cover if __name__ == "__main__": # pragma: no cover
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget from qtpy.QtWidgets import QVBoxLayout, QWidget
from bec_widgets.utils.colors import set_theme from bec_widgets.utils.colors import set_theme
from bec_widgets.widgets.signal_combobox.signal_combobox import SignalComboBox
app = QApplication([]) app = QApplication([])
set_theme("dark") set_theme("dark")
@ -127,7 +141,12 @@ if __name__ == "__main__": # pragma: no cover
layout = QVBoxLayout() layout = QVBoxLayout()
widget.setLayout(layout) widget.setLayout(layout)
line_edit = DeviceLineEdit() line_edit = DeviceLineEdit()
line_edit.include_positioner = True line_edit.filter_to_positioner = True
signal_line_edit = SignalComboBox()
line_edit.textChanged.connect(signal_line_edit.set_device)
line_edit.set_available_devices(["samx", "samy", "samz"])
line_edit.set_device("samx")
layout.addWidget(line_edit) layout.addWidget(line_edit)
layout.addWidget(signal_line_edit)
widget.show() widget.show()
app.exec_() app.exec_()

View File

@ -4,6 +4,7 @@ import sys
from typing import Literal, Optional from typing import Literal, Optional
import pyqtgraph as pg import pyqtgraph as pg
from bec_lib.device import ReadoutPriority
from qtpy.QtWidgets import QComboBox, QVBoxLayout, QWidget from qtpy.QtWidgets import QComboBox, QVBoxLayout, QWidget
from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
@ -70,7 +71,11 @@ class BECImageWidget(BECWidget, QWidget):
self.toolbar = ModularToolBar( self.toolbar = ModularToolBar(
actions={ actions={
"monitor": DeviceSelectionAction( "monitor": DeviceSelectionAction(
"Monitor:", DeviceComboBox(device_filter=BECDeviceFilter.DEVICE) "Monitor:",
DeviceComboBox(
device_filter=BECDeviceFilter.DEVICE,
readout_priority_filter=[ReadoutPriority.ASYNC],
),
), ),
"monitor_type": WidgetAction(widget=self.dim_combo_box), "monitor_type": WidgetAction(widget=self.dim_combo_box),
"connect": MaterialIconAction(icon_name="link", tooltip="Connect Device"), "connect": MaterialIconAction(icon_name="link", tooltip="Connect Device"),

View File

@ -21,6 +21,7 @@ from qtpy.QtWidgets import (
) )
from bec_widgets.utils.widget_io import WidgetIO from bec_widgets.utils.widget_io import WidgetIO
from bec_widgets.widgets.base_classes.device_input_base import BECDeviceFilter
from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
logger = bec_logger.logger logger = bec_logger.logger
@ -233,6 +234,7 @@ class ScanGroupBox(QGroupBox):
default = None default = None
widget = widget_class(arg_name=arg_name, default=default) widget = widget_class(arg_name=arg_name, default=default)
if isinstance(widget, DeviceLineEdit): if isinstance(widget, DeviceLineEdit):
widget.set_device_filter(BECDeviceFilter.DEVICE)
self.selected_devices[widget] = "" self.selected_devices[widget] = ""
widget.device_selected.connect(self.emit_device_selected) widget.device_selected.connect(self.emit_device_selected)
tooltip = item.get("tooltip", None) tooltip = item.get("tooltip", None)

View File

@ -1,4 +1,6 @@
from qtpy.QtCore import QSize from bec_lib.device import Positioner
from ophyd import Kind
from qtpy.QtCore import QSize, Signal, Slot
from qtpy.QtWidgets import QComboBox, QSizePolicy from qtpy.QtWidgets import QComboBox, QSizePolicy
from bec_widgets.utils.filter_io import ComboBoxFilterHandler, FilterIO from bec_widgets.utils.filter_io import ComboBoxFilterHandler, FilterIO
@ -21,6 +23,8 @@ class SignalComboBox(DeviceSignalInputBase, QComboBox):
ICON_NAME = "list_alt" ICON_NAME = "list_alt"
device_signal_changed = Signal(str)
def __init__( def __init__(
self, self,
parent=None, parent=None,
@ -42,13 +46,16 @@ class SignalComboBox(DeviceSignalInputBase, QComboBox):
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.setMinimumSize(QSize(100, 0)) self.setMinimumSize(QSize(100, 0))
signal_filter = signal_filter if not None else self.config.signal_filter # We do not consider the config that is passed here, this produced problems
# with QtDesigner, since config and input arguments may differ and resolve properly
# Implementing this logic and config recoverage is postponed.
self.currentTextChanged.connect(self.on_text_changed)
if signal_filter is not None: if signal_filter is not None:
self.set_filter(signal_filter) self.set_filter(signal_filter)
device = device if not None else self.config.device else:
self.set_filter([Kind.hinted, Kind.normal, Kind.config])
if device is not None: if device is not None:
self.set_device(device) self.set_device(device)
default = default if not None else self.config.default
if default is not None: if default is not None:
self.set_signal(default) self.set_signal(default)
@ -71,6 +78,24 @@ class SignalComboBox(DeviceSignalInputBase, QComboBox):
self.insertItem(0, "Hinted Signals") self.insertItem(0, "Hinted Signals")
self.model().item(0).setEnabled(False) self.model().item(0).setEnabled(False)
@Slot(str)
def on_text_changed(self, text: str):
"""Slot for text changed. If a device is selected and the signal is changed and valid it emits a signal.
For a positioner, the readback value has to be renamed to the device name.
Args:
text (str): Text in the combobox.
"""
if self.validate_device(self.device) is False:
return
if self.validate_signal(text) is False:
return
if text == "readback" and isinstance(self.get_device_object(self.device), Positioner):
device_signal = self.device
else:
device_signal = f"{self.device}_{text}"
self.device_signal_changed.emit(device_signal)
if __name__ == "__main__": # pragma: no cover if __name__ == "__main__": # pragma: no cover
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel

View File

@ -1,4 +1,5 @@
from qtpy.QtCore import QSize, Slot from ophyd import Kind
from qtpy.QtCore import QSize, Signal, Slot
from qtpy.QtGui import QPainter, QPaintEvent, QPen from qtpy.QtGui import QPainter, QPaintEvent, QPen
from qtpy.QtWidgets import QCompleter, QLineEdit, QSizePolicy from qtpy.QtWidgets import QCompleter, QLineEdit, QSizePolicy
@ -20,6 +21,8 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names. arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names.
""" """
device_signal_changed = Signal(str)
ICON_NAME = "vital_signs" ICON_NAME = "vital_signs"
def __init__( def __init__(
@ -33,9 +36,9 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
default: str | None = None, default: str | None = None,
arg_name: str | None = None, arg_name: str | None = None,
): ):
self._is_valid_input = False
super().__init__(client=client, config=config, gui_id=gui_id) super().__init__(client=client, config=config, gui_id=gui_id)
QLineEdit.__init__(self, parent=parent) QLineEdit.__init__(self, parent=parent)
self._is_valid_input = False
self._accent_colors = get_accent_colors() self._accent_colors = get_accent_colors()
self.completer = QCompleter(self) self.completer = QCompleter(self)
self.setCompleter(self.completer) self.setCompleter(self.completer)
@ -47,13 +50,15 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.setMinimumSize(QSize(100, 0)) self.setMinimumSize(QSize(100, 0))
signal_filter = signal_filter if not None else self.config.signal_filter # We do not consider the config that is passed here, this produced problems
# with QtDesigner, since config and input arguments may differ and resolve properly
# Implementing this logic and config recoverage is postponed.
if signal_filter is not None: if signal_filter is not None:
self.set_filter(signal_filter) self.set_filter(signal_filter)
device = device if not None else self.config.device else:
self.set_filter([Kind.hinted, Kind.normal, Kind.config])
if device is not None: if device is not None:
self.set_device(device) self.set_device(device)
default = default if not None else self.config.default
if default is not None: if default is not None:
self.set_signal(default) self.set_signal(default)
self.textChanged.connect(self.check_validity) self.textChanged.connect(self.check_validity)
@ -89,9 +94,10 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
""" """
Check if the current value is a valid device name. Check if the current value is a valid device name.
""" """
# i
if self.validate_signal(input_text) is True: if self.validate_signal(input_text) is True:
self._is_valid_input = True self._is_valid_input = True
if self.validate_device(self.device) is True:
self.device_signal_changed.emit(input_text)
else: else:
self._is_valid_input = False self._is_valid_input = False
self.update() self.update()

View File

@ -36,7 +36,7 @@ def test_device_input_base_init(device_input_base):
assert device_input_base.client is not None assert device_input_base.client is not None
assert isinstance(device_input_base, DeviceInputBase) assert isinstance(device_input_base, DeviceInputBase)
assert device_input_base.config.widget_class == "DeviceInputWidget" assert device_input_base.config.widget_class == "DeviceInputWidget"
assert device_input_base.config.device_filter is None assert device_input_base.config.device_filter == []
assert device_input_base.config.default is None assert device_input_base.config.default is None
assert device_input_base.devices == [] assert device_input_base.devices == []
@ -62,17 +62,15 @@ def test_device_input_base_set_device_filter(device_input_base):
def test_device_input_base_set_device_filter_error(device_input_base): def test_device_input_base_set_device_filter_error(device_input_base):
"""Test set_device_filter with Noneexisting class""" """Test set_device_filter with Noneexisting class. This should not raise. It writes a log message entry."""
with pytest.raises(ValueError) as excinfo: device_input_base.set_device_filter("NonExistingClass")
device_input_base.set_device_filter("NonExistingClass") assert device_input_base.device_filter == []
assert "Device filter NonExistingClass is not in the device list." in str(excinfo.value)
def test_device_input_base_set_default_device(device_input_base): def test_device_input_base_set_default_device(device_input_base):
"""Test setting the default device. Also tests the update_devices method.""" """Test setting the default device. Also tests the update_devices method."""
with pytest.raises(ValueError) as excinfo: device_input_base.set_device("samx")
device_input_base.set_device("samx") assert device_input_base.config.default == None
assert "Device samx is not in filtered selection." in str(excinfo.value)
device_input_base.set_device_filter(BECDeviceFilter.POSITIONER) device_input_base.set_device_filter(BECDeviceFilter.POSITIONER)
device_input_base.set_readout_priority_filter(ReadoutPriority.MONITORED) device_input_base.set_readout_priority_filter(ReadoutPriority.MONITORED)
device_input_base.set_device("samx") device_input_base.set_device("samx")
@ -99,17 +97,17 @@ def test_device_input_base_get_filters(device_input_base):
def test_device_input_base_properties(device_input_base): def test_device_input_base_properties(device_input_base):
"""Test setting the properties of the device input base.""" """Test setting the properties of the device input base."""
assert device_input_base.device_filter == [] assert device_input_base.device_filter == []
device_input_base.include_device = True device_input_base.filter_to_device = True
assert device_input_base.device_filter == [BECDeviceFilter.DEVICE] assert device_input_base.device_filter == [BECDeviceFilter.DEVICE]
device_input_base.include_positioner = True device_input_base.filter_to_positioner = True
assert device_input_base.device_filter == [BECDeviceFilter.DEVICE, BECDeviceFilter.POSITIONER] assert device_input_base.device_filter == [BECDeviceFilter.DEVICE, BECDeviceFilter.POSITIONER]
device_input_base.include_computed_signal = True device_input_base.filter_to_computed_signal = True
assert device_input_base.device_filter == [ assert device_input_base.device_filter == [
BECDeviceFilter.DEVICE, BECDeviceFilter.DEVICE,
BECDeviceFilter.POSITIONER, BECDeviceFilter.POSITIONER,
BECDeviceFilter.COMPUTED_SIGNAL, BECDeviceFilter.COMPUTED_SIGNAL,
] ]
device_input_base.include_signal = True device_input_base.filter_to_signal = True
assert device_input_base.device_filter == [ assert device_input_base.device_filter == [
BECDeviceFilter.DEVICE, BECDeviceFilter.DEVICE,
BECDeviceFilter.POSITIONER, BECDeviceFilter.POSITIONER,

View File

@ -16,21 +16,6 @@ def device_input_combobox(qtbot, mocked_client):
yield widget yield widget
@pytest.fixture
def device_input_combobox_with_config(qtbot, mocked_client):
config = {
"widget_class": "DeviceComboBox",
"gui_id": "test_gui_id",
"device_filter": [BECDeviceFilter.POSITIONER],
"default": "samx",
"arg_name": "test_arg_name",
}
widget = DeviceComboBox(client=mocked_client, config=config)
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
yield widget
@pytest.fixture @pytest.fixture
def device_input_combobox_with_kwargs(qtbot, mocked_client): def device_input_combobox_with_kwargs(qtbot, mocked_client):
widget = DeviceComboBox( widget = DeviceComboBox(
@ -72,13 +57,6 @@ def test_device_input_combobox_init(device_input_combobox):
] ]
def test_device_input_combobox_init_with_config(device_input_combobox_with_config):
assert device_input_combobox_with_config.config.gui_id == "test_gui_id"
assert device_input_combobox_with_config.config.device_filter == [BECDeviceFilter.POSITIONER]
assert device_input_combobox_with_config.config.default == "samx"
assert device_input_combobox_with_config.config.arg_name == "test_arg_name"
def test_device_input_combobox_init_with_kwargs(device_input_combobox_with_kwargs): def test_device_input_combobox_init_with_kwargs(device_input_combobox_with_kwargs):
assert device_input_combobox_with_kwargs.config.gui_id == "test_gui_id" assert device_input_combobox_with_kwargs.config.gui_id == "test_gui_id"
assert device_input_combobox_with_kwargs.config.device_filter == [BECDeviceFilter.POSITIONER] assert device_input_combobox_with_kwargs.config.device_filter == [BECDeviceFilter.POSITIONER]
@ -102,21 +80,6 @@ def device_input_line_edit(qtbot, mocked_client):
yield widget yield widget
@pytest.fixture
def device_input_line_edit_with_config(qtbot, mocked_client):
config = {
"widget_class": "DeviceLineEdit",
"gui_id": "test_gui_id",
"device_filter": [BECDeviceFilter.POSITIONER],
"default": "samx",
"arg_name": "test_arg_name",
}
widget = DeviceLineEdit(client=mocked_client, config=config)
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
yield widget
@pytest.fixture @pytest.fixture
def device_input_line_edit_with_kwargs(qtbot, mocked_client): def device_input_line_edit_with_kwargs(qtbot, mocked_client):
widget = DeviceLineEdit( widget = DeviceLineEdit(
@ -137,7 +100,13 @@ def test_device_input_line_edit_init(device_input_line_edit):
assert isinstance(device_input_line_edit, DeviceLineEdit) assert isinstance(device_input_line_edit, DeviceLineEdit)
assert device_input_line_edit.config.widget_class == "DeviceLineEdit" assert device_input_line_edit.config.widget_class == "DeviceLineEdit"
assert device_input_line_edit.config.device_filter == [] assert device_input_line_edit.config.device_filter == []
assert device_input_line_edit.config.readout_filter == [] assert device_input_line_edit.config.readout_filter == [
ReadoutPriority.MONITORED,
ReadoutPriority.BASELINE,
ReadoutPriority.ASYNC,
ReadoutPriority.CONTINUOUS,
ReadoutPriority.ON_REQUEST,
]
assert device_input_line_edit.config.default is None assert device_input_line_edit.config.default is None
assert device_input_line_edit.devices == [ assert device_input_line_edit.devices == [
"samx", "samx",
@ -160,13 +129,6 @@ def test_device_input_line_edit_init(device_input_line_edit):
] ]
def test_device_input_line_edit_init_with_config(device_input_line_edit_with_config):
assert device_input_line_edit_with_config.config.gui_id == "test_gui_id"
assert device_input_line_edit_with_config.config.device_filter == [BECDeviceFilter.POSITIONER]
assert device_input_line_edit_with_config.config.default == "samx"
assert device_input_line_edit_with_config.config.arg_name == "test_arg_name"
def test_device_input_line_edit_init_with_kwargs(device_input_line_edit_with_kwargs): def test_device_input_line_edit_init_with_kwargs(device_input_line_edit_with_kwargs):
assert device_input_line_edit_with_kwargs.config.gui_id == "test_gui_id" assert device_input_line_edit_with_kwargs.config.gui_id == "test_gui_id"
assert device_input_line_edit_with_kwargs.config.device_filter == [BECDeviceFilter.POSITIONER] assert device_input_line_edit_with_kwargs.config.device_filter == [BECDeviceFilter.POSITIONER]

View File

@ -1,12 +1,12 @@
from unittest import mock from unittest import mock
import pytest import pytest
from ophyd import Kind
from qtpy.QtWidgets import QWidget from qtpy.QtWidgets import QWidget
from bec_widgets.widgets.base_classes.device_signal_input_base import ( from bec_widgets.widgets.base_classes.device_input_base import BECDeviceFilter
BECSignalFilter, from bec_widgets.widgets.base_classes.device_signal_input_base import DeviceSignalInputBase
DeviceSignalInputBase, from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
)
from bec_widgets.widgets.signal_combobox.signal_combobox import SignalComboBox from bec_widgets.widgets.signal_combobox.signal_combobox import SignalComboBox
from bec_widgets.widgets.signal_line_edit.signal_line_edit import SignalLineEdit from bec_widgets.widgets.signal_line_edit.signal_line_edit import SignalLineEdit
@ -45,6 +45,19 @@ def device_signal_line_edit(qtbot, mocked_client):
yield widget yield widget
@pytest.fixture
def test_device_signal_combo(qtbot, mocked_client):
"""Fixture to create a SignalComboBox widget and a DeviceInputWidget widget"""
input = create_widget(
qtbot=qtbot,
widget=DeviceComboBox,
client=mocked_client,
device_filter=[BECDeviceFilter.POSITIONER],
)
signal = create_widget(qtbot=qtbot, widget=SignalComboBox, client=mocked_client)
yield input, signal
def test_device_signal_base_init(device_signal_base): def test_device_signal_base_init(device_signal_base):
"""Test if the DeviceSignalInputBase is initialized correctly""" """Test if the DeviceSignalInputBase is initialized correctly"""
assert device_signal_base._device is None assert device_signal_base._device is None
@ -58,15 +71,11 @@ def test_device_signal_base_init(device_signal_base):
def test_device_signal_qproperties(device_signal_base): def test_device_signal_qproperties(device_signal_base):
"""Test if the DeviceSignalInputBase has the correct QProperties""" """Test if the DeviceSignalInputBase has the correct QProperties"""
device_signal_base.include_config_signals = True device_signal_base.include_config_signals = True
assert device_signal_base._signal_filter == [BECSignalFilter.CONFIG] assert device_signal_base._signal_filter == [Kind.config]
device_signal_base.include_normal_signals = True device_signal_base.include_normal_signals = True
assert device_signal_base._signal_filter == [BECSignalFilter.CONFIG, BECSignalFilter.NORMAL] assert device_signal_base._signal_filter == [Kind.config, Kind.normal]
device_signal_base.include_hinted_signals = True device_signal_base.include_hinted_signals = True
assert device_signal_base._signal_filter == [ assert device_signal_base._signal_filter == [Kind.config, Kind.normal, Kind.hinted]
BECSignalFilter.CONFIG,
BECSignalFilter.NORMAL,
BECSignalFilter.HINTED,
]
def test_device_signal_set_device(device_signal_base): def test_device_signal_set_device(device_signal_base):