From ad0d78968515496aba2f169b5a548af9bb5e6652 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Tue, 8 Apr 2025 15:46:28 +0200 Subject: [PATCH] WIP refactor name and _name changed to object_name --- bec_widgets/cli/client_utils.py | 12 ++++++------ bec_widgets/cli/rpc/rpc_base.py | 19 ++++++++++++------- bec_widgets/cli/rpc/rpc_register.py | 2 +- bec_widgets/utils/bec_connector.py | 9 ++++++--- bec_widgets/utils/cli_server.py | 4 ++-- bec_widgets/widgets/containers/dock/dock.py | 15 +++++++-------- .../widgets/containers/dock/dock_area.py | 12 +++++++----- tests/unit_tests/test_rpc_base.py | 2 +- 8 files changed, 42 insertions(+), 33 deletions(-) diff --git a/bec_widgets/cli/client_utils.py b/bec_widgets/cli/client_utils.py index adfe578b..af676c1b 100644 --- a/bec_widgets/cli/client_utils.py +++ b/bec_widgets/cli/client_utils.py @@ -224,7 +224,7 @@ class BECGuiClient(RPCBase): @property def launcher(self) -> RPCBase: """The launcher object.""" - return RPCBase(gui_id=f"{self._gui_id}:launcher", parent=self, name="launcher") + return RPCBase(gui_id=f"{self._gui_id}:launcher", parent=self, object_name="launcher") def connect_to_gui_server(self, gui_id: str) -> None: """Connect to a GUI server""" @@ -251,7 +251,7 @@ class BECGuiClient(RPCBase): @property def windows(self) -> dict: """Dictionary with dock areas in the GUI.""" - return {widget._name: widget for widget in self._top_level.values()} + return {widget.object_name: widget for widget in self._top_level.values()} @property def window_list(self) -> list: @@ -469,7 +469,7 @@ class BECGuiClient(RPCBase): self._ipython_registry.pop(gui_id) removed_widgets = [ - widget._name for widget in self._top_level.values() if widget._is_deleted() + widget.object_name for widget in self._top_level.values() if widget._is_deleted() ] for widget_name in removed_widgets: @@ -479,7 +479,7 @@ class BECGuiClient(RPCBase): delattr(self, widget_name) for gui_id, widget_ref in top_level_widgets.items(): - setattr(self, widget_ref._name, widget_ref) + setattr(self, widget_ref.object_name, widget_ref) self._top_level = top_level_widgets @@ -490,7 +490,7 @@ class BECGuiClient(RPCBase): state (dict): The state of the widget from the _server_registry. parent (object): The parent object. """ - name = state["name"] + object_name = state["object_name"] gui_id = state["gui_id"] if state["widget_class"] in IGNORE_WIDGETS: return @@ -499,7 +499,7 @@ class BECGuiClient(RPCBase): return obj = self._ipython_registry.get(gui_id) if obj is None: - widget = widget_class(gui_id=gui_id, name=name, parent=parent) + widget = widget_class(gui_id=gui_id, object_name=object_name, parent=parent) self._ipython_registry[gui_id] = widget else: widget = obj diff --git a/bec_widgets/cli/rpc/rpc_base.py b/bec_widgets/cli/rpc/rpc_base.py index ba64e635..029e6c4c 100644 --- a/bec_widgets/cli/rpc/rpc_base.py +++ b/bec_widgets/cli/rpc/rpc_base.py @@ -91,7 +91,7 @@ class RPCReference: def __init__(self, registry: dict, gui_id: str) -> None: self._registry = registry self._gui_id = gui_id - self._name = self._registry[self._gui_id]._name + self.object_name = self._registry[self._gui_id].object_name @check_for_deleted_widget def __getattr__(self, name): @@ -127,13 +127,13 @@ class RPCBase: self, gui_id: str | None = None, config: dict | None = None, - name: str | None = None, + object_name: str | None = None, parent=None, ) -> None: self._client = BECClient() # BECClient is a singleton; here, we simply get the instance self._config = config if config is not None else {} self._gui_id = gui_id if gui_id is not None else str(uuid.uuid4())[:5] - self._name = name if name is not None else str(uuid.uuid4())[:5] + self.object_name = object_name if object_name is not None else str(uuid.uuid4())[:5] self._parent = parent self._msg_wait_event = threading.Event() self._rpc_response = None @@ -156,7 +156,7 @@ class RPCBase: """ Get the widget name. """ - return self._name + return self.object_name @property def _root(self) -> BECGuiClient: @@ -276,12 +276,17 @@ class RPCBase: for key, val in self._root._server_registry.items(): parent_id = val["config"].get("parent_id") if parent_id == self._gui_id: - references[key] = {"gui_id": val["config"]["gui_id"], "name": val["name"]} + references[key] = { + "gui_id": val["config"]["gui_id"], + "object_name": val["object_name"], + } removed_references = set(self._rpc_references.keys()) - set(references.keys()) for key in removed_references: - delattr(self, self._rpc_references[key]["name"]) + delattr(self, self._rpc_references[key]["object_name"]) self._rpc_references = references for key, val in references.items(): setattr( - self, val["name"], RPCReference(self._root._ipython_registry, val["gui_id"]) + self, + val["object_name"], + RPCReference(self._root._ipython_registry, val["gui_id"]), ) diff --git a/bec_widgets/cli/rpc/rpc_register.py b/bec_widgets/cli/rpc/rpc_register.py index 09bc550d..ee9a69a5 100644 --- a/bec_widgets/cli/rpc/rpc_register.py +++ b/bec_widgets/cli/rpc/rpc_register.py @@ -123,7 +123,7 @@ class RPCRegister: # This retrieves any rpc objects that are subclass of BECWidget, # i.e. curve and image items are excluded widgets = [rpc for rpc in self._rpc_register.values() if isinstance(rpc, cls)] - return [widget._name for widget in widgets] + return [widget.object_name for widget in widgets] def broadcast(self): """ diff --git a/bec_widgets/utils/bec_connector.py b/bec_widgets/utils/bec_connector.py index 33aa4317..86e4cb6a 100644 --- a/bec_widgets/utils/bec_connector.py +++ b/bec_widgets/utils/bec_connector.py @@ -88,6 +88,7 @@ class BECConnector: parent_id: str | None = None, **kwargs, ): + # Extract object_name from kwargs to not pass it to Qt class object_name = object_name or kwargs.pop("objectName", None) # Ensure the parent is always the first argument for QObject parent = kwargs.pop("parent", None) @@ -137,7 +138,7 @@ class BECConnector: # 1) If no objectName is set, set the initial name if not self.objectName(): self.setObjectName(self.__class__.__name__) - self._name = self.objectName() + self.object_name = self.objectName() # 2) Enforce unique objectName among siblings with the same BECConnector parent self.setParent(parent) @@ -145,6 +146,7 @@ class BECConnector: connector_parent = WidgetHierarchy._get_becwidget_ancestor(self) if connector_parent is not None: self.parent_id = connector_parent.gui_id + self._enforce_unique_sibling_name() self.rpc_register = RPCRegister() self.rpc_register.add_rpc(self) @@ -195,7 +197,7 @@ class BECConnector: trial_name = f"{base_name}_{counter}" if trial_name not in used_names: self.setObjectName(trial_name) - self._name = trial_name + self.object_name = trial_name break counter += 1 @@ -377,8 +379,9 @@ class BECConnector: def remove(self): """Cleanup the BECConnector""" # If the widget is attached to a dock, remove it from the dock. + # TODO this should be handled by dock and dock are not by BECConnector if self._parent_dock is not None: - self._parent_dock.delete(self._name) + self._parent_dock.delete(self.object_name) # If the widget is from Qt, trigger its close method. elif hasattr(self, "close"): self.close() diff --git a/bec_widgets/utils/cli_server.py b/bec_widgets/utils/cli_server.py index f59adf14..8ffad76d 100644 --- a/bec_widgets/utils/cli_server.py +++ b/bec_widgets/utils/cli_server.py @@ -169,7 +169,7 @@ class CLIServer: bec_widgets = set(w for w in all_qwidgets if isinstance(w, BECConnector)) bec_widgets = { c for c in bec_widgets if not (hasattr(c, "RPC") and c.RPC is False) - } # FIXME not needed + } # FIXME not needed -> actually maybe needed to filter widgets with no RPC, but can be done in register # 2) Also gather BECConnector-based data items from PlotBase # TODO do we need to access plot data items in cli in namespace? @@ -216,7 +216,7 @@ class CLIServer: return { "gui_id": connector.gui_id, - "name": connector._name or connector.__class__.__name__, + "object_name": connector.object_name or connector.__class__.__name__, "widget_class": connector.__class__.__name__, "config": config_dict, "__rpc__": True, diff --git a/bec_widgets/widgets/containers/dock/dock.py b/bec_widgets/widgets/containers/dock/dock.py index 3eea46e0..f6e92298 100644 --- a/bec_widgets/widgets/containers/dock/dock.py +++ b/bec_widgets/widgets/containers/dock/dock.py @@ -199,7 +199,7 @@ class BECDock(BECWidget, Dock): widgets(dict): The widgets in the dock. """ # pylint: disable=protected-access - return dict((widget._name, widget) for widget in self.element_list) + return dict((widget.object_name, widget) for widget in self.element_list) @property def element_list(self) -> list[BECWidget]: @@ -323,13 +323,12 @@ class BECDock(BECWidget, Dock): ), ) else: - # FIXME dangerous, pyqtgraph is using sometimes _name, we should get rid of it... - widget._name = name # pylint: disable=protected-access + widget.object_name = name self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan) if hasattr(widget, "config"): widget.config.gui_id = widget.gui_id - self.config.widgets[widget._name] = widget.config # pylint: disable=protected-access + self.config.widgets[widget.object_name] = widget.config return widget def move_widget(self, widget: QWidget, new_row: int, new_col: int): @@ -359,7 +358,7 @@ class BECDock(BECWidget, Dock): """ Remove the dock from the parent dock area. """ - self.parent_dock_area.delete(self._name) + self.parent_dock_area.delete(self.object_name) def delete(self, widget_name: str) -> None: """ @@ -369,7 +368,7 @@ class BECDock(BECWidget, Dock): widget_name(str): Delete the widget with the given name. """ # pylint: disable=protected-access - widgets = [widget for widget in self.widgets if widget._name == widget_name] + widgets = [widget for widget in self.widgets if widget.object_name == widget_name] if len(widgets) == 0: logger.warning( f"Widget with name {widget_name} not found in dock {self.name()}. " @@ -385,7 +384,7 @@ class BECDock(BECWidget, Dock): else: widget = widgets[0] self.layout.removeWidget(widget) - self.config.widgets.pop(widget._name, None) + self.config.widgets.pop(widget.object_name, None) if widget in self.widgets: self.widgets.remove(widget) widget.close() @@ -395,7 +394,7 @@ class BECDock(BECWidget, Dock): Remove all widgets from the dock. """ for widget in self.widgets: - self.delete(widget._name) # pylint: disable=protected-access + self.delete(widget.object_name) def cleanup(self): """ diff --git a/bec_widgets/widgets/containers/dock/dock_area.py b/bec_widgets/widgets/containers/dock/dock_area.py index fda39335..473ff0f9 100644 --- a/bec_widgets/widgets/containers/dock/dock_area.py +++ b/bec_widgets/widgets/containers/dock/dock_area.py @@ -91,7 +91,7 @@ class BECDockArea(BECWidget, QWidget): config=config, **kwargs, ) - self._parent = parent + self._parent = parent # TODO probably not needed self.layout = QVBoxLayout(self) self.layout.setSpacing(5) self.layout.setContentsMargins(0, 0, 0, 0) @@ -361,20 +361,22 @@ class BECDockArea(BECWidget, QWidget): Returns: BECDock: The created dock. """ - dock_names = [dock._name for dock in self.panel_list] # pylint: disable=protected-access + dock_names = [ + dock.object_name for dock in self.panel_list + ] # pylint: disable=protected-access if name is not None: # Name is provided if name in dock_names: raise ValueError( f"Name {name} must be unique for docks, but already exists in DockArea " - f"with name: {self._name} and id {self.gui_id}." + f"with name: {self.object_name} and id {self.gui_id}." ) else: # Name is not provided name = WidgetContainerUtils.generate_unique_name(name="dock", list_of_names=dock_names) dock = BECDock( parent=self, - name=name, - object_name=name, + name=name, # this is dock name pyqtgraph property, this is displayed on label + object_name=name, # this is a real qt object name passed to BECConnector parent_dock_area=self, parent_id=self.gui_id, closable=closable, diff --git a/tests/unit_tests/test_rpc_base.py b/tests/unit_tests/test_rpc_base.py index cbb85c30..d842a9fe 100644 --- a/tests/unit_tests/test_rpc_base.py +++ b/tests/unit_tests/test_rpc_base.py @@ -5,7 +5,7 @@ from bec_widgets.cli.rpc.rpc_base import DeletedWidgetError, RPCBase, RPCReferen @pytest.fixture def rpc_base(): - yield RPCBase(gui_id="rpc_base_test", name="test") + yield RPCBase(gui_id="rpc_base_test", object_name="test") def test_rpc_base(rpc_base):