mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
feat: add metadata widget to scan control
This commit is contained in:
@ -1,8 +1,16 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from bec_qthemes import material_icon
|
from bec_qthemes import material_icon
|
||||||
from PySide6.QtWidgets import QHBoxLayout, QSizePolicy, QToolButton
|
from qtpy.QtWidgets import (
|
||||||
from qtpy.QtWidgets import QFrame, QLabel, QLayout, QVBoxLayout, QWidget
|
QFrame,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QLayout,
|
||||||
|
QSizePolicy,
|
||||||
|
QToolButton,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from types import SimpleNamespace
|
from types import NoneType, SimpleNamespace
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
from bec_lib.endpoints import MessageEndpoints
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from qtpy.QtCore import Property, Signal, Slot
|
from qtpy.QtCore import Signal
|
||||||
from qtpy.QtGui import QColor
|
from qtpy.QtGui import QColor
|
||||||
from qtpy.QtWidgets import (
|
from qtpy.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
@ -18,12 +18,13 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
|
||||||
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
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
from bec_widgets.utils.colors import get_accent_colors
|
||||||
from bec_widgets.widgets.control.buttons.stop_button.stop_button import StopButton
|
from bec_widgets.widgets.control.buttons.stop_button.stop_button import StopButton
|
||||||
from bec_widgets.widgets.control.scan_control.scan_group_box import ScanGroupBox
|
from bec_widgets.widgets.control.scan_control.scan_group_box import ScanGroupBox
|
||||||
|
from bec_widgets.widgets.editors.scan_metadata.scan_metadata import ScanMetadata
|
||||||
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
||||||
|
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ class ScanControlConfig(ConnectionConfig):
|
|||||||
class ScanControl(BECWidget, QWidget):
|
class ScanControl(BECWidget, QWidget):
|
||||||
PLUGIN = True
|
PLUGIN = True
|
||||||
ICON_NAME = "tune"
|
ICON_NAME = "tune"
|
||||||
|
ARG_BOX_POSITION: int = 2
|
||||||
|
|
||||||
scan_started = Signal()
|
scan_started = Signal()
|
||||||
scan_selected = Signal(str)
|
scan_selected = Signal(str)
|
||||||
@ -83,6 +85,8 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
self.config.default_scan = default_scan
|
self.config.default_scan = default_scan
|
||||||
self.config.allowed_scans = allowed_scans
|
self.config.allowed_scans = allowed_scans
|
||||||
|
|
||||||
|
self._scan_metadata: dict | None = None
|
||||||
|
|
||||||
# Create and set main layout
|
# Create and set main layout
|
||||||
self._init_UI()
|
self._init_UI()
|
||||||
|
|
||||||
@ -152,6 +156,20 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
# Initialize scan selection
|
# Initialize scan selection
|
||||||
self.populate_scans()
|
self.populate_scans()
|
||||||
|
|
||||||
|
# Append metadata form
|
||||||
|
self._add_metadata_form()
|
||||||
|
|
||||||
|
self.layout.addStretch()
|
||||||
|
|
||||||
|
def _add_metadata_form(self):
|
||||||
|
self._metadata_form = ScanMetadata()
|
||||||
|
self.layout.addWidget(self._metadata_form)
|
||||||
|
self._metadata_form.update_with_new_scan(self.comboBox_scan_selection.currentText())
|
||||||
|
self.scan_selected.connect(self._metadata_form.update_with_new_scan)
|
||||||
|
self._metadata_form.metadata_updated.connect(self.update_scan_metadata)
|
||||||
|
self._metadata_form.metadata_cleared.connect(self.update_scan_metadata)
|
||||||
|
self._metadata_form.validate_form()
|
||||||
|
|
||||||
def populate_scans(self):
|
def populate_scans(self):
|
||||||
"""Populates the scan selection combo box with available scans from BEC session."""
|
"""Populates the scan selection combo box with available scans from BEC session."""
|
||||||
self.available_scans = self.client.connector.get(
|
self.available_scans = self.client.connector.get(
|
||||||
@ -176,8 +194,9 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
self.request_last_executed_scan_parameters()
|
self.request_last_executed_scan_parameters()
|
||||||
self.restore_scan_parameters(selected_scan_name)
|
self.restore_scan_parameters(selected_scan_name)
|
||||||
|
|
||||||
@Slot()
|
@SafeSlot()
|
||||||
def request_last_executed_scan_parameters(self):
|
@SafeSlot(bool)
|
||||||
|
def request_last_executed_scan_parameters(self, *_):
|
||||||
"""
|
"""
|
||||||
Requests the last executed scan parameters from BEC and restores them to the scan control widget.
|
Requests the last executed scan parameters from BEC and restores them to the scan control widget.
|
||||||
"""
|
"""
|
||||||
@ -211,7 +230,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
else:
|
else:
|
||||||
self.last_scan_found = False
|
self.last_scan_found = False
|
||||||
|
|
||||||
@Property(str)
|
@SafeProperty(str)
|
||||||
def current_scan(self):
|
def current_scan(self):
|
||||||
"""Returns the scan name for the currently selected scan."""
|
"""Returns the scan name for the currently selected scan."""
|
||||||
return self.comboBox_scan_selection.currentText()
|
return self.comboBox_scan_selection.currentText()
|
||||||
@ -227,7 +246,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
return
|
return
|
||||||
self.comboBox_scan_selection.setCurrentText(scan_name)
|
self.comboBox_scan_selection.setCurrentText(scan_name)
|
||||||
|
|
||||||
@Slot(str)
|
@SafeSlot(str)
|
||||||
def set_current_scan(self, scan_name: str):
|
def set_current_scan(self, scan_name: str):
|
||||||
"""Slot for setting the current scan to the given scan name.
|
"""Slot for setting the current scan to the given scan name.
|
||||||
|
|
||||||
@ -236,7 +255,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
"""
|
"""
|
||||||
self.current_scan = scan_name
|
self.current_scan = scan_name
|
||||||
|
|
||||||
@Property(bool)
|
@SafeProperty(bool)
|
||||||
def hide_arg_box(self):
|
def hide_arg_box(self):
|
||||||
"""Property to hide the argument box."""
|
"""Property to hide the argument box."""
|
||||||
if self.arg_box is None:
|
if self.arg_box is None:
|
||||||
@ -253,7 +272,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
if self.arg_box is not None:
|
if self.arg_box is not None:
|
||||||
self.arg_box.setVisible(not hide)
|
self.arg_box.setVisible(not hide)
|
||||||
|
|
||||||
@Property(bool)
|
@SafeProperty(bool)
|
||||||
def hide_kwarg_boxes(self):
|
def hide_kwarg_boxes(self):
|
||||||
"""Property to hide the keyword argument boxes."""
|
"""Property to hide the keyword argument boxes."""
|
||||||
if len(self.kwarg_boxes) == 0:
|
if len(self.kwarg_boxes) == 0:
|
||||||
@ -274,7 +293,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
for box in self.kwarg_boxes:
|
for box in self.kwarg_boxes:
|
||||||
box.setVisible(not hide)
|
box.setVisible(not hide)
|
||||||
|
|
||||||
@Property(bool)
|
@SafeProperty(bool)
|
||||||
def hide_scan_control_buttons(self):
|
def hide_scan_control_buttons(self):
|
||||||
"""Property to hide the scan control buttons."""
|
"""Property to hide the scan control buttons."""
|
||||||
return not self.button_run_scan.isVisible()
|
return not self.button_run_scan.isVisible()
|
||||||
@ -288,12 +307,40 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
"""
|
"""
|
||||||
self.show_scan_control_buttons(not hide)
|
self.show_scan_control_buttons(not hide)
|
||||||
|
|
||||||
@Slot(bool)
|
@SafeProperty(bool)
|
||||||
|
def hide_metadata(self):
|
||||||
|
"""Property to hide the metadata form."""
|
||||||
|
return not self._metadata_form.isVisible()
|
||||||
|
|
||||||
|
@hide_metadata.setter
|
||||||
|
def hide_metadata(self, hide: bool):
|
||||||
|
"""Setter for the hide_metadata property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hide(bool): Hide or show the metadata form.
|
||||||
|
"""
|
||||||
|
self._metadata_form.setVisible(not hide)
|
||||||
|
|
||||||
|
@SafeProperty(bool)
|
||||||
|
def hide_optional_metadata(self):
|
||||||
|
"""Property to hide the optional metadata form."""
|
||||||
|
return self._metadata_form.hide_optional_metadata
|
||||||
|
|
||||||
|
@hide_optional_metadata.setter
|
||||||
|
def hide_optional_metadata(self, hide: bool):
|
||||||
|
"""Setter for the hide_optional_metadata property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hide(bool): Hide or show the optional metadata form.
|
||||||
|
"""
|
||||||
|
self._metadata_form.hide_optional_metadata = hide
|
||||||
|
|
||||||
|
@SafeSlot(bool)
|
||||||
def show_scan_control_buttons(self, show: bool):
|
def show_scan_control_buttons(self, show: bool):
|
||||||
"""Shows or hides the scan control buttons."""
|
"""Shows or hides the scan control buttons."""
|
||||||
self.scan_control_group.setVisible(show)
|
self.scan_control_group.setVisible(show)
|
||||||
|
|
||||||
@Property(bool)
|
@SafeProperty(bool)
|
||||||
def hide_scan_selection_combobox(self):
|
def hide_scan_selection_combobox(self):
|
||||||
"""Property to hide the scan selection combobox."""
|
"""Property to hide the scan selection combobox."""
|
||||||
return not self.comboBox_scan_selection.isVisible()
|
return not self.comboBox_scan_selection.isVisible()
|
||||||
@ -307,12 +354,12 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
"""
|
"""
|
||||||
self.show_scan_selection_combobox(not hide)
|
self.show_scan_selection_combobox(not hide)
|
||||||
|
|
||||||
@Slot(bool)
|
@SafeSlot(bool)
|
||||||
def show_scan_selection_combobox(self, show: bool):
|
def show_scan_selection_combobox(self, show: bool):
|
||||||
"""Shows or hides the scan selection combobox."""
|
"""Shows or hides the scan selection combobox."""
|
||||||
self.scan_selection_group.setVisible(show)
|
self.scan_selection_group.setVisible(show)
|
||||||
|
|
||||||
@Slot(str)
|
@SafeSlot(str)
|
||||||
def scan_select(self, scan_name: str):
|
def scan_select(self, scan_name: str):
|
||||||
"""
|
"""
|
||||||
Slot for scan selection. Updates the scan control layout based on the selected scan.
|
Slot for scan selection. Updates the scan control layout based on the selected scan.
|
||||||
@ -335,7 +382,7 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
self.update()
|
self.update()
|
||||||
self.adjustSize()
|
self.adjustSize()
|
||||||
|
|
||||||
@Property(bool)
|
@SafeProperty(bool)
|
||||||
def hide_add_remove_buttons(self):
|
def hide_add_remove_buttons(self):
|
||||||
"""Property to hide the add_remove buttons."""
|
"""Property to hide the add_remove buttons."""
|
||||||
return self._hide_add_remove_buttons
|
return self._hide_add_remove_buttons
|
||||||
@ -358,10 +405,11 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
Args:
|
Args:
|
||||||
groups(list): List of dictionaries containing the gui_group information.
|
groups(list): List of dictionaries containing the gui_group information.
|
||||||
"""
|
"""
|
||||||
|
position = self.ARG_BOX_POSITION + (1 if self.arg_box is not None else 0)
|
||||||
for group in groups:
|
for group in groups:
|
||||||
box = ScanGroupBox(box_type="kwargs", config=group)
|
box = ScanGroupBox(box_type="kwargs", config=group)
|
||||||
box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
||||||
self.layout.addWidget(box)
|
self.layout.insertWidget(position + len(self.kwarg_boxes), box)
|
||||||
self.kwarg_boxes.append(box)
|
self.kwarg_boxes.append(box)
|
||||||
|
|
||||||
def add_arg_group(self, group: dict):
|
def add_arg_group(self, group: dict):
|
||||||
@ -374,9 +422,9 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
self.arg_box.device_selected.connect(self.emit_device_selected)
|
self.arg_box.device_selected.connect(self.emit_device_selected)
|
||||||
self.arg_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
self.arg_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
||||||
self.arg_box.hide_add_remove_buttons = self._hide_add_remove_buttons
|
self.arg_box.hide_add_remove_buttons = self._hide_add_remove_buttons
|
||||||
self.layout.addWidget(self.arg_box)
|
self.layout.insertWidget(self.ARG_BOX_POSITION, self.arg_box)
|
||||||
|
|
||||||
@Slot(str)
|
@SafeSlot(str)
|
||||||
def emit_device_selected(self, dev_names):
|
def emit_device_selected(self, dev_names):
|
||||||
"""
|
"""
|
||||||
Emit the signal to inform about selected device(s)
|
Emit the signal to inform about selected device(s)
|
||||||
@ -454,10 +502,20 @@ class ScanControl(BECWidget, QWidget):
|
|||||||
scan_params = ScanParameterConfig(name=scan_name, args=args, kwargs=kwargs)
|
scan_params = ScanParameterConfig(name=scan_name, args=args, kwargs=kwargs)
|
||||||
self.config.scans[scan_name] = scan_params
|
self.config.scans[scan_name] = scan_params
|
||||||
|
|
||||||
|
@SafeSlot(dict)
|
||||||
|
@SafeSlot(NoneType)
|
||||||
|
def update_scan_metadata(self, md: dict | None):
|
||||||
|
self._scan_metadata = md
|
||||||
|
if md is None:
|
||||||
|
self.button_run_scan.setEnabled(False)
|
||||||
|
else:
|
||||||
|
self.button_run_scan.setEnabled(True)
|
||||||
|
|
||||||
@SafeSlot(popup_error=True)
|
@SafeSlot(popup_error=True)
|
||||||
def run_scan(self):
|
def run_scan(self):
|
||||||
"""Starts the selected scan with the given parameters."""
|
"""Starts the selected scan with the given parameters."""
|
||||||
args, kwargs = self.get_scan_parameters()
|
args, kwargs = self.get_scan_parameters()
|
||||||
|
kwargs["metadata"] = self._scan_metadata
|
||||||
self.scan_args.emit(args)
|
self.scan_args.emit(args)
|
||||||
scan_function = getattr(self.scans, self.comboBox_scan_selection.currentText())
|
scan_function = getattr(self.scans, self.comboBox_scan_selection.currentText())
|
||||||
if callable(scan_function):
|
if callable(scan_function):
|
||||||
|
@ -2,13 +2,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from PySide6.QtWidgets import QSizePolicy
|
|
||||||
from qtpy.QtCore import QAbstractTableModel, QModelIndex, Qt, Signal # type: ignore
|
from qtpy.QtCore import QAbstractTableModel, QModelIndex, Qt, Signal # type: ignore
|
||||||
from qtpy.QtWidgets import (
|
from qtpy.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
QLabel,
|
|
||||||
QPushButton,
|
QPushButton,
|
||||||
|
QSizePolicy,
|
||||||
QTreeView,
|
QTreeView,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QWidget,
|
QWidget,
|
||||||
@ -111,6 +110,7 @@ class AdditionalMetadataTable(QWidget):
|
|||||||
self._table_view.setSizePolicy(
|
self._table_view.setSizePolicy(
|
||||||
QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
|
QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
|
||||||
)
|
)
|
||||||
|
self._table_view.setAlternatingRowColors(True)
|
||||||
self._layout.addWidget(self._table_view)
|
self._layout.addWidget(self._table_view)
|
||||||
|
|
||||||
self._buttons = QVBoxLayout()
|
self._buttons = QVBoxLayout()
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from types import NoneType
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from PySide6.QtWidgets import QHBoxLayout, QToolButton
|
|
||||||
from bec_lib.logger import bec_logger
|
from bec_lib.logger import bec_logger
|
||||||
from bec_lib.metadata_schema import get_metadata_schema_for_scan
|
from bec_lib.metadata_schema import get_metadata_schema_for_scan
|
||||||
from bec_qthemes import material_icon
|
from bec_qthemes import material_icon
|
||||||
from pydantic import Field, ValidationError
|
from pydantic import Field, ValidationError
|
||||||
|
from qtpy.QtCore import Signal # type: ignore
|
||||||
from qtpy.QtWidgets import (
|
from qtpy.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
QComboBox,
|
QComboBox,
|
||||||
QFrame,
|
|
||||||
QGridLayout,
|
QGridLayout,
|
||||||
|
QHBoxLayout,
|
||||||
QLabel,
|
QLabel,
|
||||||
QLayout,
|
QLayout,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
@ -20,7 +21,7 @@ from qtpy.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets.qt_utils.compact_popup import CompactPopupWidget
|
from bec_widgets.qt_utils.compact_popup import CompactPopupWidget
|
||||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.qt_utils.expandable_frame import ExpandableGroupFrame
|
from bec_widgets.qt_utils.expandable_frame import ExpandableGroupFrame
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.widgets.editors.scan_metadata._metadata_widgets import widget_from_type
|
from bec_widgets.widgets.editors.scan_metadata._metadata_widgets import widget_from_type
|
||||||
@ -39,6 +40,9 @@ class ScanMetadata(BECWidget, QWidget):
|
|||||||
metadata schema registry supplied in the plugin repo to find pydantic models
|
metadata schema registry supplied in the plugin repo to find pydantic models
|
||||||
associated with the scan type. Sets limits for numerical values if specified."""
|
associated with the scan type. Sets limits for numerical values if specified."""
|
||||||
|
|
||||||
|
metadata_updated = Signal(dict)
|
||||||
|
metadata_cleared = Signal(NoneType)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent=None,
|
parent=None,
|
||||||
@ -55,7 +59,7 @@ class ScanMetadata(BECWidget, QWidget):
|
|||||||
self._layout.setContentsMargins(0, 0, 0, 0)
|
self._layout.setContentsMargins(0, 0, 0, 0)
|
||||||
self.setLayout(self._layout)
|
self.setLayout(self._layout)
|
||||||
|
|
||||||
self._required_md_box = ExpandableGroupFrame("Required scan metadata")
|
self._required_md_box = ExpandableGroupFrame("Scan schema metadata")
|
||||||
self._layout.addWidget(self._required_md_box)
|
self._layout.addWidget(self._required_md_box)
|
||||||
self._required_md_box_layout = QHBoxLayout()
|
self._required_md_box_layout = QHBoxLayout()
|
||||||
self._required_md_box.set_layout(self._required_md_box_layout)
|
self._required_md_box.set_layout(self._required_md_box_layout)
|
||||||
@ -93,14 +97,20 @@ class ScanMetadata(BECWidget, QWidget):
|
|||||||
self.populate()
|
self.populate()
|
||||||
self.validate_form()
|
self.validate_form()
|
||||||
|
|
||||||
def validate_form(self, *_):
|
def validate_form(self, *_) -> bool:
|
||||||
|
"""validate the currently entered metadata against the pydantic schema.
|
||||||
|
If successful, returns on metadata_emitted and returns true.
|
||||||
|
Otherwise, emits on metadata_cleared and returns false."""
|
||||||
try:
|
try:
|
||||||
self._md_schema.model_validate(self.get_full_model_dict())
|
metadata_dict = self.get_full_model_dict()
|
||||||
|
self._md_schema.model_validate(metadata_dict)
|
||||||
self._validity.set_global_state("success")
|
self._validity.set_global_state("success")
|
||||||
self._validity_message.setText("No errors!")
|
self._validity_message.setText("No errors!")
|
||||||
|
self.metadata_updated.emit(metadata_dict)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
self._validity.set_global_state("emergency")
|
self._validity.set_global_state("emergency")
|
||||||
self._validity_message.setText(str(e))
|
self._validity_message.setText(str(e))
|
||||||
|
self.metadata_cleared.emit(None)
|
||||||
|
|
||||||
def get_full_model_dict(self):
|
def get_full_model_dict(self):
|
||||||
"""Get the entered metadata as a dict"""
|
"""Get the entered metadata as a dict"""
|
||||||
@ -153,6 +163,20 @@ class ScanMetadata(BECWidget, QWidget):
|
|||||||
self._md_grid_layout.setContentsMargins(0, 0, 0, 0)
|
self._md_grid_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
self._md_grid_layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
|
self._md_grid_layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
|
||||||
|
|
||||||
|
@SafeProperty(bool)
|
||||||
|
def hide_optional_metadata(self): # type: ignore
|
||||||
|
"""Property to hide the optional metadata table."""
|
||||||
|
return not self._additional_md_box.isVisible()
|
||||||
|
|
||||||
|
@hide_optional_metadata.setter
|
||||||
|
def hide_optional_metadata(self, hide: bool):
|
||||||
|
"""Setter for the hide_optional_metadata property.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hide(bool): Hide or show the optional metadata table.
|
||||||
|
"""
|
||||||
|
self._additional_md_box.setVisible(not hide)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
@ -7,6 +7,7 @@ from bec_lib.messages import AvailableResourceMessage, ScanQueueHistoryMessage,
|
|||||||
|
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
from bec_widgets.widgets.control.scan_control import ScanControl
|
from bec_widgets.widgets.control.scan_control import ScanControl
|
||||||
|
from bec_widgets.widgets.editors.scan_metadata._metadata_widgets import StrMetadataField
|
||||||
|
|
||||||
from .client_mocks import mocked_client
|
from .client_mocks import mocked_client
|
||||||
|
|
||||||
@ -403,7 +404,7 @@ def test_run_line_scan_with_parameters(scan_control, mocked_client):
|
|||||||
expected_device = mocked_client.device_manager.devices.samx
|
expected_device = mocked_client.device_manager.devices.samx
|
||||||
expected_args_list = [expected_device, args["start"], args["stop"]]
|
expected_args_list = [expected_device, args["start"], args["stop"]]
|
||||||
assert called_args == tuple(expected_args_list)
|
assert called_args == tuple(expected_args_list)
|
||||||
assert called_kwargs == kwargs
|
assert called_kwargs == kwargs | {"metadata": {"sample_name": ""}}
|
||||||
|
|
||||||
# Check the emitted signal
|
# Check the emitted signal
|
||||||
mock_slot.assert_called_once()
|
mock_slot.assert_called_once()
|
||||||
@ -479,7 +480,7 @@ def test_run_grid_scan_with_parameters(scan_control, mocked_client):
|
|||||||
args_row2["steps"],
|
args_row2["steps"],
|
||||||
]
|
]
|
||||||
assert called_args == tuple(expected_args_list)
|
assert called_args == tuple(expected_args_list)
|
||||||
assert called_kwargs == kwargs
|
assert called_kwargs == kwargs | {"metadata": {"sample_name": ""}}
|
||||||
|
|
||||||
# Check the emitted signal
|
# Check the emitted signal
|
||||||
mock_slot.assert_called_once()
|
mock_slot.assert_called_once()
|
||||||
@ -532,3 +533,22 @@ def test_get_scan_parameters_from_redis(scan_control, mocked_client):
|
|||||||
|
|
||||||
assert args == ["samx", 0.0, 2.0]
|
assert args == ["samx", 0.0, 2.0]
|
||||||
assert kwargs == {"steps": 10, "relative": False, "exp_time": 2.0, "burst_at_each_point": 1}
|
assert kwargs == {"steps": 10, "relative": False, "exp_time": 2.0, "burst_at_each_point": 1}
|
||||||
|
|
||||||
|
|
||||||
|
def test_scan_metadata_is_connected(scan_control):
|
||||||
|
assert scan_control._metadata_form._scan_name == "line_scan"
|
||||||
|
scan_control.comboBox_scan_selection.setCurrentText("grid_scan")
|
||||||
|
assert scan_control._metadata_form._scan_name == "grid_scan"
|
||||||
|
sample_name = scan_control._metadata_form._md_grid_layout.itemAtPosition(0, 1).widget()
|
||||||
|
assert isinstance(sample_name, StrMetadataField)
|
||||||
|
sample_name._main_widget.setText("Test Sample")
|
||||||
|
scan_control._metadata_form._additional_metadata._table_model._data = [
|
||||||
|
["test key 1", "test value 1"],
|
||||||
|
["test key 2", "test value 2"],
|
||||||
|
]
|
||||||
|
scan_control._metadata_form.validate_form()
|
||||||
|
assert scan_control._scan_metadata == {
|
||||||
|
"sample_name": "Test Sample",
|
||||||
|
"test key 1": "test value 1",
|
||||||
|
"test key 2": "test value 2",
|
||||||
|
}
|
||||||
|
@ -5,11 +5,9 @@ import pytest
|
|||||||
from bec_lib.metadata_schema import BasicScanMetadata
|
from bec_lib.metadata_schema import BasicScanMetadata
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from pydantic.types import Json
|
from pydantic.types import Json
|
||||||
from PySide6.QtCore import QItemSelectionModel, QModelIndex, QRect
|
from qtpy.QtCore import QItemSelectionModel, QPoint, Qt
|
||||||
from qtpy.QtCore import QPoint, Qt
|
|
||||||
from qtpy.QtWidgets import QCheckBox, QDoubleSpinBox, QLineEdit, QSpinBox, QWidget
|
|
||||||
|
|
||||||
from bec_widgets.widgets.editors.scan_metadata import AdditionalMetadataTableModel, ScanMetadata
|
from bec_widgets.widgets.editors.scan_metadata import ScanMetadata
|
||||||
from bec_widgets.widgets.editors.scan_metadata._metadata_widgets import (
|
from bec_widgets.widgets.editors.scan_metadata._metadata_widgets import (
|
||||||
BoolMetadataField,
|
BoolMetadataField,
|
||||||
FloatDecimalMetadataField,
|
FloatDecimalMetadataField,
|
||||||
@ -191,7 +189,8 @@ def test_additional_metadata_table_add_row(table: AdditionalMetadataTable):
|
|||||||
def test_additional_metadata_table_delete_row(table: AdditionalMetadataTable):
|
def test_additional_metadata_table_delete_row(table: AdditionalMetadataTable):
|
||||||
assert table._table_model.rowCount() == 3
|
assert table._table_model.rowCount() == 3
|
||||||
m = table._table_view.selectionModel()
|
m = table._table_view.selectionModel()
|
||||||
m.select(table._table_view.indexAt(QPoint(40, 30)), QItemSelectionModel.SelectionFlag.Select)
|
item = table._table_view.indexAt(QPoint(0, 0)).siblingAtRow(1)
|
||||||
|
m.select(item, QItemSelectionModel.SelectionFlag.Select)
|
||||||
table.delete_selected_rows()
|
table.delete_selected_rows()
|
||||||
assert table._table_model.rowCount() == 2
|
assert table._table_model.rowCount() == 2
|
||||||
assert list(table.dump_dict().keys()) == ["key1", "key3"]
|
assert list(table.dump_dict().keys()) == ["key1", "key3"]
|
||||||
|
Reference in New Issue
Block a user