Skip to content

Commit

Permalink
Merge pull request #2678 from Textualize/fileno
Browse files Browse the repository at this point in the history
robust handling of fileno
  • Loading branch information
willmcgugan committed Nov 30, 2022
2 parents 5baaf50 + 6925187 commit 9c0f164
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 5 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bumped minimum Python version to 3.7 https://github.com/Textualize/rich/pull/2567
- Pretty-printing of "tagged" `__repr__` results is now greedy when matching tags https://github.com/Textualize/rich/pull/2565

### Fixed

- Handling of broken `fileno` made more robust. Fixes https://github.com/Textualize/rich/issues/2645

### Added

- Add type annotation for key_separator of pretty.Node https://github.com/Textualize/rich/issues/2625


## [12.6.0] - 2022-10-02

### Added
Expand Down
24 changes: 24 additions & 0 deletions rich/_fileno.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

from typing import IO, Callable


def get_fileno(file_like: IO[str]) -> int | None:
"""Get fileno() from a file, accounting for poorly implemented file-like objects.
Args:
file_like (IO): A file-like object.
Returns:
int | None: The result of fileno if available, or None if operation failed.
"""
fileno: Callable[[], int] | None = getattr(file_like, "fileno", None)
if fileno is not None:
try:
return fileno()
except Exception:
# `fileno` is documented as potentially raising a OSError
# Alas, from the issues, there are so many poorly implemented file-like objects,
# that `fileno()` can raise just about anything.
return None
return None
9 changes: 4 additions & 5 deletions rich/console.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import inspect
import io
import os
import platform
import sys
Expand Down Expand Up @@ -48,6 +47,7 @@
from . import errors, themes
from ._emoji_replace import _emoji_replace
from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT
from ._fileno import get_fileno
from ._log_render import FormatTimeCallable, LogRender
from .align import Align, AlignMethod
from .color import ColorSystem, blend_rgb
Expand Down Expand Up @@ -2006,12 +2006,11 @@ def _check_buffer(self) -> None:
if WINDOWS:
use_legacy_windows_render = False
if self.legacy_windows:
try:
fileno = get_fileno(self.file)
if fileno is not None:
use_legacy_windows_render = (
self.file.fileno() in _STD_STREAMS_OUTPUT
fileno in _STD_STREAMS_OUTPUT
)
except (ValueError, io.UnsupportedOperation):
pass

if use_legacy_windows_render:
from rich._win32_console import LegacyWindowsTerm
Expand Down
25 changes: 25 additions & 0 deletions tests/test_getfileno.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rich._fileno import get_fileno


def test_get_fileno():
class FileLike:
def fileno(self) -> int:
return 123

assert get_fileno(FileLike()) == 123


def test_get_fileno_missing():
class FileLike:
pass

assert get_fileno(FileLike()) is None


def test_get_fileno_broken():
class FileLike:
def fileno(self) -> int:
1 / 0
return 123

assert get_fileno(FileLike()) is None

0 comments on commit 9c0f164

Please sign in to comment.