From f446dde5a8746cc044492d26387ccf399d95e31e Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Wed, 1 Jul 2026 19:05:26 +0200 Subject: [PATCH] fix: allow writing to shared terminal without ownership --- .../views/developer_view/developer_widget.py | 4 +++- .../editors/bec_console/bec_console.py | 20 ++++++++++++++++--- tests/unit_tests/test_bec_console.py | 17 ++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/bec_widgets/applications/views/developer_view/developer_widget.py b/bec_widgets/applications/views/developer_view/developer_widget.py index 2c573a57..08d592c2 100644 --- a/bec_widgets/applications/views/developer_view/developer_widget.py +++ b/bec_widgets/applications/views/developer_view/developer_widget.py @@ -321,7 +321,9 @@ class DeveloperWidget(DockAreaWidget): # If still modified, user likely cancelled save dialog return self.current_script_id = upload_script(self.client.connector, widget.get_text()) - self.console.write(f'bec._run_script("{self.current_script_id}")') + self.console.write( + f'bec._run_script("{self.current_script_id}")', regardless_of_ownership=True + ) print(f"Uploaded script with ID: {self.current_script_id}") @SafeSlot() diff --git a/bec_widgets/widgets/editors/bec_console/bec_console.py b/bec_widgets/widgets/editors/bec_console/bec_console.py index 9199e22f..59fa8def 100644 --- a/bec_widgets/widgets/editors/bec_console/bec_console.py +++ b/bec_widgets/widgets/editors/bec_console/bec_console.py @@ -327,6 +327,13 @@ class BecConsoleRegistry: if info is not None and info.owner_console_id == console.console_id: info.initialized = True + def get_terminal(self, term_id: str) -> BecTerminal | None: + """Return a tracked terminal instance even if another console currently owns it.""" + info = self._terminal_registry.get(term_id) + if info is None or not self._is_valid_qobject(info.instance): + return None + return info.instance + def owner_is_visible(self, term_id: str) -> bool: """ Check if the owner of an instance is currently visible. @@ -472,16 +479,23 @@ class BecConsole(BECWidget, QWidget): """ self._startup_cmd = cmd - def write(self, data: str, send_return: bool = True): + def write( + self, data: str, send_return: bool = True, regardless_of_ownership: bool = False + ): """ Send data to the console Args: data (str): The data to send. send_return (bool): Whether to send a return after the data. + regardless_of_ownership (bool): Whether to send to the shared terminal session even + when this console does not currently own the visible terminal widget. """ - if self.term: - self.term.write(data, send_return) + term = self.term + if term is None and regardless_of_ownership: + term = _bec_console_registry.get_terminal(self.terminal_id) + if term: + term.write(data, send_return) def _ensure_startup_started(self): if not self.startup_cmd or not _bec_console_registry.should_initialize(self): diff --git a/tests/unit_tests/test_bec_console.py b/tests/unit_tests/test_bec_console.py index 29a4c8b2..d887c973 100644 --- a/tests/unit_tests/test_bec_console.py +++ b/tests/unit_tests/test_bec_console.py @@ -135,6 +135,23 @@ def test_bec_console_write(console_widget): mock_write.assert_called_once_with("test command", True) +def test_bec_console_write_can_target_shared_terminal_without_ownership(qtbot): + owner = BecConsole(client=mocked_client, gui_id="owner_console", terminal_id="shared_submit") + submitter = BecConsole( + client=mocked_client, gui_id="submitter_console", terminal_id="shared_submit" + ) + qtbot.addWidget(owner) + qtbot.addWidget(submitter) + + owner.take_terminal_ownership() + assert owner.term is not None + assert submitter.term is None + + with mock.patch.object(owner.term, "write") as mock_write: + submitter.write("test command", regardless_of_ownership=True) + mock_write.assert_called_once_with("test command", True) + + def test_is_owner(console_widget: BecConsole): assert _bec_console_registry.is_owner(console_widget) mock_console = mock.MagicMock()