1
0
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:
2026-01-21 15:45:21 +01:00
committed by Klaus Wakonig
parent 43c311782d
commit d48b9d224f
3 changed files with 91 additions and 2 deletions

View File

@@ -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

View File

@@ -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(...).

View File

@@ -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"