mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-03-04 16:02:51 +01:00
feat: add export and load settings methods to BECConnector; add SafeProperty safe getter flag
This commit is contained in:
@@ -12,7 +12,7 @@ import shiboken6 as shb
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.utils.import_utils import lazy_import_from
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from qtpy.QtCore import QObject, QRunnable, QThreadPool, QTimer, Signal
|
||||
from qtpy.QtCore import Property, QObject, QRunnable, QThreadPool, QTimer, Signal
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
||||
@@ -480,6 +480,62 @@ class BECConnector:
|
||||
else:
|
||||
return self.config
|
||||
|
||||
def export_settings(self) -> dict:
|
||||
"""
|
||||
Export the settings of the widget as dict.
|
||||
|
||||
Returns:
|
||||
dict: The exported settings of the widget.
|
||||
"""
|
||||
|
||||
# We first get all qproperties that were defined in a bec_widgets class
|
||||
objs = self._get_bec_meta_objects()
|
||||
settings = {}
|
||||
for prop_name in objs.keys():
|
||||
try:
|
||||
prop_value = getattr(self, prop_name)
|
||||
settings[prop_name] = prop_value
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Could not export property '{prop_name}' from '{self.__class__.__name__}': {e}"
|
||||
)
|
||||
return settings
|
||||
|
||||
def load_settings(self, settings: dict) -> None:
|
||||
"""
|
||||
Load the settings of the widget from dict.
|
||||
|
||||
Args:
|
||||
settings (dict): The settings to load into the widget.
|
||||
"""
|
||||
objs = self._get_bec_meta_objects()
|
||||
for prop_name, prop_value in settings.items():
|
||||
if prop_name in objs:
|
||||
try:
|
||||
setattr(self, prop_name, prop_value)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Could not load property '{prop_name}' into '{self.__class__.__name__}': {e}"
|
||||
)
|
||||
|
||||
def _get_bec_meta_objects(self) -> dict:
|
||||
"""
|
||||
Get BEC meta objects for the widget.
|
||||
|
||||
Returns:
|
||||
dict: BEC meta objects.
|
||||
"""
|
||||
if not isinstance(self, QObject):
|
||||
return {}
|
||||
objects = {}
|
||||
for name, attr in vars(self.__class__).items():
|
||||
if isinstance(attr, Property):
|
||||
# Check if the property is a SafeProperty
|
||||
is_safe_property = getattr(attr.fget, "__is_safe_getter__", False)
|
||||
if is_safe_property:
|
||||
objects[name] = attr
|
||||
return objects
|
||||
|
||||
|
||||
# --- Example usage of BECConnector: running a simple task ---
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
@@ -53,6 +53,8 @@ def SafeProperty(prop_type, *prop_args, popup_error: bool = False, default=None,
|
||||
logger.error(f"SafeProperty error in GETTER of '{prop_name}':\n{error_msg}")
|
||||
return default
|
||||
|
||||
safe_getter.__is_safe_getter__ = True # type: ignore[attr-defined]
|
||||
|
||||
class PropertyWrapper:
|
||||
"""
|
||||
Intermediate wrapper used so that the user can optionally chain .setter(...).
|
||||
|
||||
@@ -3,9 +3,10 @@ import time
|
||||
|
||||
import pytest
|
||||
from qtpy.QtCore import QObject
|
||||
from qtpy.QtWidgets import QApplication
|
||||
from qtpy.QtWidgets import QApplication, QWidget
|
||||
|
||||
from bec_widgets.utils import BECConnector
|
||||
from bec_widgets.utils.error_popups import SafeProperty
|
||||
from bec_widgets.utils.error_popups import SafeSlot as Slot
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
@@ -131,3 +132,33 @@ def test_bec_connector_change_object_name(bec_connector):
|
||||
# Verify that the object with the previous name is no longer registered
|
||||
all_objects = bec_connector.rpc_register.list_all_connections().values()
|
||||
assert not any(obj.objectName() == previous_name for obj in all_objects)
|
||||
|
||||
|
||||
def test_bec_connector_export_settings():
|
||||
|
||||
class MyWidget(BECConnector, QWidget):
|
||||
def __init__(self, parent=None, client=None, **kwargs):
|
||||
super().__init__(parent=parent, client=client, **kwargs)
|
||||
self.setWindowTitle("My Widget")
|
||||
self._my_str_property = "default"
|
||||
|
||||
@SafeProperty(str)
|
||||
def my_str_property(self) -> str:
|
||||
return self._my_str_property
|
||||
|
||||
@my_str_property.setter
|
||||
def my_str_property(self, value: str):
|
||||
self._my_str_property = value
|
||||
|
||||
@property
|
||||
def my_int_property(self) -> int:
|
||||
return 42
|
||||
|
||||
widget = MyWidget(client=mocked_client)
|
||||
out = widget.export_settings()
|
||||
assert len(out) == 1
|
||||
assert out["my_str_property"] == "default"
|
||||
|
||||
config = {"my_str_property": "new_value"}
|
||||
widget.load_settings(config)
|
||||
assert widget.my_str_property == "new_value"
|
||||
|
||||
Reference in New Issue
Block a user