From 90a3e7583e6ccdfc7ffa12bd6bf6717a80e2768f Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Fri, 24 Jul 2026 21:07:05 +0200 Subject: [PATCH] fix(file-manager): treat explorer exit code 1 as success on Windows --- core/file_manager.py | 10 ++++++++-- tests/test_file_manager.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/core/file_manager.py b/core/file_manager.py index 1427464..3190314 100644 --- a/core/file_manager.py +++ b/core/file_manager.py @@ -82,7 +82,7 @@ def _find_launcher(*names: str) -> tuple[str, str]: ) -def _launch(command: list[str]) -> None: +def _launch(command: list[str], check_exit_code: bool = True) -> None: kwargs: Dict[str, Any] = { "shell": False, "stdin": subprocess.DEVNULL, @@ -97,6 +97,12 @@ def _launch(command: list[str]) -> None: except (OSError, ValueError) as exc: raise FileManagerError(f"Could not start the system file manager: {exc}") from exc + # Explorer commonly delegates the request to an existing shell process and + # exits with code 1 even though the folder opened successfully. A successful + # process creation is therefore the only reliable Windows signal. + if not check_exit_code: + return + # Most launcher commands exit immediately after handing the request to the # desktop. Catch a fast failure without waiting for a long-running manager. try: @@ -154,7 +160,7 @@ def open_in_file_manager(path_value: Any, system: str | None = None) -> Dict[str f"Opening folders is not supported on {display_name}." ) - _launch(command) + _launch(command, check_exit_code=platform_name != "windows") return { "platform": platform_name, "launcher": launcher, diff --git a/tests/test_file_manager.py b/tests/test_file_manager.py index f7ffdce..70395a7 100644 --- a/tests/test_file_manager.py +++ b/tests/test_file_manager.py @@ -87,6 +87,21 @@ class FileManagerTests(unittest.TestCase): self.assertEqual(command, [r"C:\Windows\explorer.exe", os.path.realpath(self.directory)]) self.assertFalse(result["selected"]) + @patch("core.file_manager.subprocess.Popen") + @patch("core.file_manager.shutil.which") + def test_windows_does_not_treat_explorer_exit_code_one_as_failure( + self, mock_which, mock_popen + ): + mock_which.return_value = r"C:\Windows\explorer.exe" + process = MagicMock() + process.wait.return_value = 1 + mock_popen.return_value = process + + result = open_in_file_manager(self.file_path, system="Windows") + + process.wait.assert_not_called() + self.assertEqual(result["launcher"], "explorer") + @patch("core.file_manager.subprocess.Popen") @patch("core.file_manager.shutil.which", return_value="/usr/bin/open") def test_macos_reveals_a_file(self, _mock_which, mock_popen):