Skip to content
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

Handle recording on legacy mode Windows consoles #2066

Merged
merged 11 commits into from Mar 18, 2022
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fix capturing stdout on legacy Windows https://github.com/Textualize/rich/pull/2055
- Fix capturing stdout on legacy Windows https://github.com/Textualize/rich/pull/2066

## [12.0.0] - 2022-03-10

Expand Down
5 changes: 3 additions & 2 deletions rich/_win32_console.py
Expand Up @@ -4,7 +4,7 @@
"""
import ctypes
import sys
from typing import Any, NamedTuple, Type, cast
from typing import Any

windll: Any = None
if sys.platform == "win32":
Expand All @@ -14,6 +14,7 @@

import time
from ctypes import Structure, byref, wintypes
from typing import IO, NamedTuple, Type, cast

from rich.color import ColorSystem
from rich.style import Style
Expand Down Expand Up @@ -333,7 +334,7 @@ class LegacyWindowsTerm:
15, # bright white
]

def __init__(self, file: IO[str]) -> None:
def __init__(self, file: "IO[str]") -> None:
handle = GetStdHandle(STDOUT)
self._handle = handle
default_text = GetConsoleScreenBufferInfo(handle).wAttributes
Expand Down
34 changes: 21 additions & 13 deletions rich/console.py
Expand Up @@ -2,6 +2,7 @@
import io
import os
import platform
import pty
import sys
import threading
from abc import ABC, abstractmethod
Expand Down Expand Up @@ -1909,12 +1910,21 @@ def log(
buffer_extend(line)

def _check_buffer(self) -> None:
"""Check if the buffer may be rendered."""
"""Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False)
Rendering is supported on Windows, Unix and Jupyter environments. For
legacy Windows consoles, the win32 API is called directly.
This method will also record what it renders if recording is enabled via Console.record.
"""
if self.quiet:
del self._buffer[:]
return
with self._lock:
if self._buffer_index == 0:

if self.record:
with self._record_buffer_lock:
self._record_buffer.extend(self._buffer[:])

if self.is_jupyter: # pragma: no cover
from .jupyter import display

Expand All @@ -1927,18 +1937,19 @@ def _check_buffer(self) -> None:
except (ValueError, io.UnsupportedOperation):
file_no = -1

legacy_windows_stdout = self.legacy_windows and file_no == 1
if legacy_windows_stdout:
stdout_num = pty.STDOUT_FILENO
stderr_num = pty.STDERR_FILENO
is_std_stream = file_no in (stdout_num, stderr_num)
legacy_windows_std = self.legacy_windows and is_std_stream
if legacy_windows_std:
from rich._win32_console import LegacyWindowsTerm
from rich._windows_renderer import legacy_windows_render

with open(file_no, "w") as output_file:
legacy_windows_render(
self._buffer[:], LegacyWindowsTerm(output_file)
)

output_capture_enabled = bool(self._buffer_index)
if not legacy_windows_stdout or output_capture_enabled:
legacy_windows_render(
self._buffer[:], LegacyWindowsTerm(self.file)
)
else:
# Either a non-std stream on legacy Windows, or modern Windows.
text = self._render_buffer(self._buffer[:])
# https://bugs.python.org/issue37871
write = self.file.write
Expand All @@ -1965,9 +1976,6 @@ def _render_buffer(self, buffer: Iterable[Segment]) -> str:
append = output.append
color_system = self._color_system
legacy_windows = self.legacy_windows
if self.record:
with self._record_buffer_lock:
self._record_buffer.extend(buffer)
not_terminal = not self.is_terminal
if self.no_color and color_system:
buffer = Segment.remove_color(buffer)
Expand Down