From 683a8a6d8f6908b204199a45576c71f8e9fe4c73 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 15 Jan 2026 23:54:48 -0400 Subject: [PATCH] Fix signal handling during graph rebuild - Add _rebuilding flag to ignore signals during rebuild - Prevents cascade of port_disconnected signals when clearing graph - Fixes KeyError in NodeGraphQt undo stack - Fixes false dependency warnings on view switch The port_disconnected and nodes_deleted signals were firing during clear_session(), causing recursive rebuilds and errors. Co-Authored-By: Claude Opus 4.5 --- src/cmdforge/gui/widgets/flow_graph.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/cmdforge/gui/widgets/flow_graph.py b/src/cmdforge/gui/widgets/flow_graph.py index bd733df..6050ece 100644 --- a/src/cmdforge/gui/widgets/flow_graph.py +++ b/src/cmdforge/gui/widgets/flow_graph.py @@ -135,6 +135,7 @@ class FlowGraphWidget(QWidget): self._input_node = None self._output_node = None self._step_nodes: List[CmdForgeBaseNode] = [] + self._rebuilding = False # Flag to ignore signals during rebuild self._setup_ui() @@ -215,13 +216,21 @@ class FlowGraphWidget(QWidget): if not self._graph: return - # Clear existing nodes - self._graph.clear_session() + # Set flag to ignore signals during rebuild + self._rebuilding = True + + try: + # Clear existing nodes + self._graph.clear_session() + except Exception: + pass # Ignore errors during clear + self._input_node = None self._output_node = None self._step_nodes = [] if not self._tool: + self._rebuilding = False return # Create input node @@ -294,6 +303,7 @@ class FlowGraphWidget(QWidget): node.set_selected(True) # Use a timer to fit after the widget is fully rendered + # Also clears the rebuilding flag after everything settles QTimer.singleShot(50, self._fit_and_clear_selection) def _fit_and_clear_selection(self): @@ -303,6 +313,9 @@ class FlowGraphWidget(QWidget): # Clear selection self._graph.clear_selection() + # Clear rebuilding flag - now safe to handle user interactions + self._rebuilding = False + def select_all_nodes(self): """Select all nodes in the graph.""" if not self._graph: @@ -419,6 +432,10 @@ class FlowGraphWidget(QWidget): def _on_nodes_deleted(self, nodes): """Handle node deletion from the graph.""" + # Ignore during rebuild + if self._rebuilding: + return + # Collect step indices of deleted step nodes (not Input/Output nodes) deleted_indices = [] for node in nodes: @@ -439,6 +456,10 @@ class FlowGraphWidget(QWidget): 2. The chain reconnects (previous node → next node) 3. Disconnected node attaches at the end before Output """ + # Ignore during rebuild + if self._rebuilding: + return + if not self._tool or not self._tool.steps: return