From 2e0414f9697c56101d473ab6f61a2739b7f3afd5 Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 23 Jul 2026 23:28:55 +0000 Subject: [PATCH] fix(test): restore headless unit tests broken by PTY check in e719022 The PTY check added in e719022 calls sys.stdin.fileno() which raises io.UnsupportedOperation under pytest's stdin capture. Guard the fileno() call with a try/except so the check degrades cleanly to "not a tty" instead of crashing, then stub os.isatty in the test setUp so headless unit tests aren't blocked on a real TTY. Co-Authored-By: Claude Sonnet 4.6 --- bot_bottle/cli/start.py | 7 ++++++- tests/unit/test_cli_start_headless.py | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bot_bottle/cli/start.py b/bot_bottle/cli/start.py index afe78a8..27bcf3a 100644 --- a/bot_bottle/cli/start.py +++ b/bot_bottle/cli/start.py @@ -14,6 +14,7 @@ the private orchestrator `_launch_bottle`. from __future__ import annotations import argparse +import io import os import shutil import sys @@ -195,7 +196,11 @@ def _start_headless( path, so the agent still execs on the inherited stdio/PTY — an orchestrator allocates that PTY and relays it to its desktop/mobile clients.""" - if not os.isatty(sys.stdin.fileno()): + try: + stdin_fd = sys.stdin.fileno() + except io.UnsupportedOperation: + stdin_fd = -1 + if not os.isatty(stdin_fd): die( "--headless requires a PTY on stdin; run via:\n" " script -q /dev/null ./cli.py start ..." diff --git a/tests/unit/test_cli_start_headless.py b/tests/unit/test_cli_start_headless.py index 48bc274..092b26c 100644 --- a/tests/unit/test_cli_start_headless.py +++ b/tests/unit/test_cli_start_headless.py @@ -69,6 +69,9 @@ class TestCmdStartHeadless(unittest.TestCase): self._modal = patch.object(tui_mod, "name_color_modal").start() patch.dict(os.environ, {}, clear=False).start() os.environ.pop("BOT_BOTTLE_BACKEND", None) + # PTY check uses os.isatty(sys.stdin.fileno()); stub both so + # headless unit tests aren't blocked on a real TTY. + patch("bot_bottle.cli.start.os.isatty", return_value=True).start() self.addCleanup(patch.stopall) def _spec(self):