failed WRONG_FIX wrong_fix · 30 tool calls · 105 s · Textualize/rich
TTY_COMPATIBLE Implement new `TTY_COMPATIBLE` environment variable @ofek @webknjaz @hugovk Relevant discussion: https://github.com/Textualize/rich/issues/2924
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_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} |
| 2 | read_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} |
| 3 | read_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} |
| 4 | read_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/Ofull{"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} |
| 5 | read_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} |
| 6 | run_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 afull{"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} |
| 7 | edit_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} |
| 8 | run_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; frofull{"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}} |
| 9 | run_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} |
| 10 | read_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 ConsoleOptionsfull{"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} |
| 11 | read_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: Optionafull{"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 |
| 12 | read_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 elsefull{"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 |
| 13 | run_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} |
| 14 | read_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.hefull{"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 |
| 15 | run_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} |
| 16 | read_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 = Falfull{"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 |
| 17 | read_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} |
| 18 | read_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\", \"tfull{"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} |
| 19 | read_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 highlifull{"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 |
| 20 | read_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(linfull{"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} |
| 21 | read_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."} |
| 22 | read_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._cfull{"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} |
| 23 | run_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} |
| 24 | run_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} |
| 25 | run_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} |
| 26 | run_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} |
| 27 | run_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} |
| 28 | run_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} |
| 29 | run_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} |
| 30 | run_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} |
| 31 | submit_patch | {} | {"status": "ok", "patch_size": 633, "files_changed": 1}full{"status": "ok", "patch_size": 633, "files_changed": 1} |
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()
........................................................................ [ 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