diff --git a/poethepoet/executor/poetry.py b/poethepoet/executor/poetry.py index 1c9e6ace..f4ca7054 100644 --- a/poethepoet/executor/poetry.py +++ b/poethepoet/executor/poetry.py @@ -57,11 +57,16 @@ async def execute( return await self._execute_cmd(cmd, input=input, use_exec=use_exec) # Run this task with `poetry run` - return await self._execute_cmd( + result = await self._execute_cmd( (self._poetry_cmd(), "--no-plugins", "run", *cmd), input=input, use_exec=use_exec, ) + # The inner cmd may be a .bat/.cmd but _exec_via_subproc only sees + # poetry.exe as cmd[0], so check the original command here + if self._is_windows and cmd[0].lower().endswith((".bat", ".cmd")): + result.no_console_ctrl = True + return result async def _handle_file_not_found( self, cmd: Sequence[str], error: FileNotFoundError diff --git a/poethepoet/executor/uv.py b/poethepoet/executor/uv.py index f8f2366f..f3c0129c 100644 --- a/poethepoet/executor/uv.py +++ b/poethepoet/executor/uv.py @@ -74,11 +74,16 @@ async def execute( ) # Run this task with `uv run` - return await self._execute_cmd( + result = await self._execute_cmd( (self._uv_cmd(), "run", *uv_run_options, *cmd), input=input, use_exec=use_exec, ) + # The inner cmd may be a .bat/.cmd but _exec_via_subproc only sees uv.exe + # as cmd[0], so check the original command here + if self._is_windows and cmd[0].lower().endswith((".bat", ".cmd")): + result.no_console_ctrl = True + return result @classmethod def _uv_cmd(cls): diff --git a/poethepoet/shutdown.py b/poethepoet/shutdown.py index d4236590..e425f532 100644 --- a/poethepoet/shutdown.py +++ b/poethepoet/shutdown.py @@ -46,7 +46,7 @@ def _initialize_shutdown(self): self._shutdown_loop(), name="ShutdownWorker" ) - async def _shutdown_loop(self, escalation_interval_s: float = 1.0): + async def _shutdown_loop(self, escalation_interval_s: float = 0.8): """ Call shutdown again every interval_s seconds until everything is dead """ @@ -64,12 +64,12 @@ def _shutdown(self): if proc.returncode is None: if proc.no_console_ctrl: self._io.print_debug( - " ! Terminating subprocess tree %s" + " ! Force-terminating subprocess tree %s" " to avoid console corruption", proc.pid, ) subprocess.run( - ["taskkill", "/T", "/PID", str(proc.pid)], + ["taskkill", "/F", "/T", "/PID", str(proc.pid)], capture_output=True, ) else: diff --git a/tests/test_shutdown.py b/tests/test_shutdown.py index 04778585..66a46263 100644 --- a/tests/test_shutdown.py +++ b/tests/test_shutdown.py @@ -74,7 +74,7 @@ def fake_taskkill(cmd: list[str], **_kwargs): manager._shutdown() assert fake_proc.signal_calls == [] - assert taskkill_calls == [["taskkill", "/T", "/PID", str(process.pid)]] + assert taskkill_calls == [["taskkill", "/F", "/T", "/PID", str(process.pid)]] loop.close()