diff --git a/uaclient/cli/formatter.py b/uaclient/cli/formatter.py new file mode 100644 index 0000000000..25dd63bb74 --- /dev/null +++ b/uaclient/cli/formatter.py @@ -0,0 +1,38 @@ +import os +import sys + +from uaclient.config import UAConfig + + +# Class attributes and methods so we don't need singletons or globals for this +class ProOutputFormatterConfig: + use_utf8 = True + use_color = True + show_suggestions = True + + # Initializing the class after the import is useful for unit testing + @classmethod + def init(cls, cfg: UAConfig): + cls.use_utf8 = ( + sys.stdout.encoding is not None + and "UTF-8" in sys.stdout.encoding.upper() + ) + + cls.use_color = ( + sys.stdout.isatty() + and os.getenv("NO_COLOR") is None + and cfg.cli_color + ) + + cls.show_suggestions = cfg.cli_suggestions + + @classmethod + def disable_color(cls) -> None: + cls.use_color = False + + @classmethod + def disable_suggestions(cls) -> None: + cls.show_suggestions = False + + +ProOutputFormatterConfig.init(cfg=UAConfig()) diff --git a/uaclient/cli/tests/test_cli_formatter.py b/uaclient/cli/tests/test_cli_formatter.py new file mode 100644 index 0000000000..93c0b10a53 --- /dev/null +++ b/uaclient/cli/tests/test_cli_formatter.py @@ -0,0 +1,65 @@ +import mock +import pytest + +from uaclient.cli.formatter import ProOutputFormatterConfig as POFC + +M_PATH = "uaclient.cli.formatter." + + +class TestProFormatterConfig: + @pytest.mark.parametrize( + "system_encoding,expected_use_utf8", + ((None, False), ("iso-8859-13", False), ("utf-8", True)), + ) + def test_use_utf8(self, system_encoding, expected_use_utf8, FakeConfig): + cfg = FakeConfig() + + with mock.patch(M_PATH + "sys.stdout") as m_stdout: + m_stdout.encoding = system_encoding + POFC.init(cfg) + + assert POFC.use_utf8 is expected_use_utf8 + + @pytest.mark.parametrize("config_value", (True, False)) + @pytest.mark.parametrize("is_tty", (True, False)) + @pytest.mark.parametrize("env_no_color", ("True", None)) + @mock.patch(M_PATH + "sys.stdout.isatty") + @mock.patch(M_PATH + "os.getenv") + def test_color_config( + self, + m_getenv, + m_is_tty, + config_value, + is_tty, + env_no_color, + FakeConfig, + ): + cfg = FakeConfig() + cfg.user_config.cli_color = config_value + + m_is_tty.return_value = is_tty + + m_getenv.return_value = env_no_color + + POFC.init(cfg) + + expected_result = True + if any((config_value is False, not is_tty, env_no_color)): + expected_result = False + + assert POFC.use_color is expected_result + + POFC.disable_color() + assert POFC.use_color is False + + @pytest.mark.parametrize("config_value", (True, False)) + def test_suggestions_config(self, config_value, FakeConfig): + cfg = FakeConfig() + cfg.user_config.cli_suggestions = config_value + + POFC.init(cfg) + + assert POFC.show_suggestions is config_value + + POFC.disable_suggestions() + assert POFC.show_suggestions is False