mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
fix: (#612) fix additional MD form
makes sure the form is validated on any changes of the additional metadata table model so that they are propagated to the scan control widget even when nothing is entered in the standard form
This commit is contained in:
@ -53,6 +53,7 @@ class DictBackedTableModel(QAbstractTableModel):
|
|||||||
if value in self._disallowed_keys or value in self._other_keys(index.row()):
|
if value in self._disallowed_keys or value in self._other_keys(index.row()):
|
||||||
return False
|
return False
|
||||||
self._data[index.row()][index.column()] = str(value)
|
self._data[index.row()][index.column()] = str(value)
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -109,6 +110,7 @@ class DictBackedTableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
class DictBackedTable(QWidget):
|
class DictBackedTable(QWidget):
|
||||||
delete_rows = Signal(list)
|
delete_rows = Signal(list)
|
||||||
|
data_updated = Signal()
|
||||||
|
|
||||||
def __init__(self, initial_data: list[list[str]]):
|
def __init__(self, initial_data: list[list[str]]):
|
||||||
"""Widget which uses a DictBackedTableModel to display an editable table
|
"""Widget which uses a DictBackedTableModel to display an editable table
|
||||||
@ -141,6 +143,11 @@ class DictBackedTable(QWidget):
|
|||||||
self._add_button.clicked.connect(self._table_model.add_row)
|
self._add_button.clicked.connect(self._table_model.add_row)
|
||||||
self._remove_button.clicked.connect(self.delete_selected_rows)
|
self._remove_button.clicked.connect(self.delete_selected_rows)
|
||||||
self.delete_rows.connect(self._table_model.delete_rows)
|
self.delete_rows.connect(self._table_model.delete_rows)
|
||||||
|
self._table_model.dataChanged.connect(self._emit_data_updated)
|
||||||
|
|
||||||
|
def _emit_data_updated(self, *args, **kwargs):
|
||||||
|
"""Just to swallow the args"""
|
||||||
|
self.data_updated.emit()
|
||||||
|
|
||||||
def delete_selected_rows(self):
|
def delete_selected_rows(self):
|
||||||
"""Delete rows which are part of the selection model"""
|
"""Delete rows which are part of the selection model"""
|
||||||
|
@ -43,6 +43,7 @@ class ScanMetadata(PydanticModelForm):
|
|||||||
self._additional_metadata = DictBackedTable(initial_extras or [])
|
self._additional_metadata = DictBackedTable(initial_extras or [])
|
||||||
self._scan_name = scan_name or ""
|
self._scan_name = scan_name or ""
|
||||||
self._md_schema = get_metadata_schema_for_scan(self._scan_name)
|
self._md_schema = get_metadata_schema_for_scan(self._scan_name)
|
||||||
|
self._additional_metadata.data_updated.connect(self.validate_form)
|
||||||
|
|
||||||
super().__init__(parent=parent, metadata_model=self._md_schema, client=client, **kwargs)
|
super().__init__(parent=parent, metadata_model=self._md_schema, client=client, **kwargs)
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
||||||
from unittest.mock import MagicMock
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
from bec_lib.endpoints import MessageEndpoints
|
||||||
from bec_lib.messages import AvailableResourceMessage, ScanQueueHistoryMessage, ScanQueueMessage
|
from bec_lib.messages import AvailableResourceMessage, ScanQueueHistoryMessage, ScanQueueMessage
|
||||||
|
from qtpy.QtCore import QModelIndex, QPoint, Qt
|
||||||
|
|
||||||
from bec_widgets.utils.forms_from_types.items import StrMetadataField
|
from bec_widgets.utils.forms_from_types.items import StrMetadataField
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
@ -540,6 +542,29 @@ def test_get_scan_parameters_from_redis(scan_control, mocked_client):
|
|||||||
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}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_MD = {"sample_name": "Test Sample", "test key 1": "test value 1", "test key 2": "test value 2"}
|
||||||
|
TEST_TABLE_ENTRY = [["test key 1", "test value 1"], ["test key 2", "test value 2"]]
|
||||||
|
|
||||||
|
|
||||||
|
def test_scan_metadata_is_updated_even_without_default_form_changes(
|
||||||
|
scan_control: ScanControl, qtbot
|
||||||
|
):
|
||||||
|
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"
|
||||||
|
scan_control._metadata_form._additional_metadata._add_button.click()
|
||||||
|
qtbot.wait(100)
|
||||||
|
table_model = scan_control._metadata_form._additional_metadata._table_model
|
||||||
|
model_key = table_model.index(0, 0, QModelIndex())
|
||||||
|
table_model.setData(model_key, "test key 1", Qt.EditRole)
|
||||||
|
model_value = model_key.siblingAtColumn(1)
|
||||||
|
table_model.setData(model_value, "test value 1", Qt.EditRole)
|
||||||
|
assert scan_control._metadata_form._additional_metadata.dump_dict() == {
|
||||||
|
"test key 1": "test value 1"
|
||||||
|
}
|
||||||
|
assert scan_control._scan_metadata == {"sample_name": "", "test key 1": "test value 1"}
|
||||||
|
|
||||||
|
|
||||||
def test_scan_metadata_is_connected(scan_control):
|
def test_scan_metadata_is_connected(scan_control):
|
||||||
assert scan_control._metadata_form._scan_name == "line_scan"
|
assert scan_control._metadata_form._scan_name == "line_scan"
|
||||||
scan_control.comboBox_scan_selection.setCurrentText("grid_scan")
|
scan_control.comboBox_scan_selection.setCurrentText("grid_scan")
|
||||||
@ -548,16 +573,28 @@ def test_scan_metadata_is_connected(scan_control):
|
|||||||
assert isinstance(sample_name, StrMetadataField)
|
assert isinstance(sample_name, StrMetadataField)
|
||||||
sample_name._main_widget.setText("Test Sample")
|
sample_name._main_widget.setText("Test Sample")
|
||||||
|
|
||||||
scan_control._metadata_form._additional_metadata._table_model._data = [
|
scan_control._metadata_form._additional_metadata._table_model._data = TEST_TABLE_ENTRY
|
||||||
["test key 1", "test value 1"],
|
|
||||||
["test key 2", "test value 2"],
|
|
||||||
]
|
|
||||||
scan_control._metadata_form.validate_form()
|
scan_control._metadata_form.validate_form()
|
||||||
assert scan_control._scan_metadata == {
|
assert scan_control._scan_metadata == TEST_MD
|
||||||
"sample_name": "Test Sample",
|
|
||||||
"test key 1": "test value 1",
|
|
||||||
"test key 2": "test value 2",
|
def test_scan_metadata_is_passed_to_scan_function(scan_control: ScanControl):
|
||||||
}
|
scan_control.comboBox_scan_selection.setCurrentText("grid_scan")
|
||||||
|
|
||||||
|
sample_name = scan_control._metadata_form._form_grid.layout().itemAtPosition(0, 1).widget()
|
||||||
|
sample_name._main_widget.setText("Test Sample")
|
||||||
|
scan_control._metadata_form._additional_metadata._table_model._data = TEST_TABLE_ENTRY
|
||||||
|
scan_control._metadata_form.validate_form()
|
||||||
|
|
||||||
|
assert scan_control._scan_metadata == TEST_MD
|
||||||
|
|
||||||
|
scans = SimpleNamespace(grid_scan=MagicMock())
|
||||||
|
with (
|
||||||
|
patch.object(scan_control, "scans", scans),
|
||||||
|
patch.object(scan_control, "get_scan_parameters", lambda: ((), {})),
|
||||||
|
):
|
||||||
|
scan_control.run_scan()
|
||||||
|
scans.grid_scan.assert_called_once_with(metadata=TEST_MD)
|
||||||
|
|
||||||
|
|
||||||
def test_restore_parameters_with_fewer_arg_bundles(scan_control, qtbot):
|
def test_restore_parameters_with_fewer_arg_bundles(scan_control, qtbot):
|
||||||
|
Reference in New Issue
Block a user