Skip to content

Commit

Permalink
Adds ability to configure stderr output color
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Oct 28, 2024
1 parent ab51e14 commit 799495c
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/changelog/3426.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Adds ability to configure the stderr color for output received from external
commands.
8 changes: 8 additions & 0 deletions src/tox/config/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Type, TypeVar, cast

from colorama import Fore

from tox.config.loader.str_convert import StrConvert
from tox.plugin import NAME
from tox.util.ci import is_ci
Expand Down Expand Up @@ -366,6 +368,12 @@ def add_color_flags(parser: ArgumentParser) -> None:
choices=["yes", "no"],
help="should output be enriched with colors, default is yes unless TERM=dumb or NO_COLOR is defined.",
)
parser.add_argument(
"--stderr-color",
default="RED",
choices=["0", *Fore.__dict__.keys()],
help="color for stderr output, use 0 to disable coloring.",
)


def add_exit_and_dump_after(parser: ArgumentParser) -> None:
Expand Down
8 changes: 7 additions & 1 deletion src/tox/execute/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,17 @@ def call(
env: ToxEnv,
) -> Iterator[ExecuteStatus]:
start = time.monotonic()
stderr_color = Fore.RED
try:
cfg_color = env.conf._conf.options.stderr_color # noqa: SLF001
stderr_color = None if cfg_color == "0" else Fore.__dict__[cfg_color]
except (AttributeError, KeyError, TypeError): # many tests have a mocked 'env'
pass
try:
# collector is what forwards the content from the file streams to the standard streams
out, err = out_err[0].buffer, out_err[1].buffer
out_sync = SyncWrite(out.name, out if show else None)
err_sync = SyncWrite(err.name, err if show else None, Fore.RED if self._colored else None)
err_sync = SyncWrite(err.name, err if show else None, stderr_color)
with out_sync, err_sync:
instance = self.build_instance(request, self._option_class(env), out_sync, err_sync)
with instance as status:
Expand Down
2 changes: 2 additions & 0 deletions tests/config/cli/test_cli_env_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def test_verbose_no_test() -> None:
"verbose": 4,
"quiet": 0,
"colored": "no",
"stderr_color": "RED",
"work_dir": None,
"root_dir": None,
"config_file": None,
Expand Down Expand Up @@ -90,6 +91,7 @@ def test_env_var_exhaustive_parallel_values(
assert vars(options.parsed) == {
"always_copy": False,
"colored": "no",
"stderr_color": "RED",
"command": "legacy",
"default_runner": "virtualenv",
"develop": False,
Expand Down
2 changes: 2 additions & 0 deletions tests/config/cli/test_cli_ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
def default_options() -> dict[str, Any]:
return {
"colored": "no",
"stderr_color": "RED",
"command": "r",
"default_runner": "virtualenv",
"develop": False,
Expand Down Expand Up @@ -200,6 +201,7 @@ def test_ini_exhaustive_parallel_values(core_handlers: dict[str, Callable[[State
options = get_options("p")
assert vars(options.parsed) == {
"colored": "yes",
"stderr_color": "RED",
"command": "p",
"default_runner": "virtualenv",
"develop": False,
Expand Down

0 comments on commit 799495c

Please sign in to comment.