TTY_INTERACTIVE env var

This commit is contained in:
Will McGugan 2025-06-20 21:23:40 +01:00
parent 49117ced66
commit 0ab2467297
5 changed files with 44 additions and 4 deletions

View file

@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed extraction of recursive exceptions https://github.com/Textualize/rich/pull/3772
### Addedd
- Added `TTY_INTERACTIVE` environment variable to force interactive mode off or on.
## [14.0.0] - 2025-03-30
### Added

View file

@ -410,8 +410,6 @@ Interactive mode
Rich will remove animations such as progress bars and status indicators when not writing to a terminal as you probably don't want to write these out to a text file (for example). You can override this behavior by setting the ``force_interactive`` argument on the constructor. Set it to True to enable animations or False to disable them.
.. note::
Some CI systems support ANSI color and style but not anything that moves the cursor or selectively refreshes parts of the terminal. For these you might want to set ``force_terminal`` to ``True`` and ``force_interactive`` to ``False``.
Environment variables
---------------------
@ -429,8 +427,10 @@ If the environment variable ``NO_COLOR`` is set, Rich will disable all color in
The environment variable ``TTY_COMPATIBLE`` is used to override Rich's auto-detection of terminal support. If ``TTY_COMPATIBLE`` is set to ``1`` then Rich will assume it is writing to a device which can handle escape sequences like a terminal. If ``TTY_COMPATIBLE`` is set to ``"0"``, then Rich will assume that it is writing to a device that is *not* capable of displaying escape sequences (such as a regular file). If the variable is not set, or set to a value other than "0" or "1", then Rich will attempt to auto-detect terminal support.
The environment variable ``TTY_INTERACTIVE`` is used to override Rich's auto-detection of interactive mode (see above). If you set this to ``"0"``, it will disable interactive mode even if Rich thinks it is writing to a terminal. Set this to ``"1"`` to force interactive mode on. If this environment variable is not set, or set to any other value, then interactive mode will be auto-detected as normal.
.. note::
If you want Rich output in CI or Github Actions, then you should set ``TTY_COMPATIBLE=1``.
If you want Rich output in CI or Github Actions, then you should set ``TTY_COMPATIBLE=1`` and ``TTY_INTERACTIVE=0``.
If ``width`` / ``height`` arguments are not explicitly provided as arguments to ``Console`` then the environment variables ``COLUMNS`` / ``LINES`` can be used to set the console width / height. ``JUPYTER_COLUMNS`` / ``JUPYTER_LINES`` behave similarly and are used in Jupyter.

View file

@ -22,18 +22,20 @@ from typing import (
Dict,
Iterable,
List,
Literal,
Mapping,
NamedTuple,
Optional,
Protocol,
TextIO,
Tuple,
Type,
Union,
cast,
runtime_checkable,
)
from rich._null_file import NULL_FILE
from typing import Literal, Protocol, runtime_checkable
from . import errors, themes
from ._emoji_replace import _emoji_replace
@ -731,6 +733,14 @@ class Console:
if no_color is not None
else self._environ.get("NO_COLOR", "") != ""
)
if force_interactive is None:
tty_interactive = self._environ.get("TTY_INTERACTIVE", None)
if tty_interactive is not None:
if tty_interactive == "0":
force_interactive = False
elif tty_interactive == "1":
force_interactive = True
self.is_interactive = (
(self.is_terminal and not self.is_dumb_terminal)
if force_interactive is None

View file

@ -26,6 +26,7 @@ def report() -> None: # pragma: no cover
"TERM_PROGRAM",
"TERM",
"TTY_COMPATIBLE",
"TTY_INTERACTIVE",
"VSCODE_VERBOSE_LOGGING",
)
env = {name: os.getenv(name) for name in env_names}

View file

@ -1038,6 +1038,31 @@ def test_capture_and_record() -> None:
assert recorded_content == "Print 0\n"
def test_tty_interactive() -> None:
"""Check TTY_INTERACTIVE environment var."""
# Bytes file, not interactive
console = Console(file=io.BytesIO())
assert not console.is_interactive
# Bytes file, force interactive
console = Console(file=io.BytesIO(), _environ={"TTY_INTERACTIVE": "1"})
assert console.is_interactive
# Force tty compatible, should be interactive
console = Console(file=io.BytesIO(), _environ={"TTY_COMPATIBLE": "1"})
assert console.is_interactive
# Force tty compatible, force not interactive
console = Console(
file=io.BytesIO(), _environ={"TTY_COMPATIBLE": "1", "TTY_INTERACTIVE": "0"}
)
# Bytes file, Unknown value of TTY_INTERACTIVE should still auto-detect
console = Console(file=io.BytesIO(), _environ={"TTY_INTERACTIVE": "foo"})
assert not console.is_interactive
def test_tty_compatible() -> None:
"""Check TTY_COMPATIBLE environment var."""