From 8563bcf6cfcdcec98414895cb29ea148209fa967 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 17:01:01 +0000 Subject: [PATCH] fix(watcher): escape exception strings to prevent rich MarkupError crashes Co-authored-by: shenald-dev <245350826+shenald-dev@users.noreply.github.com> --- src/echo/watcher.py | 2 +- tests/test_markup.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/echo/watcher.py b/src/echo/watcher.py index 12447ec..1c674d8 100644 --- a/src/echo/watcher.py +++ b/src/echo/watcher.py @@ -161,7 +161,7 @@ def _run_command(self, event_path): else: console.print(f"[red]✖ Command failed with exit code {process.returncode}.[/red]") except Exception as e: - console.print(f"[bold red]Error executing command: {e}[/bold red]") + console.print(f"[bold red]Error executing command: {escape(str(e))}[/bold red]") def _is_ignored_impl(self, path: str) -> bool: if path.startswith(self._abs_base_path): diff --git a/tests/test_markup.py b/tests/test_markup.py index 9f27807..0815cf0 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -1,5 +1,7 @@ import time from echo.watcher import CommandRunnerHandler +import subprocess + from unittest.mock import MagicMock def test_rich_markup_crash_escaping(): @@ -24,3 +26,23 @@ def test_rich_markup_crash_escaping(): if handler.current_process: handler.current_process.terminate() handler.current_process.wait() + + +def test_rich_error_crash(): + handler = CommandRunnerHandler("echo test") + + class MockException(Exception): + def __str__(self): + return "File not found: [missing.py]" + + original_popen = subprocess.Popen + + def fake_popen(*args, **kwargs): + raise MockException() + + subprocess.Popen = fake_popen + try: + # this should crash rich with MarkupError if not escaped + handler._run_command("test.txt") + finally: + subprocess.Popen = original_popen