mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
feat(bec_connector): export config to yaml
This commit is contained in:
@ -622,12 +622,6 @@ class BECFigure(RPCBase):
|
|||||||
list[BECPlotBase]: List of all widgets in the figure.
|
list[BECPlotBase]: List of all widgets in the figure.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def apply_config(self, config: "dict | FigureConfig"):
|
|
||||||
"""
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class BECImageItem(RPCBase):
|
class BECImageItem(RPCBase):
|
||||||
@property
|
@property
|
||||||
|
@ -47,9 +47,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
"d0": self.d0,
|
"d0": self.d0,
|
||||||
"d1": self.d1,
|
"d1": self.d1,
|
||||||
"d2": self.d2,
|
"d2": self.d2,
|
||||||
"fig0": self.fig0,
|
|
||||||
"fig1": self.fig1,
|
|
||||||
"fig2": self.fig2,
|
|
||||||
"plt": self.plt,
|
"plt": self.plt,
|
||||||
"bar": self.bar,
|
"bar": self.bar,
|
||||||
}
|
}
|
||||||
@ -108,6 +105,8 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
# curves for w1
|
# curves for w1
|
||||||
self.c1 = self.w1.get_config()
|
self.c1 = self.w1.get_config()
|
||||||
|
|
||||||
|
self.fig_c = self.figure.config_dict
|
||||||
|
|
||||||
def _init_dock(self):
|
def _init_dock(self):
|
||||||
|
|
||||||
self.d0 = self.dock.add_dock(name="dock_0")
|
self.d0 = self.dock.add_dock(name="dock_0")
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
# pylint: disable = no-name-in-module,missing-module-docstring
|
# pylint: disable = no-name-in-module,missing-module-docstring
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import yaml
|
||||||
from bec_lib.utils.import_utils import lazy_import_from
|
from bec_lib.utils.import_utils import lazy_import_from
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from qtpy.QtCore import QObject, QRunnable, QThreadPool, Signal
|
from qtpy.QtCore import QObject, QRunnable, QThreadPool, Signal
|
||||||
from qtpy.QtCore import Slot as pyqtSlot
|
from qtpy.QtCore import Slot as pyqtSlot
|
||||||
|
|
||||||
from bec_widgets.cli.rpc_register import RPCRegister
|
from bec_widgets.cli.rpc_register import RPCRegister
|
||||||
|
from bec_widgets.utils.yaml_dialog import load_yaml, load_yaml_gui, save_yaml, save_yaml_gui
|
||||||
|
|
||||||
BECDispatcher = lazy_import_from("bec_widgets.utils.bec_dispatcher", ("BECDispatcher",))
|
BECDispatcher = lazy_import_from("bec_widgets.utils.bec_dispatcher", ("BECDispatcher",))
|
||||||
|
|
||||||
@ -161,6 +165,60 @@ class BECConnector:
|
|||||||
"""
|
"""
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
def apply_config(self, config: dict, generate_new_id: bool = True) -> None:
|
||||||
|
"""
|
||||||
|
Apply the configuration to the widget.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config(dict): Configuration settings.
|
||||||
|
generate_new_id(bool): If True, generate a new GUI ID for the widget.
|
||||||
|
"""
|
||||||
|
self.config = ConnectionConfig(**config)
|
||||||
|
if generate_new_id is True:
|
||||||
|
gui_id = str(uuid.uuid4())
|
||||||
|
self.rpc_register.remove_rpc(self)
|
||||||
|
self.set_gui_id(gui_id)
|
||||||
|
self.rpc_register.add_rpc(self)
|
||||||
|
else:
|
||||||
|
self.gui_id = self.config.gui_id
|
||||||
|
|
||||||
|
def load_config(self, path: str | None = None, gui: bool = False):
|
||||||
|
"""
|
||||||
|
Load the configuration of the widget from YAML.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(str): Path to the configuration file for non-GUI dialog mode.
|
||||||
|
gui(bool): If True, use the GUI dialog to load the configuration file.
|
||||||
|
"""
|
||||||
|
if gui is True:
|
||||||
|
config = load_yaml_gui(self)
|
||||||
|
else:
|
||||||
|
config = load_yaml(path)
|
||||||
|
|
||||||
|
if config is not None:
|
||||||
|
if config.get("widget_class") != self.__class__.__name__:
|
||||||
|
raise ValueError(
|
||||||
|
f"Configuration file is not for {self.__class__.__name__}. Got configuration for {config.get('widget_class')}."
|
||||||
|
)
|
||||||
|
self.apply_config(config)
|
||||||
|
|
||||||
|
def save_config(self, path: str | None = None, gui: bool = False):
|
||||||
|
"""
|
||||||
|
Save the configuration of the widget to YAML.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(str): Path to save the configuration file for non-GUI dialog mode.
|
||||||
|
gui(bool): If True, use the GUI dialog to save the configuration file.
|
||||||
|
"""
|
||||||
|
if gui is True:
|
||||||
|
save_yaml_gui(self, self.config_dict)
|
||||||
|
else:
|
||||||
|
if path is None:
|
||||||
|
path = os.getcwd()
|
||||||
|
file_path = os.path.join(path, f"{self.__class__.__name__}_config.yaml")
|
||||||
|
|
||||||
|
save_yaml(file_path, self.config_dict)
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def set_gui_id(self, gui_id: str) -> None:
|
def set_gui_id(self, gui_id: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -6,7 +6,7 @@ import yaml
|
|||||||
from qtpy.QtWidgets import QFileDialog
|
from qtpy.QtWidgets import QFileDialog
|
||||||
|
|
||||||
|
|
||||||
def load_yaml(instance) -> Union[dict, None]:
|
def load_yaml_gui(instance) -> Union[dict, None]:
|
||||||
"""
|
"""
|
||||||
Load YAML file from disk.
|
Load YAML file from disk.
|
||||||
|
|
||||||
@ -20,12 +20,25 @@ def load_yaml(instance) -> Union[dict, None]:
|
|||||||
file_path, _ = QFileDialog.getOpenFileName(
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
instance, "Load Settings", "", "YAML Files (*.yaml *.yml);;All Files (*)", options=options
|
instance, "Load Settings", "", "YAML Files (*.yaml *.yml);;All Files (*)", options=options
|
||||||
)
|
)
|
||||||
|
config = load_yaml(file_path)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml(file_path: str) -> Union[dict, None]:
|
||||||
|
"""
|
||||||
|
Load YAML file from disk.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path(str): Path to the YAML file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Configuration data loaded from the YAML file.
|
||||||
|
"""
|
||||||
if not file_path:
|
if not file_path:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(file_path, "r") as file:
|
with open(file_path, "r") as file:
|
||||||
config = yaml.safe_load(file)
|
config = yaml.load(file, Loader=yaml.FullLoader)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@ -38,7 +51,7 @@ def load_yaml(instance) -> Union[dict, None]:
|
|||||||
print(f"An error occurred while loading the settings from {file_path}: {e}")
|
print(f"An error occurred while loading the settings from {file_path}: {e}")
|
||||||
|
|
||||||
|
|
||||||
def save_yaml(instance, config: dict) -> None:
|
def save_yaml_gui(instance, config: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Save YAML file to disk.
|
Save YAML file to disk.
|
||||||
|
|
||||||
@ -51,6 +64,17 @@ def save_yaml(instance, config: dict) -> None:
|
|||||||
instance, "Save Settings", "", "YAML Files (*.yaml *.yml);;All Files (*)", options=options
|
instance, "Save Settings", "", "YAML Files (*.yaml *.yml);;All Files (*)", options=options
|
||||||
)
|
)
|
||||||
|
|
||||||
|
save_yaml(file_path, config)
|
||||||
|
|
||||||
|
|
||||||
|
def save_yaml(file_path: str, config: dict) -> None:
|
||||||
|
"""
|
||||||
|
Save YAML file to disk.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path(str): Path to the YAML file.
|
||||||
|
config(dict): Configuration data to be saved.
|
||||||
|
"""
|
||||||
if not file_path:
|
if not file_path:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@ -123,7 +123,9 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|||||||
"clear_all",
|
"clear_all",
|
||||||
"get_all_rpc",
|
"get_all_rpc",
|
||||||
"widget_list",
|
"widget_list",
|
||||||
"apply_config",
|
# "apply_config",
|
||||||
|
# "save_config",
|
||||||
|
# "load_config",
|
||||||
]
|
]
|
||||||
subplot_map = {
|
subplot_map = {
|
||||||
"PlotBase": BECPlotBase,
|
"PlotBase": BECPlotBase,
|
||||||
@ -173,7 +175,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|||||||
"Key must be a string (widget id) or a tuple of two integers (grid coordinates)"
|
"Key must be a string (widget id) or a tuple of two integers (grid coordinates)"
|
||||||
)
|
)
|
||||||
|
|
||||||
def apply_config(self, config: dict | FigureConfig):
|
def apply_config(self, config: dict | FigureConfig): # ,generate_new_id: bool = False):
|
||||||
if isinstance(config, dict):
|
if isinstance(config, dict):
|
||||||
try:
|
try:
|
||||||
config = FigureConfig(**config)
|
config = FigureConfig(**config)
|
||||||
|
@ -7,7 +7,7 @@ import pytest
|
|||||||
import yaml
|
import yaml
|
||||||
from qtpy.QtWidgets import QPushButton, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QPushButton, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.utils.yaml_dialog import load_yaml, save_yaml
|
from bec_widgets.utils.yaml_dialog import load_yaml_gui, save_yaml_gui
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
@ -33,7 +33,7 @@ def test_load_yaml(qtbot, example_widget):
|
|||||||
temp_file.write(b"name: test\nvalue: 42")
|
temp_file.write(b"name: test\nvalue: 42")
|
||||||
|
|
||||||
def load_yaml_wrapper():
|
def load_yaml_wrapper():
|
||||||
config = load_yaml(example_widget)
|
config = load_yaml_gui(example_widget)
|
||||||
if config:
|
if config:
|
||||||
example_widget.config.update(config)
|
example_widget.config.update(config)
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ def test_load_yaml(qtbot, example_widget):
|
|||||||
|
|
||||||
def test_load_yaml_file_not_found(qtbot, example_widget, capsys):
|
def test_load_yaml_file_not_found(qtbot, example_widget, capsys):
|
||||||
def load_yaml_wrapper():
|
def load_yaml_wrapper():
|
||||||
config = load_yaml(example_widget)
|
config = load_yaml_gui(example_widget)
|
||||||
if config:
|
if config:
|
||||||
example_widget.config.update(config)
|
example_widget.config.update(config)
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ def test_load_yaml_general_exception(qtbot, example_widget, capsys, monkeypatch)
|
|||||||
monkeypatch.setattr("builtins.open", mock_open)
|
monkeypatch.setattr("builtins.open", mock_open)
|
||||||
|
|
||||||
def load_yaml_wrapper():
|
def load_yaml_wrapper():
|
||||||
config = load_yaml(example_widget)
|
config = load_yaml_gui(example_widget)
|
||||||
if config:
|
if config:
|
||||||
example_widget.config.update(config)
|
example_widget.config.update(config)
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ def test_load_yaml_permission_error(qtbot, example_widget, monkeypatch, capsys):
|
|||||||
os.chmod(temp_file_path, 0o000) # Remove permissions
|
os.chmod(temp_file_path, 0o000) # Remove permissions
|
||||||
|
|
||||||
def load_yaml_wrapper():
|
def load_yaml_wrapper():
|
||||||
config = load_yaml(example_widget)
|
config = load_yaml_gui(example_widget)
|
||||||
if config:
|
if config:
|
||||||
example_widget.config.update(config)
|
example_widget.config.update(config)
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ def test_load_yaml_invalid_yaml(qtbot, example_widget, capsys):
|
|||||||
temp_file.write(b"\tinvalid_yaml: [unbalanced_brackets: ]")
|
temp_file.write(b"\tinvalid_yaml: [unbalanced_brackets: ]")
|
||||||
|
|
||||||
def load_yaml_wrapper():
|
def load_yaml_wrapper():
|
||||||
config = load_yaml(example_widget)
|
config = load_yaml_gui(example_widget)
|
||||||
if config:
|
if config:
|
||||||
example_widget.config.update(config)
|
example_widget.config.update(config)
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ def test_save_yaml(qtbot, example_widget):
|
|||||||
example_widget.saved_config = {"name": "test", "value": 42}
|
example_widget.saved_config = {"name": "test", "value": 42}
|
||||||
|
|
||||||
def save_yaml_wrapper():
|
def save_yaml_wrapper():
|
||||||
save_yaml(example_widget, example_widget.saved_config)
|
save_yaml_gui(example_widget, example_widget.saved_config)
|
||||||
|
|
||||||
example_widget.export_button.clicked.connect(save_yaml_wrapper)
|
example_widget.export_button.clicked.connect(save_yaml_wrapper)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user