rich icon indicating copy to clipboard operation
rich copied to clipboard

[BUG] Color Disappears When Using Piping on Windows, Even with force_terminal Enabled.

Open undecV opened this issue 2 years ago • 5 comments

  • [x] I've checked docs and closed issues for possible solutions.
  • [x] I can't find my issue in the FAQ.

Describe the bug

I'm trying to use Rich with pipe and the command tee and watch. On Windows, both in CMD, Powershell, new Windows Terminal, and VSCode Terminal. When using pipes, the output loses color even if foece_terminal is set.

from datetime import datetime
from rich.console import Console
from rich.logging import RichHandler
from colorama import Fore
import logging

logging.basicConfig(level=logging.DEBUG, handlers=[RichHandler()])
logger = logging.getLogger(__name__)

console = Console(color_system="auto", force_terminal=True, force_interactive=False, highlight=False)
now = datetime.now().isoformat('T')

console.print(f"no_color: [red]{console.no_color}[/]")
console.print(f"is_terminal: [red]{console.is_terminal}[/]")
console.print(f"is_dumb_terminal: [red]{console.is_dumb_terminal}[/]")
console.print(f"color_system: [red]{console.color_system}[/]")
console.print(f"[red]{now}[/red]")
print(f"{Fore.RED}{now}{Fore.RESET}")
logger.debug("[red]Bla[/]", extra={"markup": True})

Screenshot (Windows side): Screenshot (Windows side) The red line is colored by colorama, for comparison.

I ran the same code in WSL. Screenshot (Linux side, WSL) (Expected output): Screenshot (WSL side)

Might be related to #2622.

Platform

I'm using Windows 11, Python 3.11.4 (Windows), and Python 3.10.12 (WSL). I tried both in Windows terminal and VSCode terminal. Both had the same observation.

Windows side (VSCode)
rich==13.5.2
textual==0.32.0

rich.diagnose

╭───────────────────────── <class 'rich.console.Console'> ─────────────────────────╮
│ A high level console interface.                                                  │
│                                                                                  │
│ ╭──────────────────────────────────────────────────────────────────────────────╮ │
│ │ <console width=166 ColorSystem.TRUECOLOR>                                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                  │
│     color_system = 'truecolor'                                                   │
│         encoding = 'utf-8'                                                       │
│             file = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> │
│           height = 15                                                            │
│    is_alt_screen = False                                                         │
│ is_dumb_terminal = False                                                         │
│   is_interactive = True                                                          │
│       is_jupyter = False                                                         │
│      is_terminal = True                                                          │
│   legacy_windows = False                                                         │
│         no_color = False                                                         │
│          options = ConsoleOptions(                                               │
│                        size=ConsoleDimensions(width=166, height=15),             │
│                        legacy_windows=False,                                     │
│                        min_width=1,                                              │
│                        max_width=166,                                            │
│                        is_terminal=True,                                         │
│                        encoding='utf-8',                                         │
│                        max_height=15,                                            │
│                        justify=None,                                             │
│                        overflow=None,                                            │
│                        no_wrap=False,                                            │
│                        highlight=None,                                           │
│                        markup=None,                                              │
│                        height=None                                               │
│                    )                                                             │
│            quiet = False                                                         │
│           record = False                                                         │
│         safe_box = True                                                          │
│             size = ConsoleDimensions(width=166, height=15)                       │
│        soft_wrap = False                                                         │
│           stderr = False                                                         │
│            style = None                                                          │
│         tab_size = 8                                                             │
│            width = 166                                                           │
╰──────────────────────────────────────────────────────────────────────────────────╯
╭── <class 'rich._windows.WindowsConsoleFeatures'> ───╮
│ Windows features available.                         │
│                                                     │
│ ╭─────────────────────────────────────────────────╮ │
│ │ WindowsConsoleFeatures(vt=True, truecolor=True) │ │
│ ╰─────────────────────────────────────────────────╯ │
│                                                     │
│ truecolor = True                                    │
│        vt = True                                    │
╰─────────────────────────────────────────────────────╯
╭────── Environment Variables ───────╮
│ {                                  │
│     'TERM': None,                  │
│     'COLORTERM': 'truecolor',      │
│     'CLICOLOR': None,              │
│     'NO_COLOR': None,              │
│     'TERM_PROGRAM': 'vscode',      │
│     'COLUMNS': None,               │
│     'LINES': None,                 │
│     'JUPYTER_COLUMNS': None,       │
│     'JUPYTER_LINES': None,         │
│     'JPY_PARENT_PID': None,        │
│     'VSCODE_VERBOSE_LOGGING': None │
│ }                                  │
╰────────────────────────────────────╯
platform="Windows"
Linux side (WSL, VSCode)
rich==13.5.2
textual==0.32.0

rich.diagnose

╭───────────────────────── <class 'rich.console.Console'> ─────────────────────────╮
│ A high level console interface.                                                  │
│                                                                                  │
│ ╭──────────────────────────────────────────────────────────────────────────────╮ │
│ │ <console width=179 ColorSystem.TRUECOLOR>                                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                  │
│     color_system = 'truecolor'                                                   │
│         encoding = 'utf-8'                                                       │
│             file = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> │
│           height = 15                                                            │
│    is_alt_screen = False                                                         │
│ is_dumb_terminal = False                                                         │
│   is_interactive = True                                                          │
│       is_jupyter = False                                                         │
│      is_terminal = True                                                          │
│   legacy_windows = False                                                         │
│         no_color = False                                                         │
│          options = ConsoleOptions(                                               │
│                        size=ConsoleDimensions(width=179, height=15),             │
│                        legacy_windows=False,                                     │
│                        min_width=1,                                              │
│                        max_width=179,                                            │
│                        is_terminal=True,                                         │
│                        encoding='utf-8',                                         │
│                        max_height=15,                                            │
│                        justify=None,                                             │
│                        overflow=None,                                            │
│                        no_wrap=False,                                            │
│                        highlight=None,                                           │
│                        markup=None,                                              │
│                        height=None                                               │
│                    )                                                             │
│            quiet = False                                                         │
│           record = False                                                         │
│         safe_box = True                                                          │
│             size = ConsoleDimensions(width=179, height=15)                       │
│        soft_wrap = False                                                         │
│           stderr = False                                                         │
│            style = None                                                          │
│         tab_size = 8                                                             │
│            width = 179                                                           │
╰──────────────────────────────────────────────────────────────────────────────────╯
╭─── <class 'rich._windows.WindowsConsoleFeatures'> ────╮
│ Windows features available.                           │
│                                                       │
│ ╭───────────────────────────────────────────────────╮ │
│ │ WindowsConsoleFeatures(vt=False, truecolor=False) │ │
│ ╰───────────────────────────────────────────────────╯ │
│                                                       │
│ truecolor = False                                     │
│        vt = False                                     │
╰───────────────────────────────────────────────────────╯
╭────── Environment Variables ───────╮
│ {                                  │
│     'TERM': 'xterm-256color',      │
│     'COLORTERM': 'truecolor',      │
│     'CLICOLOR': None,              │
│     'NO_COLOR': None,              │
│     'TERM_PROGRAM': 'vscode',      │
│     'COLUMNS': None,               │
│     'LINES': None,                 │
│     'JUPYTER_COLUMNS': None,       │
│     'JUPYTER_LINES': None,         │
│     'JPY_PARENT_PID': None,        │
│     'VSCODE_VERBOSE_LOGGING': None │
│ }                                  │
╰────────────────────────────────────╯
platform="Linux"

undecV avatar Aug 10 '23 21:08 undecV

Thank you for your issue. Give us a little time to review it.

PS. You might want to check the FAQ if you haven't done so already.

This is an automated reply, generated by FAQtory

github-actions[bot] avatar Aug 10 '23 21:08 github-actions[bot]

Encountered the same problem on Windows 10. Piping kills the colors, even with force_terminal=True.

Works as expected on Mac OSX and Linux.

zapta avatar Jan 29 '25 18:01 zapta

I managed to get colors piped out by forcingvt=True after this line:

https://github.com/Textualize/rich/blob/43d3b04725ab9731727fb1126e35980c62f32377/rich/_windows.py#L53

Looking at the code, it seems that the force_terminal signal in the Console initialization doesn't reach down to the windows code that determines if there is a terminal (I presume that vt refers to vt100 or similar).

A possible fix would be to add to get_windows_console_features() a parameter force_terminal that will force vt=True and then add in console.py have a second variable _windows_console_features_forced that will cache the features for the cases where the console is initialized with force_terminal.

Any takes?

zapta avatar Jan 30 '25 08:01 zapta

This is the workaround that we implemented for the meantime. The parent process passes to the child process its vt and truecolor values and the child process replicated them. In our case the parameters are passed via a Protocol Buffer record but should work just the same with command line arguments.

import sys
import rich.console
from apio.common.proto.apio_pb2 import RichLibWindowsParams

# For accessing rich.console._windows_console_features
# pylint: disable=protected-access


def get_workaround_parametes() -> RichLibWindowsParams:
    """Called on the apio (parent) process side, when running on windows,
    to collect the parameters for the rich library workaround."""
    result = RichLibWindowsParams(
        stdout_encoding=sys.stdout.encoding,
        vt=rich.console._windows_console_features.vt,
        truecolor=rich.console._windows_console_features.truecolor,
    )
    assert result.IsInitialized(), result
    return result


def apply_workaround(params: RichLibWindowsParams):
    """Called on the scons (child) process side, when running on windows,
    to apply the the workaround for the rich library."""
    assert params.IsInitialized, params

    # This takes care of the table graphic box.
    # https://github.com/Textualize/rich/issues/3625
    sys.stdout.reconfigure(encoding=params.stdout_encoding)

    # This enables the colors.
    # https://github.com/Textualize/rich/issues/3082
    assert rich.console._windows_console_features is not None
    rich.console._windows_console_features.vt = params.vt
    rich.console._windows_console_features.truecolor = params.truecolor

zapta avatar Jan 30 '25 18:01 zapta

Thank you so much for following up on this issue! Honestly, trying to understand or even fix this problem is way beyond my capabilities. QAQ

I've opted for an alternative solution in my project for now, but if this issue gets resolved, I'd be more than happy to use Rich for the same purpose. After all, Rich is much more elegant!

undecV avatar Feb 01 '25 13:02 undecV