Skip to content

Commit c1c5a2b

Browse files
hugovknicoddemus
andauthored
Add support for NO_COLOR and FORCE_COLOR (#7466)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
1 parent 2ae721c commit c1c5a2b

File tree

4 files changed

+61
-14
lines changed

4 files changed

+61
-14
lines changed

changelog/7464.feature.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added support for ``NO_COLOR`` and ``FORCE_COLOR`` environment variables to control colored output.
2+
3+
For more information, see `the docs <https://docs.pytest.org/en/stable/reference.html#environment-variables>`__.

doc/en/reference.rst

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -988,10 +988,20 @@ Environment variables that can be used to change pytest's behavior.
988988
This contains a command-line (parsed by the py:mod:`shlex` module) that will be **prepended** to the command line given
989989
by the user, see :ref:`adding default options` for more information.
990990

991+
.. envvar:: PYTEST_CURRENT_TEST
992+
993+
This is not meant to be set by users, but is set by pytest internally with the name of the current test so other
994+
processes can inspect it, see :ref:`pytest current test env` for more information.
995+
991996
.. envvar:: PYTEST_DEBUG
992997

993998
When set, pytest will print tracing and debug information.
994999

1000+
.. envvar:: PYTEST_DISABLE_PLUGIN_AUTOLOAD
1001+
1002+
When set, disables plugin auto-loading through setuptools entrypoints. Only explicitly specified plugins will be
1003+
loaded.
1004+
9951005
.. envvar:: PYTEST_PLUGINS
9961006

9971007
Contains comma-separated list of modules that should be loaded as plugins:
@@ -1000,15 +1010,22 @@ Contains comma-separated list of modules that should be loaded as plugins:
10001010
10011011
export PYTEST_PLUGINS=mymodule.plugin,xdist
10021012
1003-
.. envvar:: PYTEST_DISABLE_PLUGIN_AUTOLOAD
1013+
.. envvar:: PY_COLORS
10041014

1005-
When set, disables plugin auto-loading through setuptools entrypoints. Only explicitly specified plugins will be
1006-
loaded.
1015+
When set to ``1``, pytest will use color in terminal output.
1016+
When set to ``0``, pytest will not use color.
1017+
``PY_COLORS`` takes precedence over ``NO_COLOR`` and ``FORCE_COLOR``.
10071018

1008-
.. envvar:: PYTEST_CURRENT_TEST
1019+
.. envvar:: NO_COLOR
10091020

1010-
This is not meant to be set by users, but is set by pytest internally with the name of the current test so other
1011-
processes can inspect it, see :ref:`pytest current test env` for more information.
1021+
When set (regardless of value), pytest will not use color in terminal output.
1022+
``PY_COLORS`` takes precedence over ``NO_COLOR``, which takes precedence over ``FORCE_COLOR``.
1023+
See `no-color.org <https://no-color.org/>`__ for other libraries supporting this community standard.
1024+
1025+
.. envvar:: FORCE_COLOR
1026+
1027+
When set (regardless of value), pytest will use color in terminal output.
1028+
``PY_COLORS`` and ``NO_COLOR`` take precedence over ``FORCE_COLOR``.
10121029

10131030
Exceptions
10141031
----------

src/_pytest/_io/terminalwriter.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ def should_do_markup(file: TextIO) -> bool:
2727
return True
2828
if os.environ.get("PY_COLORS") == "0":
2929
return False
30+
if "NO_COLOR" in os.environ:
31+
return False
32+
if "FORCE_COLOR" in os.environ:
33+
return True
3034
return (
31-
hasattr(file, "isatty")
32-
and file.isatty()
33-
and os.environ.get("TERM") != "dumb"
34-
and not (sys.platform.startswith("java") and os._name == "nt")
35+
hasattr(file, "isatty") and file.isatty() and os.environ.get("TERM") != "dumb"
3536
)
3637

3738

testing/io/test_terminalwriter.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ def test_attr_hasmarkup() -> None:
154154
assert "\x1b[0m" in s
155155

156156

157-
def test_should_do_markup_PY_COLORS_eq_1(monkeypatch: MonkeyPatch) -> None:
158-
monkeypatch.setitem(os.environ, "PY_COLORS", "1")
157+
def assert_color_set():
159158
file = io.StringIO()
160159
tw = terminalwriter.TerminalWriter(file)
161160
assert tw.hasmarkup
@@ -166,8 +165,7 @@ def test_should_do_markup_PY_COLORS_eq_1(monkeypatch: MonkeyPatch) -> None:
166165
assert "\x1b[0m" in s
167166

168167

169-
def test_should_do_markup_PY_COLORS_eq_0(monkeypatch: MonkeyPatch) -> None:
170-
monkeypatch.setitem(os.environ, "PY_COLORS", "0")
168+
def assert_color_not_set():
171169
f = io.StringIO()
172170
f.isatty = lambda: True # type: ignore
173171
tw = terminalwriter.TerminalWriter(file=f)
@@ -177,6 +175,34 @@ def test_should_do_markup_PY_COLORS_eq_0(monkeypatch: MonkeyPatch) -> None:
177175
assert s == "hello\n"
178176

179177

178+
def test_should_do_markup_PY_COLORS_eq_1(monkeypatch: MonkeyPatch) -> None:
179+
monkeypatch.setitem(os.environ, "PY_COLORS", "1")
180+
assert_color_set()
181+
182+
183+
def test_should_not_do_markup_PY_COLORS_eq_0(monkeypatch: MonkeyPatch) -> None:
184+
monkeypatch.setitem(os.environ, "PY_COLORS", "0")
185+
assert_color_not_set()
186+
187+
188+
def test_should_not_do_markup_NO_COLOR(monkeypatch: MonkeyPatch) -> None:
189+
monkeypatch.setitem(os.environ, "NO_COLOR", "1")
190+
assert_color_not_set()
191+
192+
193+
def test_should_do_markup_FORCE_COLOR(monkeypatch: MonkeyPatch) -> None:
194+
monkeypatch.setitem(os.environ, "FORCE_COLOR", "1")
195+
assert_color_set()
196+
197+
198+
def test_should_not_do_markup_NO_COLOR_and_FORCE_COLOR(
199+
monkeypatch: MonkeyPatch,
200+
) -> None:
201+
monkeypatch.setitem(os.environ, "NO_COLOR", "1")
202+
monkeypatch.setitem(os.environ, "FORCE_COLOR", "1")
203+
assert_color_not_set()
204+
205+
180206
class TestTerminalWriterLineWidth:
181207
def test_init(self) -> None:
182208
tw = terminalwriter.TerminalWriter()

0 commit comments

Comments
 (0)