Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions Lib/_colorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ def get_colors(colorize: bool = False) -> ANSIColors:


def can_colorize() -> bool:
if sys.platform == "win32":
try:
import nt

if not nt._supports_virtual_terminal():
return False
except (ImportError, AttributeError):
return False
if not sys.flags.ignore_environment:
if os.environ.get("PYTHON_COLORS") == "0":
return False
Expand All @@ -58,6 +50,15 @@ def can_colorize() -> bool:
if not hasattr(sys.stderr, "fileno"):
return False

if sys.platform == "win32":
try:
import nt

if not nt._supports_virtual_terminal():
return False
except (ImportError, AttributeError):
return False

try:
return os.isatty(sys.stderr.fileno())
except io.UnsupportedOperation:
Expand Down
96 changes: 75 additions & 21 deletions Lib/test/test__colorize.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import contextlib
import sys
import unittest
import unittest.mock
Expand All @@ -18,38 +17,93 @@ def tearDownModule():

class TestColorizeFunction(unittest.TestCase):
@force_not_colorized
@unittest.skipUnless(sys.platform != "win32", "non-Windows only")
def test_colorized_detection_checks_for_environment_variables(self):
if sys.platform == "win32":
virtual_patching = unittest.mock.patch("nt._supports_virtual_terminal",
return_value=True)
else:
virtual_patching = contextlib.nullcontext()
with virtual_patching:

flags = unittest.mock.MagicMock(ignore_environment=False)
with (unittest.mock.patch("os.isatty") as isatty_mock,
unittest.mock.patch("sys.flags", unittest.mock.MagicMock(ignore_environment=False)),
unittest.mock.patch("_colorize.can_colorize", ORIGINAL_CAN_COLORIZE)):
isatty_mock.return_value = True
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"TERM": "dumb"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"NO_COLOR": "1", "PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)

isatty_mock.return_value = False
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), False)

@force_not_colorized
@unittest.skipUnless(sys.platform == "win32", "Windows only")
def test_colorized_detection_checks_for_environment_variables_on_windows(self):
with unittest.mock.patch("nt._supports_virtual_terminal") as supports_vt_mock:
# If virtual terminal sequences are supported
supports_vt_mock.return_value = True
with (unittest.mock.patch("os.isatty") as isatty_mock,
unittest.mock.patch("sys.flags", unittest.mock.MagicMock(ignore_environment=False)),
unittest.mock.patch("_colorize.can_colorize", ORIGINAL_CAN_COLORIZE)):
isatty_mock.return_value = True
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"TERM": "dumb"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"NO_COLOR": "1", "PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)

isatty_mock.return_value = False
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), False)

# If virtual terminal sequences are not supported
supports_vt_mock.return_value = False
with (unittest.mock.patch("os.isatty") as isatty_mock,
unittest.mock.patch("sys.flags", flags),
unittest.mock.patch("sys.flags", unittest.mock.MagicMock(ignore_environment=False)),
unittest.mock.patch("_colorize.can_colorize", ORIGINAL_CAN_COLORIZE)):
isatty_mock.return_value = True
with unittest.mock.patch("os.environ", {'TERM': 'dumb'}):
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {"TERM": "dumb"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}):
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}):
with unittest.mock.patch("os.environ", {"PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}):
with unittest.mock.patch("os.environ", {"NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ",
{'NO_COLOR': '1', "PYTHON_COLORS": '1'}):
with unittest.mock.patch("os.environ", {"NO_COLOR": "1", "PYTHON_COLORS": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}):
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ",
{'FORCE_COLOR': '1', 'NO_COLOR': '1'}):
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "NO_COLOR": "1"}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ",
{'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}):
with unittest.mock.patch("os.environ", {"FORCE_COLOR": "1", "PYTHON_COLORS": "0"}):
self.assertEqual(_colorize.can_colorize(), False)

isatty_mock.return_value = False
with unittest.mock.patch("os.environ", {}):
self.assertEqual(_colorize.can_colorize(), False)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow to force color output on Windows using environment variables. Patch by
Andrey Efremov.
Loading