mirror of https://github.com/Textualize/rich.git
Fall back to `sys.__stderr__` on non-Windows OS to get size
This fixes the "pipe" bug, where we could not determine the available size correctly when the output of Rich is piped to another process
This commit is contained in:
parent
41bf6372c5
commit
d98d671c49
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fall back to `sys.__stderr__` on POSIX systems when trying to get the terminal size (fix issues when Rich is piped to another process)
|
||||
|
||||
## [12.2.0] - 2022-04-05
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -27,6 +27,7 @@ The following people have contributed to the development of Rich:
|
|||
- [Nathan Page](https://github.com/nathanrpage97)
|
||||
- [Avi Perl](https://github.com/avi-perl)
|
||||
- [Laurent Peuch](https://github.com/psycojoker)
|
||||
- [Olivier Philippon](https://github.com/DrBenton)
|
||||
- [Kylian Point](https://github.com/p0lux)
|
||||
- [Kyle Pollina](https://github.com/kylepollina)
|
||||
- [Clément Robert](https://github.com/neutrinoceros)
|
||||
|
|
|
@ -1102,12 +1102,16 @@ class Console:
|
|||
except OSError: # Probably not a terminal
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
width, height = os.get_terminal_size(sys.__stdin__.fileno())
|
||||
except (AttributeError, ValueError, OSError):
|
||||
posix_std_descriptors = (
|
||||
sys.__stdin__, # try this one first...
|
||||
sys.__stdout__, # ...then that one...
|
||||
sys.__stderr__, # ...and ultimately try to fall back to this one
|
||||
)
|
||||
for descriptor in posix_std_descriptors:
|
||||
try:
|
||||
width, height = os.get_terminal_size(sys.__stdout__.fileno())
|
||||
except (AttributeError, ValueError, OSError):
|
||||
width, height = os.get_terminal_size(descriptor.fileno())
|
||||
break
|
||||
except (AttributeError, ValueError, OSError) as err:
|
||||
pass
|
||||
|
||||
columns = self._environ.get("COLUMNS")
|
||||
|
|
|
@ -3,7 +3,8 @@ import io
|
|||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple, Type, Union
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -122,6 +123,48 @@ def test_size():
|
|||
assert w == 99 and h == 101
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"is_windows,no_descriptor_size,stdin_size,stdout_size,stderr_size,expected_size",
|
||||
[
|
||||
# on Windows we'll use `os.get_terminal_size()` without arguments...
|
||||
(True, (133, 24), ValueError, ValueError, ValueError, (133, 24)),
|
||||
(False, (133, 24), ValueError, ValueError, ValueError, (80, 25)),
|
||||
# ...while on other OS we'll try to pass stdin, then stdout, then stderr to it:
|
||||
(False, ValueError, (133, 24), ValueError, ValueError, (133, 24)),
|
||||
(False, ValueError, ValueError, (133, 24), ValueError, (133, 24)),
|
||||
(False, ValueError, ValueError, ValueError, (133, 24), (133, 24)),
|
||||
(False, ValueError, ValueError, ValueError, ValueError, (80, 25)),
|
||||
],
|
||||
)
|
||||
@mock.patch("rich.console.os.get_terminal_size")
|
||||
def test_size_can_fall_back_to_std_descriptors(
|
||||
get_terminal_size_mock: mock.MagicMock,
|
||||
is_windows: bool,
|
||||
no_descriptor_size: Union[Tuple[int, int], Type[ValueError]],
|
||||
stdin_size: Union[Tuple[int, int], Type[ValueError]],
|
||||
stdout_size: Union[Tuple[int, int], Type[ValueError]],
|
||||
stderr_size: Union[Tuple[int, int], Type[ValueError]],
|
||||
expected_size,
|
||||
):
|
||||
def get_terminal_size_mock_impl(fileno: int = None) -> Tuple[int, int]:
|
||||
value = {
|
||||
None: no_descriptor_size,
|
||||
sys.__stdin__.fileno(): stdin_size,
|
||||
sys.__stdout__.fileno(): stdout_size,
|
||||
sys.__stderr__.fileno(): stderr_size,
|
||||
}[fileno]
|
||||
if value is ValueError:
|
||||
raise value
|
||||
return value
|
||||
|
||||
get_terminal_size_mock.side_effect = get_terminal_size_mock_impl
|
||||
|
||||
console = Console(legacy_windows=False)
|
||||
with mock.patch("rich.console.WINDOWS", new=is_windows):
|
||||
w, h = console.size
|
||||
assert (w, h) == expected_size
|
||||
|
||||
|
||||
def test_repr():
|
||||
console = Console()
|
||||
assert isinstance(repr(console), str)
|
||||
|
|
Loading…
Reference in New Issue