[BUG] Rich 12.0.0 fails to write to stdout attached to a pipe on Windows
See original GitHub issueDescribe the bug
Since rich 12.0.0, printing to stdout fails running under a subprocess attached to a pipe on Windows.
To reproduce, save the following reproducer and run it first with rich==12.0.0
import subprocess
import sys
code = """\
import sys
from rich.console import Console
console = Console(file=sys.stdout)
console.print("spam")
"""
err_code = code.replace("sys.stdout", "sys.stderr")
cmd = [sys.executable, "-"]
print("[capture_output=True via sys.stdout]")
proc = subprocess.run(cmd, input=code, capture_output=True, encoding="utf-8")
print(f"{proc.stdout=} {proc.stderr=}")
print("[capture_output=True via sys.stderr]")
proc = subprocess.run(cmd, input=err_code, capture_output=True, encoding="utf-8")
print(f"{proc.stdout=} {proc.stderr=}")
print("[capture_output=False via sys.stdout]")
proc = subprocess.run(cmd, input=code, capture_output=False, encoding="utf-8")
Thereโs a few observations here:
- With rich==12.0.0 installed, the captured stdout is empty. With an older version it works fine (see orange / blue)
- Standard error is completely unaffected. Itโs also fine letting the subprocess inherit the streams (see green)
Platform
Python: CPython 3.8.5 OS: Windows 10 Home 21H2 (build 19044.1526) Terminal: Windows Terminal 1.11.3471.0
rich.diagnose
(venv) PS R:\Programming\diff-shades> python -m rich.diagnose
โญโโโโโโโโโโโโโโโโโโโโโโโโโ <class 'rich.console.Console'> โโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ A high level console interface. โ
โ โ
โ โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ โ
โ โ <console width=148 ColorSystem.TRUECOLOR> โ โ
โ โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ โ
โ โ
โ color_system = 'truecolor' โ
โ encoding = 'utf-8' โ
โ file = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'> โ
โ height = 35 โ
โ 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=148, height=35), โ
โ legacy_windows=False, โ
โ min_width=1, โ
โ max_width=148, โ
โ is_terminal=True, โ
โ encoding='utf-8', โ
โ max_height=35, โ
โ justify=None, โ
โ overflow=None, โ
โ no_wrap=False, โ
โ highlight=None, โ
โ markup=None, โ
โ height=None โ
โ ) โ
โ quiet = False โ
โ record = False โ
โ safe_box = True โ
โ size = ConsoleDimensions(width=148, height=35) โ
โ soft_wrap = False โ
โ stderr = False โ
โ style = None โ
โ tab_size = 8 โ
โ width = 148 โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โญโโ <class 'rich._windows.WindowsConsoleFeatures'> โโโโฎ
โ Windows features available. โ
โ โ
โ โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ โ
โ โ WindowsConsoleFeatures(vt=True, truecolor=True) โ โ
โ โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ โ
โ โ
โ truecolor = True โ
โ vt = True โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โญโโโโโโ Environment Variables โโโโโโโโฎ
โ { โ
โ 'TERM': None, โ
โ 'COLORTERM': None, โ
โ 'CLICOLOR': None, โ
โ 'NO_COLOR': None, โ
โ 'TERM_PROGRAM': None, โ
โ 'COLUMNS': None, โ
โ 'LINES': None, โ
โ 'JPY_PARENT_PID': None, โ
โ 'VSCODE_VERBOSE_LOGGING': None โ
โ } โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
platform="Windows"
Additional context
This was discovered by GHA Windows CI (the problem is hidden and buried in this test, but this shows it has been reproduced under several environments[^1]). Original investigation into this strange behaviour happened in the #black-formatter channel on Python Discord.
According to @jack1142 who helped me investigate it, itโs related to the recent move to replace colorama with first-party code that interacts with the Windows APIs:
Iโm pretty sure itโs because it canโt use WriteConsole API (the one thatโs used for legacy console printing) when itโs piped because output from WriteConsole is not capturable
They then shared this excerpt from Windows console API documentation:
WriteConsole fails if it is used with a standard handle that is redirected to a file. If an application processes multilingual output that can be redirected, determine whether the output handle is a console handle (one method is to call the GetConsoleMode function and check whether it succeeds). If the handle is a console handle, call WriteConsole. If the handle is not a console handle, the output is redirected and you should call WriteFile to perform the I/O. https://docs.microsoft.com/en-us/windows/console/writeconsole
[^1]: if youโre curious, itโs basically testing whether recording the output (via Console(record=True)
) and then dumping it as HTML works as expected with the rest of the tool
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:6
Can confirm all reported cases are fixed on master, many thanks! @darrenburns
@ichard26 Thanks for investigating in such detail, and for the examples. It really helps! Iโll take a look into these issues shortly ๐