Skip to content

[BUG] [Windows] ANSI SGR sequences printed to streams which are not attached to TTYs. #3693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 tasks done
emcd opened this issue Apr 5, 2025 · 4 comments
Closed
2 tasks done

Comments

@emcd
Copy link

emcd commented Apr 5, 2025

Describe the bug

On Windows, ANSI SGR sequences are emitted regardless of whether a stream is attached to a TTY or not.
The following simple reproducer will correctly print an uncolored "foo" on non-Windows platforms but will print a red "foo" on Windows:

from locale import getpreferredencoding
from os import devnull
from rich.console import Console
from rich.style import Style

blackhole = open( devnull, 'w', encoding = getpreferredencoding( ) )
console = Console( file = blackhole )
with console.capture( ) as capture:
    console.print( 'foo', style = Style( color = 'red' ) )

# Prints plain 'foo' on non-Windows; prints red 'foo' on Windows.
# Should print plain 'foo' on all platforms.
print( capture.get( ) )

The null device is definitely not a TTY, but capture on a Console print will show that ANSI C1 sequences are being emitted.

Image

Expected behavior is that a plain "foo" would be printed on all platforms.

Closely related to #3647. (And maybe fixed by #3648, though it is not clear that the terminal on the Github Actions Windows runners is a legacy terminal. But, it seems like the code path for legacy terminal detection is not different than that for non-terminal detection on Windows, so the fix may be valid. Would definitely like to see the fix or a maintainer-approved variant thereof merged.)

Possibly has some bearing on #2622 and #3082, even though they are the "opposite" problem.

Platforms

Platform 1: (exhibits bug)

Windows 10, CMD.EXE
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── <class 'rich.console.Console'> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ A high level console interface. │
│ │
│ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ color_system = 'truecolor' │
│ encoding = 'utf-8' │
│ file = <_io.TextIOWrapper name='' mode='w' encoding='utf-8'> │
│ height = 76 │
│ 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=270, height=76), legacy_windows=False, min_width=1, max_width=270, is_terminal=True, encoding='utf-8', max_height=76, justify=None, overflow=None, no_wrap=False, highlight=None, markup=None, height=None) │
│ quiet = False │
│ record = False │
│ safe_box = True │
│ size = ConsoleDimensions(width=270, height=76) │
│ soft_wrap = False │
│ stderr = False │
│ style = None │
│ tab_size = 8 │
│ width = 270 │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭── <class 'rich._windows.WindowsConsoleFeatures'> ───╮
│ Windows features available. │
│ │
│ ╭─────────────────────────────────────────────────╮ │
│ │ WindowsConsoleFeatures(vt=True, truecolor=True) │ │
│ ╰─────────────────────────────────────────────────╯ │
│ │
│ truecolor = True │
│ vt = True │
╰─────────────────────────────────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Environment Variables ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ {'CLICOLOR': None, 'COLORTERM': None, 'COLUMNS': None, 'JPY_PARENT_PID': None, 'JUPYTER_COLUMNS': None, 'JUPYTER_LINES': None, 'LINES': None, 'NO_COLOR': None, 'TERM_PROGRAM': None, 'TERM': None, 'TTY_COMPATIBLE': None, 'VSCODE_VERBOSE_LOGGING': None} │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
platform="Windows"

rich==14.0.0

Platform 2: (exhibits bug)

Github Actions Windows runner (Windows 11?), Git Bash (mintty)?

Platform 3: (does not exhibit bug)

Ubuntu 22.04 (GNU/Linux)

Copy link

github-actions bot commented Apr 5, 2025

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

emcd added a commit to emcd/python-icecream-truck that referenced this issue Apr 5, 2025
@xymy
Copy link
Contributor

xymy commented Apr 10, 2025

I think your issue is not related to #3647. In your code, blackhole.isatty() is True, which leads to console.is_terminal is True. So rich will not strip ANSI code.

Try to open a random file, and it does not print ANSI color code any more:

from locale import getpreferredencoding
from os import devnull
from rich.console import Console
from rich.style import Style

# Change filename to 'foo'
blackhole = open( 'foo', 'w', encoding = getpreferredencoding( ) )
console = Console( file = blackhole )
with console.capture( ) as capture:
    console.print( 'foo', style = Style( color = 'red' ) )

# Does not print ANSI color code any more
print( capture.get( ) )

@emcd
Copy link
Author

emcd commented Apr 10, 2025

I think your issue is not related to #3647. In your code, blackhole.isatty() is True,

The null device is not a TTY on POSIX systems:

>>> sys.platform
'linux'
>>> f = open( os.devnull, 'w' )
>>> f.isatty( )
False

However, you appear to be correct about the behavior on Windows:

>>> sys.platform
'win32'
>>> f = open( os.devnull, 'w' )
>>> f.isatty( )
True

That is very unintuitive. Will withdraw this issue. Thanks for the followup.

@emcd emcd closed this as completed Apr 10, 2025
Copy link

I hope we solved your problem.

If you like using Rich, you might also enjoy Textual

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants
@emcd @xymy and others