diff --git a/conans/client/output.py b/conans/client/output.py index b36fb06d153..882754ef7c5 100644 --- a/conans/client/output.py +++ b/conans/client/output.py @@ -8,12 +8,29 @@ def colorama_initialize(): + if "NO_COLOR" in os.environ: + return False + + clicolor_force = get_env("CLICOLOR_FORCE") + if clicolor_force is not None and clicolor_force != "0": + import colorama + colorama.init(convert=False, strip=False) + return True + + isatty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty() + + clicolor = get_env("CLICOLOR") + if clicolor is not None: + if clicolor == "0" or not isatty: + return False + import colorama + colorama.init() + return True + # Respect color env setting or check tty if unset color_set = "CONAN_COLOR_DISPLAY" in os.environ if ((color_set and get_env("CONAN_COLOR_DISPLAY", 1)) - or (not color_set - and hasattr(sys.stdout, "isatty") - and sys.stdout.isatty())): + or (not color_set and isatty)): import colorama if get_env("PYCHARM_HOSTED"): # in PyCharm disable convert/strip colorama.init(convert=False, strip=False) diff --git a/conans/test/unittests/client/conan_output_test.py b/conans/test/unittests/client/conan_output_test.py index 77838157ce0..26dc205817b 100644 --- a/conans/test/unittests/client/conan_output_test.py +++ b/conans/test/unittests/client/conan_output_test.py @@ -3,9 +3,10 @@ import unittest from types import MethodType +from parameterized import parameterized from six import StringIO -from conans.client.output import ConanOutput +from conans.client.output import ConanOutput, colorama_initialize from mock import mock @@ -28,3 +29,47 @@ def write_raise(self, data): out.write("Hello world") sleep.assert_any_call(0.02) self.assertEqual("Hello world", stream.getvalue()) + + @parameterized.expand([(False, {}), + (False, {"CONAN_COLOR_DISPLAY": "0"}), + (True, {"CONAN_COLOR_DISPLAY": "0"}), + (False, {"PYCHARM_HOSTED": "1"}), + (True, {"PYCHARM_HOSTED": "1", "CONAN_COLOR_DISPLAY": "0"}), + (True, {"NO_COLOR": ""}), + (True, {"CLICOLOR": "0"}), + (True, {"CLICOLOR": "0", "CONAN_COLOR_DISPLAY": "1"}), + (False, {"CLICOLOR": "1"}), + (False, {"CLICOLOR_FORCE": "0"}), + (True, + {"CLICOLOR": "1", "CLICOLOR_FORCE": "1", "CONAN_COLOR_DISPLAY": "1", + "PYCHARM_HOSTED": "1", "NO_COLOR": "1"})]) + def test_output_no_color(self, isatty, env): + with mock.patch("colorama.init") as init: + with mock.patch("sys.stdout.isatty", return_value=isatty), \ + mock.patch.dict("os.environ", env, clear=True): + assert not colorama_initialize() + init.assert_not_called() + + @parameterized.expand([(True, {}), + (False, {"CONAN_COLOR_DISPLAY": "1"}), + (True, {"CONAN_COLOR_DISPLAY": "1"}), + (True, {"CLICOLOR": "1"}), + (True, {"CLICOLOR_FORCE": "0"})]) + def test_output_color(self, isatty, env): + with mock.patch("colorama.init") as init: + with mock.patch("sys.stdout.isatty", return_value=isatty), \ + mock.patch.dict("os.environ", env, clear=True): + assert colorama_initialize() + init.assert_called_once_with() + + @parameterized.expand([(False, {"PYCHARM_HOSTED": "1", "CONAN_COLOR_DISPLAY": "1"}), + (True, {"PYCHARM_HOSTED": "1"}), + (False, {"CLICOLOR_FORCE": "1"}), + (True, {"CLICOLOR_FORCE": "1", "CLICOLOR": "0"}), + (True, {"CLICOLOR_FORCE": "1", "CONAN_COLOR_DISPLAY": "0"})]) + def test_output_color_prevent_strip(self, isatty, env): + with mock.patch("colorama.init") as init: + with mock.patch("sys.stdout.isatty", return_value=isatty), \ + mock.patch.dict("os.environ", env, clear=True): + assert colorama_initialize() + init.assert_called_once_with(convert=False, strip=False)