← pod_r4_v1

rich_3675

failed WRONG_FIX wrong_fix · 30 tool calls · 105 s · Textualize/rich

Task input

TTY_COMPATIBLE

Implement new `TTY_COMPATIBLE` environment variable

@ofek @webknjaz @hugovk 

Relevant discussion: https://github.com/Textualize/rich/issues/2924

Tool calls (31)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"is_terminal\" rich | head -20"
}
{"status": "ok", "stdout": "rich/console.py:136: is_terminal: bool\nrich/console.py:741: (self.is_terminal and not self.is_dumb_terminal)\nrich/console.py:795:
full
{"status": "ok", "stdout": "rich/console.py:136:    is_terminal: bool\nrich/console.py:741:            (self.is_terminal and not self.is_dumb_terminal)\nrich/console.py:795:        if not self.is_terminal or self.is_dumb_terminal:\nrich/console.py:931:    def is_terminal(self) -> bool:\nrich/console.py:976:        return self.is_terminal and is_dumb\nrich/console.py:988:            is_terminal=self.is_terminal,\nrich/console.py:1183:        if self.is_terminal:\nrich/console.py:1203:        if self.is_terminal and not self.legacy_windows:\nrich/console.py:1245:        if self.is_terminal:\nrich/console.py:2102:        not_terminal = not self.is_terminal\nrich/live.py:154:                    if not self._alt_screen and self.console.is_terminal:\nrich/live.py:179:        if self.console.is_terminal or self.console.is_jupyter:\nrich/live.py:240:            elif self.console.is_terminal and not self.console.is_dumb_terminal:\n", "stderr": "", "exit_code": 0}
2read_file
{
 "filepath": "rich/console.py",
 "start_line": 931,
 "end_line": 950
}
{"status": "ok", "filepath": "rich/console.py", "content": " def is_terminal(self) -> bool:\n \"\"\"Check if the console is writing to a terminal.\n\n Returns:\
full
{"status": "ok", "filepath": "rich/console.py", "content": "    def is_terminal(self) -> bool:\n        \"\"\"Check if the console is writing to a terminal.\n\n        Returns:\n            bool: True if the console writing to a device capable of\n            understanding terminal codes, otherwise False.\n        \"\"\"\n        if self._force_terminal is not None:\n            return self._force_terminal\n\n        if hasattr(sys.stdin, \"__module__\") and sys.stdin.__module__.startswith(\n            \"idlelib\"\n        ):\n            # Return False for Idle which claims to be a tty but can't handle ansi codes\n            return False\n\n        if self.is_jupyter:\n            # return False for Jupyter, which may have FORCE_COLOR set\n            return False\n", "start_line": 931, "end_line": 950, "total_lines": 2661, "is_truncated": false}
3read_file
{
 "end_line": 960,
 "filepath": "rich/console.py",
 "start_line": 951
}
{"status": "ok", "filepath": "rich/console.py", "content": " # If FORCE_COLOR env var has any value at all, we assume a terminal.\n force_color = self._environ.
full
{"status": "ok", "filepath": "rich/console.py", "content": "        # If FORCE_COLOR env var has any value at all, we assume a terminal.\n        force_color = self._environ.get(\"FORCE_COLOR\")\n        if force_color is not None:\n            self._force_terminal = True\n            return True\n\n        isatty: Optional[Callable[[], bool]] = getattr(self.file, \"isatty\", None)\n        try:\n            return False if isatty is None else isatty()\n        except ValueError:", "start_line": 951, "end_line": 960, "total_lines": 2661, "is_truncated": false}
4read_file
{
 "end_line": 970,
 "filepath": "rich/console.py",
 "start_line": 961
}
{"status": "ok", "filepath": "rich/console.py", "content": " # in some situation (at the end of a pytest run for example) isatty() can raise\n # ValueError: I/O
full
{"status": "ok", "filepath": "rich/console.py", "content": "            # in some situation (at the end of a pytest run for example) isatty() can raise\n            # ValueError: I/O operation on closed file\n            # return False because we aren't in a terminal anymore\n            return False\n\n    @property\n    def is_dumb_terminal(self) -> bool:\n        \"\"\"Detect dumb terminal.\n\n        Returns:", "start_line": 961, "end_line": 970, "total_lines": 2661, "is_truncated": false}
5read_file
{
 "end_line": 990,
 "filepath": "rich/console.py",
 "start_line": 971
}
{"status": "ok", "filepath": "rich/console.py", "content": " bool: True if writing to a dumb terminal, otherwise False.\n\n \"\"\"\n _term = self._environ.get(\
full
{"status": "ok", "filepath": "rich/console.py", "content": "            bool: True if writing to a dumb terminal, otherwise False.\n\n        \"\"\"\n        _term = self._environ.get(\"TERM\", \"\")\n        is_dumb = _term.lower() in (\"dumb\", \"unknown\")\n        return self.is_terminal and is_dumb\n\n    @property\n    def options(self) -> ConsoleOptions:\n        \"\"\"Get default console options.\"\"\"\n        return ConsoleOptions(\n            max_height=self.size.height,\n            size=self.size,\n            legacy_windows=self.legacy_windows,\n            min_width=1,\n            max_width=self.width,\n            encoding=self.encoding,\n            is_terminal=self.is_terminal,\n        )\n", "start_line": 971, "end_line": 990, "total_lines": 2661, "is_truncated": false}
6run_command
{
 "command": "grep -rn \"FORCE_COLOR\" rich | head -20"
}
{"status": "ok", "stdout": "rich/console.py:948: # return False for Jupyter, which may have FORCE_COLOR set\nrich/console.py:951: # If FORCE_COLOR env var has a
full
{"status": "ok", "stdout": "rich/console.py:948:            # return False for Jupyter, which may have FORCE_COLOR set\nrich/console.py:951:        # If FORCE_COLOR env var has any value at all, we assume a terminal.\nrich/console.py:952:        force_color = self._environ.get(\"FORCE_COLOR\")\n", "stderr": "", "exit_code": 0}
7edit_file
{
 "filepath": "rich/console.py",
 "new_string": "        # If FORCE_COLOR env var has any value at all, we assume a terminal.\n        force_color = self._environ.get(\"FORCE_COLOR\")\n        if force_color is not None:\n            self._force_terminal = True\n            return True\n\n        # If TTY_COMPATIBLE env var has any value at all, we assume a terminal.\n        tty_compatible = self._environ.get(\"TTY_COMPATIBLE\")\n        if tty_compatible is not None:\n            self._force_terminal = True\n            return True\n\n        isatty: Optional[Callable[[], bool]] = getattr(self.file, \"isatty\", None)",
 "old_string": "        # If FORCE_COLOR env var has any value at all, we assume a terminal.\n        force_color = self._environ.get(\"FORCE_COLOR\")\n        if force_color is not None:\n            self._force_terminal = True\n            return True\n\n        isatty: Optional[Callable[[], bool]] = getattr(self.file, \"isatty\", None)"
}
{"status": "ok", "filepath": "rich/console.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/console.py\n+++ b/rich/console.py\n@@ -954,6 +954,12
full
{"status": "ok", "filepath": "rich/console.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/console.py\n+++ b/rich/console.py\n@@ -954,6 +954,12 @@\n             self._force_terminal = True\n             return True\n \n+        # If TTY_COMPATIBLE env var has any value at all, we assume a terminal.\n+        tty_compatible = self._environ.get(\"TTY_COMPATIBLE\")\n+        if tty_compatible is not None:\n+            self._force_terminal = True\n+            return True\n+\n         isatty: Optional[Callable[[], bool]] = getattr(self.file, \"isatty\", None)\n         try:\n             return False if isatty is None else isatty()\n", "is_truncated": false}
8run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal()}')\""
}
{"status": "error", "error_type": "CommandError", "error_message": "Traceback (most recent call last):\n File \"<string>\", line 1, in <module>\n import os; fro
full
{"status": "error", "error_type": "CommandError", "error_message": "Traceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n    import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal()}')\n                                                                                                                                                    ~~~~~~~~~~~~~~~~~~~^^\nTypeError: 'bool' object is not callable\n", "details": {"stdout": "", "stderr": "Traceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n    import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal()}')\n                                                                                                                                                    ~~~~~~~~~~~~~~~~~~~^^\nTypeError: 'bool' object is not callable\n", "exit_code": 1}}
9run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
10read_file
{
 "end_line": 140,
 "filepath": "rich/console.py",
 "start_line": 120
}
{"status": "ok", "filepath": "rich/console.py", "content": " height: int\n \"\"\"The height of the console in lines.\"\"\"\n\n\n@dataclass\nclass ConsoleOptions
full
{"status": "ok", "filepath": "rich/console.py", "content": "    height: int\n    \"\"\"The height of the console in lines.\"\"\"\n\n\n@dataclass\nclass ConsoleOptions:\n    \"\"\"Options for __rich_console__ method.\"\"\"\n\n    size: ConsoleDimensions\n    \"\"\"Size of console.\"\"\"\n    legacy_windows: bool\n    \"\"\"legacy_windows: flag for legacy windows.\"\"\"\n    min_width: int\n    \"\"\"Minimum width of renderable.\"\"\"\n    max_width: int\n    \"\"\"Maximum width of renderable.\"\"\"\n    is_terminal: bool\n    \"\"\"True if the target is a terminal, otherwise False.\"\"\"\n    encoding: str\n    \"\"\"Encoding of terminal.\"\"\"\n    max_height: int", "start_line": 120, "end_line": 140, "total_lines": 2667, "is_truncated": false}
11read_file
{
 "end_line": 200,
 "filepath": "rich/console.py",
 "start_line": 150
}
{"status": "ok", "filepath": "rich/console.py", "content": " markup: Optional[bool] = None\n \"\"\"Enable markup when rendering strings.\"\"\"\n height: Optiona
full
{"status": "ok", "filepath": "rich/console.py", "content": "    markup: Optional[bool] = None\n    \"\"\"Enable markup when rendering strings.\"\"\"\n    height: Optional[int] = None\n\n    @property\n    def ascii_only(self) -> bool:\n        \"\"\"Check if renderables should use ascii only.\"\"\"\n        return not self.encoding.startswith(\"utf\")\n\n    def copy(self) -> \"ConsoleOptions\":\n        \"\"\"Return a copy of the options.\n\n        Returns:\n            ConsoleOptions: a copy of self.\n        \"\"\"\n        options: ConsoleOptions = ConsoleOptions.__new__(ConsoleOptions)\n        options.__dict__ = self.__dict__.copy()\n        return options\n\n    def update(\n        self,\n        *,\n        width: Union[int, NoChange] = NO_CHANGE,\n        min_width: Union[int, NoChange] = NO_CHANGE,\n        max_width: Union[int, NoChange] = NO_CHANGE,\n        justify: Union[Optional[JustifyMethod], NoChange] = NO_CHANGE,\n        overflow: Union[Optional[OverflowMethod], NoChange] = NO_CHANGE,\n        no_wrap: Union[Optional[bool], NoChange] = NO_CHANGE,\n        highlight: Union[Optional[bool], NoChange] = NO_CHANGE,\n        markup: Union[Optional[bool], NoChange] = NO_CHANGE,\n        height: Union[Optional[int], NoChange] = NO_CHANGE,\n    ) -> \"ConsoleOptions\":\n        \"\"\"Update values, return a copy.\"\"\"\n        options = self.copy()\n        if not isinstance(width, NoChange):\n            options.min_width = options.max_width = max(0, width)\n        if not isinstance(min_width, NoChange):\n            options.min_width = min_width\n        if not isinstance(max_width, NoChange):\n            options.max_width = max_width\n        if not isinstance(justify, NoChange):\n            options.justify = justify\n        if not isinstance(overflow, NoChange):\n            options.overflow = overflow\n        if not isinstance(no_wrap, NoChange):\n            options.no_wrap = no_wrap\n        if not isinstance(highlight, NoChange):\n        
12read_file
{
 "end_line": 300,
 "filepath": "rich/console.py",
 "start_line": 201
}
{"status": "ok", "filepath": "rich/console.py", "content": " if height is not None:\n options.max_height = height\n options.height = None if height is None else
full
{"status": "ok", "filepath": "rich/console.py", "content": "            if height is not None:\n                options.max_height = height\n            options.height = None if height is None else max(0, height)\n        return options\n\n    def update_width(self, width: int) -> \"ConsoleOptions\":\n        \"\"\"Update just the width, return a copy.\n\n        Args:\n            width (int): New width (sets both min_width and max_width)\n\n        Returns:\n            ~ConsoleOptions: New console options instance.\n        \"\"\"\n        options = self.copy()\n        options.min_width = options.max_width = max(0, width)\n        return options\n\n    def update_height(self, height: int) -> \"ConsoleOptions\":\n        \"\"\"Update the height, and return a copy.\n\n        Args:\n            height (int): New height\n\n        Returns:\n            ~ConsoleOptions: New Console options instance.\n        \"\"\"\n        options = self.copy()\n        options.max_height = options.height = height\n        return options\n\n    def reset_height(self) -> \"ConsoleOptions\":\n        \"\"\"Return a copy of the options with height set to ``None``.\n\n        Returns:\n            ~ConsoleOptions: New console options instance.\n        \"\"\"\n        options = self.copy()\n        options.height = None\n        return options\n\n    def update_dimensions(self, width: int, height: int) -> \"ConsoleOptions\":\n        \"\"\"Update the width and height, and return a copy.\n\n        Args:\n            width (int): New width (sets both min_width and max_width).\n            height (int): New height.\n\n        Returns:\n            ~ConsoleOptions: New console options instance.\n        \"\"\"\n        options = self.copy()\n        options.min_width = options.max_width = max(0, width)\n        options.height = options.max_height = height\n        return options\n\n\n@runtime_checkable\nclass RichCast(Protocol):\n    \"\"\"An object that may be 'cast' to a console rendera
13run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
14read_file
{
 "end_line": 350,
 "filepath": "rich/console.py",
 "start_line": 251
}
{"status": "ok", "filepath": "rich/console.py", "content": " \"\"\"\n options = self.copy()\n options.min_width = options.max_width = max(0, width)\n options.he
full
{"status": "ok", "filepath": "rich/console.py", "content": "        \"\"\"\n        options = self.copy()\n        options.min_width = options.max_width = max(0, width)\n        options.height = options.max_height = height\n        return options\n\n\n@runtime_checkable\nclass RichCast(Protocol):\n    \"\"\"An object that may be 'cast' to a console renderable.\"\"\"\n\n    def __rich__(\n        self,\n    ) -> Union[\"ConsoleRenderable\", \"RichCast\", str]:  # pragma: no cover\n        ...\n\n\n@runtime_checkable\nclass ConsoleRenderable(Protocol):\n    \"\"\"An object that supports the console protocol.\"\"\"\n\n    def __rich_console__(\n        self, console: \"Console\", options: \"ConsoleOptions\"\n    ) -> \"RenderResult\":  # pragma: no cover\n        ...\n\n\n# A type that may be rendered by Console.\nRenderableType = Union[ConsoleRenderable, RichCast, str]\n\"\"\"A string or any object that may be rendered by Rich.\"\"\"\n\n# The result of calling a __rich_console__ method.\nRenderResult = Iterable[Union[RenderableType, Segment]]\n\n_null_highlighter = NullHighlighter()\n\n\nclass CaptureError(Exception):\n    \"\"\"An error in the Capture context manager.\"\"\"\n\n\nclass NewLine:\n    \"\"\"A renderable to generate new line(s)\"\"\"\n\n    def __init__(self, count: int = 1) -> None:\n        self.count = count\n\n    def __rich_console__(\n        self, console: \"Console\", options: \"ConsoleOptions\"\n    ) -> Iterable[Segment]:\n        yield Segment(\"\\n\" * self.count)\n\n\nclass ScreenUpdate:\n    \"\"\"Render a list of lines at a given offset.\"\"\"\n\n    def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None:\n        self._lines = lines\n        self.x = x\n        self.y = y\n\n    def __rich_console__(\n        self, console: \"Console\", options: ConsoleOptions\n    ) -> RenderResult:\n        x = self.x\n        move_to = Control.move_to\n        for offset, line in enumerate(self._lines, self.y):\n            yield move_t
15run_command
{
 "command": "grep -n \"def __init__(\" rich/console.py | grep -A 10 \"def __init__(\" | head -20"
}
{"status": "ok", "stdout": "295: def __init__(self, count: int = 1) -> None:\n307: def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None:\n330:
full
{"status": "ok", "stdout": "295:    def __init__(self, count: int = 1) -> None:\n307:    def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None:\n330:    def __init__(self, console: \"Console\") -> None:\n358:    def __init__(self, console: \"Console\", theme: Theme, inherit: bool = True) -> None:\n379:    def __init__(\n418:    def __init__(\n470:    def __init__(self, *renderables: \"RenderableType\", fit: bool = True) -> None:\n631:    def __init__(\n", "stderr": "", "exit_code": 0}
16read_file
{
 "end_line": 450,
 "filepath": "rich/console.py",
 "start_line": 379
}
{"status": "ok", "filepath": "rich/console.py", "content": " def __init__(\n self,\n console: \"Console\",\n pager: Optional[Pager] = None,\n styles: bool = Fal
full
{"status": "ok", "filepath": "rich/console.py", "content": "    def __init__(\n        self,\n        console: \"Console\",\n        pager: Optional[Pager] = None,\n        styles: bool = False,\n        links: bool = False,\n    ) -> None:\n        self._console = console\n        self.pager = SystemPager() if pager is None else pager\n        self.styles = styles\n        self.links = links\n\n    def __enter__(self) -> \"PagerContext\":\n        self._console._enter_buffer()\n        return self\n\n    def __exit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        if exc_type is None:\n            with self._console._lock:\n                buffer: List[Segment] = self._console._buffer[:]\n                del self._console._buffer[:]\n                segments: Iterable[Segment] = buffer\n                if not self.styles:\n                    segments = Segment.strip_styles(segments)\n                elif not self.links:\n                    segments = Segment.strip_links(segments)\n                content = self._console._render_buffer(segments)\n            self.pager.show(content)\n        self._console._exit_buffer()\n\n\nclass ScreenContext:\n    \"\"\"A context manager that enables an alternative screen. See :meth:`~rich.console.Console.screen` for usage.\"\"\"\n\n    def __init__(\n        self, console: \"Console\", hide_cursor: bool, style: StyleType = \"\"\n    ) -> None:\n        self.console = console\n        self.hide_cursor = hide_cursor\n        self.screen = Screen(style=style)\n        self._changed = False\n\n    def update(\n        self, *renderables: RenderableType, style: Optional[StyleType] = None\n    ) -> None:\n        \"\"\"Update the screen.\n\n        Args:\n            renderable (RenderableType, optional): Optional renderable to replace current renderable,\n                or None for no change. Defaults to 
17read_file
{
 "end_line": 450,
 "filepath": "rich/console.py",
 "start_line": 418
}
{"status": "ok", "filepath": "rich/console.py", "content": " def __init__(\n self, console: \"Console\", hide_cursor: bool, style: StyleType = \"\"\n ) -> None:
full
{"status": "ok", "filepath": "rich/console.py", "content": "    def __init__(\n        self, console: \"Console\", hide_cursor: bool, style: StyleType = \"\"\n    ) -> None:\n        self.console = console\n        self.hide_cursor = hide_cursor\n        self.screen = Screen(style=style)\n        self._changed = False\n\n    def update(\n        self, *renderables: RenderableType, style: Optional[StyleType] = None\n    ) -> None:\n        \"\"\"Update the screen.\n\n        Args:\n            renderable (RenderableType, optional): Optional renderable to replace current renderable,\n                or None for no change. Defaults to None.\n            style: (Style, optional): Replacement style, or None for no change. Defaults to None.\n        \"\"\"\n        if renderables:\n            self.screen.renderable = (\n                Group(*renderables) if len(renderables) > 1 else renderables[0]\n            )\n        if style is not None:\n            self.screen.style = style\n        self.console.print(self.screen, end=\"\")\n\n    def __enter__(self) -> \"ScreenContext\":\n        self._changed = self.console.set_alt_screen(True)\n        if self._changed and self.hide_cursor:\n            self.console.show_cursor(False)\n        return self\n\n    def __exit__(", "start_line": 418, "end_line": 450, "total_lines": 2667, "is_truncated": false}
18read_file
{
 "end_line": 650,
 "filepath": "rich/console.py",
 "start_line": 631
}
{"status": "ok", "filepath": "rich/console.py", "content": " def __init__(\n self,\n *,\n color_system: Optional[\n Literal[\"auto\", \"standard\", \"256\", \"t
full
{"status": "ok", "filepath": "rich/console.py", "content": "    def __init__(\n        self,\n        *,\n        color_system: Optional[\n            Literal[\"auto\", \"standard\", \"256\", \"truecolor\", \"windows\"]\n        ] = \"auto\",\n        force_terminal: Optional[bool] = None,\n        force_jupyter: Optional[bool] = None,\n        force_interactive: Optional[bool] = None,\n        soft_wrap: bool = False,\n        theme: Optional[Theme] = None,\n        stderr: bool = False,\n        file: Optional[IO[str]] = None,\n        quiet: bool = False,\n        width: Optional[int] = None,\n        height: Optional[int] = None,\n        style: Optional[StyleType] = None,\n        no_color: Optional[bool] = None,\n        tab_size: int = 8,\n        record: bool = False,", "start_line": 631, "end_line": 650, "total_lines": 2667, "is_truncated": false}
19read_file
{
 "end_line": 700,
 "filepath": "rich/console.py",
 "start_line": 651
}
{"status": "ok", "filepath": "rich/console.py", "content": " markup: bool = True,\n emoji: bool = True,\n emoji_variant: Optional[EmojiVariant] = None,\n highli
full
{"status": "ok", "filepath": "rich/console.py", "content": "        markup: bool = True,\n        emoji: bool = True,\n        emoji_variant: Optional[EmojiVariant] = None,\n        highlight: bool = True,\n        log_time: bool = True,\n        log_path: bool = True,\n        log_time_format: Union[str, FormatTimeCallable] = \"[%X]\",\n        highlighter: Optional[\"HighlighterType\"] = ReprHighlighter(),\n        legacy_windows: Optional[bool] = None,\n        safe_box: bool = True,\n        get_datetime: Optional[Callable[[], datetime]] = None,\n        get_time: Optional[Callable[[], float]] = None,\n        _environ: Optional[Mapping[str, str]] = None,\n    ):\n        # Copy of os.environ allows us to replace it for testing\n        if _environ is not None:\n            self._environ = _environ\n\n        self.is_jupyter = _is_jupyter() if force_jupyter is None else force_jupyter\n        if self.is_jupyter:\n            if width is None:\n                jupyter_columns = self._environ.get(\"JUPYTER_COLUMNS\")\n                if jupyter_columns is not None and jupyter_columns.isdigit():\n                    width = int(jupyter_columns)\n                else:\n                    width = JUPYTER_DEFAULT_COLUMNS\n            if height is None:\n                jupyter_lines = self._environ.get(\"JUPYTER_LINES\")\n                if jupyter_lines is not None and jupyter_lines.isdigit():\n                    height = int(jupyter_lines)\n                else:\n                    height = JUPYTER_DEFAULT_LINES\n\n        self.tab_size = tab_size\n        self.record = record\n        self._markup = markup\n        self._emoji = emoji\n        self._emoji_variant: Optional[EmojiVariant] = emoji_variant\n        self._highlight = highlight\n        self.legacy_windows: bool = (\n            (detect_legacy_windows() and not self.is_jupyter)\n            if legacy_windows is None\n            else legacy_windows\n        )\n\n        if width is None:\n            
20read_file
{
 "end_line": 720,
 "filepath": "rich/console.py",
 "start_line": 701
}
{"status": "ok", "filepath": "rich/console.py", "content": " lines = self._environ.get(\"LINES\")\n if lines is not None and lines.isdigit():\n height = int(lin
full
{"status": "ok", "filepath": "rich/console.py", "content": "            lines = self._environ.get(\"LINES\")\n            if lines is not None and lines.isdigit():\n                height = int(lines)\n\n        self.soft_wrap = soft_wrap\n        self._width = width\n        self._height = height\n\n        self._color_system: Optional[ColorSystem]\n\n        self._force_terminal = None\n        if force_terminal is not None:\n            self._force_terminal = force_terminal\n\n        self._file = file\n        self.quiet = quiet\n        self.stderr = stderr\n\n        if color_system is None:\n            self._color_system = None", "start_line": 701, "end_line": 720, "total_lines": 2667, "is_truncated": false}
21read_file
{
 "end_line": 730,
 "filepath": "rich/console.py`,start_line:721"
}
{"status": "error", "error_type": "FileReadError", "error_message": "File 'rich/console.py`,start_line:721' not found in workspace."}
full
{"status": "error", "error_type": "FileReadError", "error_message": "File 'rich/console.py`,start_line:721' not found in workspace."}
22read_file
{
 "end_line": 730,
 "filepath": "rich/console.py",
 "start_line": 721
}
{"status": "ok", "filepath": "rich/console.py", "content": " elif color_system == \"auto\":\n self._color_system = self._detect_color_system()\n else:\n self._c
full
{"status": "ok", "filepath": "rich/console.py", "content": "        elif color_system == \"auto\":\n            self._color_system = self._detect_color_system()\n        else:\n            self._color_system = COLOR_SYSTEMS[color_system]\n\n        self._lock = threading.RLock()\n        self._log_render = LogRender(\n            show_time=log_time,\n            show_path=log_path,\n            time_format=log_time_format,", "start_line": 721, "end_line": 730, "total_lines": 2667, "is_truncated": false}
23run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(force_terminal=False); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
24run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
25run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ.pop('TTY_COMPATIBLE', None); console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
26run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
27run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['FORCE_COLOR'] = '1'; console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
28run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['FORCE_COLOR'] = '1'; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
29run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ.pop('FORCE_COLOR', None); os.environ.pop('TTY_COMPATIBLE', None); console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: False\n", "stderr": "", "exit_code": 0}
30run_command
{
 "command": "python3 -c \"import os; from rich.console import Console; os.environ['TTY_COMPATIBLE'] = '1'; console = Console(); print(f'is_terminal: {console.is_terminal}')\""
}
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "is_terminal: True\n", "stderr": "", "exit_code": 0}
31submit_patch
{}
{"status": "ok", "patch_size": 633, "files_changed": 1}
full
{"status": "ok", "patch_size": 633, "files_changed": 1}

Patch

diff --git a/rich/console.py b/rich/console.py
index 3ec9a8aa..c42e88f2 100644
--- a/rich/console.py
+++ b/rich/console.py
@@ -954,6 +954,12 @@ class Console:
             self._force_terminal = True
             return True
 
+        # If TTY_COMPATIBLE env var has any value at all, we assume a terminal.
+        tty_compatible = self._environ.get("TTY_COMPATIBLE")
+        if tty_compatible is not None:
+            self._force_terminal = True
+            return True
+
         isatty: Optional[Callable[[], bool]] = getattr(self.file, "isatty", None)
         try:
             return False if isatty is None else isatty()

Test output

show
........................................................................ [ 72%]
..........................F
=================================== FAILURES ===================================
_____________________________ test_tty_compatible ______________________________

    def test_tty_compatible() -> None:
        """Check TTY_COMPATIBLE environment var."""
    
        class FakeTTY:
            """An file file-like which reports it is a TTY."""
    
            def __init__(self) -> None:
                self.called_isatty = False
    
            def isatty(self) -> bool:
                self.called_isatty = True
                return True
    
        class FakeFile:
            """A file object that reports False for isatty"""
    
            def __init__(self) -> None:
                self.called_isatty = False
    
            def isatty(self) -> bool:
                self.called_isatty = True
                return False
    
        # Console file is not a TTY
        console = Console(file=FakeFile())
        # Not a TTY, so is_terminal should be False
        assert not console.is_terminal
        # Should have called isatty to auto-detect tty support
        assert console.file.called_isatty
    
        # Not a terminal
        console = Console(file=FakeFile(), _environ={"TTY_COMPATIBLE": "1"})
        # env TTY_COMPATIBLE=1 should report that it is a terminal
        assert console.is_terminal
        # Should not have called file.isattry
        assert not console.file.called_isatty
    
        # File is a fake TTY
        console = Console(file=FakeTTY())
        # Should report True
        assert console.is_terminal
        # SHould have auto-detected
        assert console.file.called_isatty
    
        # File is a fake TTY
        console = Console(file=FakeTTY(), _environ={"TTY_COMPATIBLE": ""})
        # Blank TTY_COMPATIBLE should auto-detect, so is_terminal is True
        assert console.is_terminal
        # Should have auto-detected
>       assert console.file.called_isatty
E       assert False
E        +  where False = <tests.test_console.test_tty_compatible.<locals>.FakeTTY object at 0x104258690>.called_isatty
E        +    where <tests.test_console.test_tty_compatible.<locals>.FakeTTY object at 0x104258690> = <console width=80 ColorSystem.STANDARD>.file

tests/test_console.py:1098: AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 98 passed in 0.71s