Skip to content

Commit

Permalink
[OUTPUT] Allows entries color overriding from configuration
Browse files Browse the repository at this point in the history
> closes #109
  • Loading branch information
Samuel FORESTIER committed Feb 9, 2022
1 parent e0362c3 commit 3c4af91
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 38 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ Below stand further descriptions for each available (default) option :
// If set to `true`, any execution warning or error would be hidden.
// Configuration parsing warnings **would** still be shown.
"suppress_warnings": false,
// Use this option to specify a custom color for entries (logo won't be affected).
// Value should be a string suitable for inclusion in the ANSI/ECMA-48 escape code for setting graphical rendition
//
// For instance "5;31;47" would result in yellow text blinking on white background.
// See <https://wiki.bash-hackers.org/scripting/terminalcodes> for more information.
"entries_color": "",
// Set this option to `false` to force Archey to use its own colors palettes.
// `true` by default to honor os-release(5) `ANSI_COLOR` option.
"honor_ansi_color": true,
Expand Down
3 changes: 2 additions & 1 deletion archey/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class Colors(Enum):
ANSI terminal colors enumeration.
Supports an arbitrary number of display attributes.
See <http://www.termsys.demon.co.uk/vtansi.htm#colors>.
See <https://web.archive.org/web/20200627145120/http://www.termsys.demon.co.uk/vtansi.htm>
or <https://en.wikipedia.org/wiki/ANSI_escape_code>.
"""
CLEAR = (0,)
RED_NORMAL = (0, 31)
Expand Down
1 change: 1 addition & 0 deletions archey/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
'allow_overriding': True,
'parallel_loading': True,
'suppress_warnings': False,
'entries_color': '',
'honor_ansi_color': True,
'default_strings': {
'latest': 'latest',
Expand Down
11 changes: 9 additions & 2 deletions archey/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ def __init__(self, **kwargs):
else:
self._logo, self._colors = logo_module.LOGO.copy(), logo_module.COLORS.copy()

configuration = Configuration()

# If `os-release`'s `ANSI_COLOR` option is set, honor it.
ansi_color = Distributions.get_ansi_color()
if ansi_color and Configuration().get('honor_ansi_color'):
if ansi_color and configuration.get("honor_ansi_color"):
# Replace each Archey integrated colors by `ANSI_COLOR`.
self._colors = len(self._colors) * [Colors.escape_code_from_attrs(ansi_color)]

entries_color = configuration.get("entries_color")
self._entries_color = (
Colors.escape_code_from_attrs(entries_color) if entries_color else self._colors[0]
)

# Each entry will be added to this list
self._entries = []
# Each class output will be added in the list below afterwards
Expand All @@ -66,7 +73,7 @@ def add_entry(self, module: Type[Entry]):

def append(self, key: str, value):
"""Append a pre-formatted entry to the final output content"""
self._results.append(f'{self._colors[0]}{key}:{Colors.CLEAR} {value}')
self._results.append(f"{self._entries_color}{key}:{Colors.CLEAR} {value}")

def output(self):
"""
Expand Down
23 changes: 16 additions & 7 deletions archey/test/entries/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,28 @@ def patch_clean_configuration(
Decorator for an entry test definition, which sets the entry's `_default_strings` attribute
to the Archey defaults, optionally updated with `configuration`.
"""
# Let's initially give the entry configuration the defaults.
# Let's initially give defaults to configuration objects.
# We deep-copy `DEFAULT_CONFIG` to prevent its mutation.
entry_configuration = deepcopy(DEFAULT_CONFIG)
# Then, let's merge in `configuration` recursively.
Utility.update_recursive(entry_configuration, (configuration or {}))
default_config = deepcopy(DEFAULT_CONFIG)
# Then we recursively merge in passed `configuration`.
Utility.update_recursive(default_config, (configuration or {}))

def decorator_patch_clean_configuration(method: Callable) -> Callable:
@wraps(method)
def wrapper_patch_clean_configuration(*args, **kwargs):
with patch('archey.entry.Configuration', autospec=True) as config_instance_mock:
# `Configuration` singleton is used in `Entry` and `Output` unit-tested modules.
with patch(
"archey.entry.Configuration", autospec=True
) as entry_config_instance_mock, patch(
"archey.output.Configuration", autospec=True
) as output_config_instance_mock:
# Mock "publicly" used methods.
config_instance_mock().get = entry_configuration.get
config_instance_mock().__iter__ = iter(entry_configuration.items())
entry_config_instance_mock().get = default_config.get
entry_config_instance_mock().__iter__ = iter(default_config.items())

output_config_instance_mock().get = default_config.get
output_config_instance_mock().__iter__ = iter(default_config.items())

return method(*args, **kwargs)

return wrapper_patch_clean_configuration
Expand Down
65 changes: 37 additions & 28 deletions archey/test/test_archey_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from archey.colors import Colors
from archey.output import Output
from archey.distributions import Distributions
from archey.test.entries import HelperMethods


class TestOutput(unittest.TestCase):
Expand All @@ -33,13 +34,8 @@ def tearDown(self):
'archey.output.lazy_load_logo_module',
return_value=Mock(COLORS=['COLOR_0'])
)
@patch(
'archey.output.Configuration.get', # Disable `honor_ansi_color` option.
side_effect=(
lambda config_key: not (config_key == 'honor_ansi_color')
)
)
def test_append_regular(self, _, __, ___):
@HelperMethods.patch_clean_configuration(configuration={"honor_ansi_color": False})
def test_append_regular(self, _, __):
"""Test the `append` method, for new entries"""
output = Output()
output.append('KEY', 'VALUE')
Expand All @@ -57,15 +53,11 @@ def test_append_regular(self, _, __, ___):
'archey.output.Distributions.get_ansi_color',
return_value='ANSI_COLOR'
)
@patch(
'archey.output.Configuration.get', # Enable `honor_ansi_color` option.
side_effect=(
lambda config_key: config_key == 'honor_ansi_color'
)
)
def test_append_ansi_color(self, _, __, ___):
@HelperMethods.patch_clean_configuration
def test_append_ansi_color(self, _, __):
"""Check that `Output` honor `ANSI_COLOR` as required"""
output = Output()
output.append("key", "value")

# Slackware logo got three colors, so let's check they have been correctly replaced.
self.assertTrue(
Expand All @@ -75,6 +67,10 @@ def test_append_ansi_color(self, _, __, ___):
len(output._colors), # pylint: disable=protected-access
3 # Slackware's logo got 3 defined colors.
)
self.assertListEqual(
output._results, # pylint: disable=protected-access
[f"\x1b[ANSI_COLORmkey:{Colors.CLEAR} value"]
)

@patch(
'archey.output.Distributions.get_local',
Expand All @@ -84,15 +80,11 @@ def test_append_ansi_color(self, _, __, ___):
'archey.output.Distributions.get_ansi_color',
return_value='ANSI_COLOR'
)
@patch(
'archey.output.Configuration.get', # Disable `honor_ansi_color` option.
side_effect=(
lambda config_key: not (config_key == 'honor_ansi_color')
)
)
def test_append_no_ansi_color(self, _, __, ___):
@HelperMethods.patch_clean_configuration(configuration={"honor_ansi_color": False})
def test_append_no_ansi_color(self, _, __):
"""Check that `Output` DOES NOT honor `ANSI_COLOR` when specified"""
output = Output()
output.append("key", "value")

# Check that NO colors have been replaced (actually, that the list is the same as before).
self.assertFalse(
Expand All @@ -107,6 +99,29 @@ def test_append_no_ansi_color(self, _, __, ___):
Colors.YELLOW_NORMAL
]
)
self.assertListEqual(
output._results, # pylint: disable=protected-access
[f"{Colors.BLUE_BRIGHT}key:{Colors.CLEAR} value"]
)

@patch(
'archey.output.Distributions.get_local',
return_value=Distributions.DEBIAN # Make Debian being selected.
)
@patch(
'archey.output.Distributions.get_ansi_color',
return_value="ANSI_COLOR"
)
@HelperMethods.patch_clean_configuration(configuration={"entries_color": "5;31;47"})
def test_append_custom_entries_color(self, _, __):
"""Check that `Output` honor `ANSI_COLOR` as required"""
output = Output()
output.append("key", "value")

self.assertListEqual(
output._results, # pylint: disable=protected-access
[f"\x1b[5;31;47mkey:{Colors.CLEAR} value"]
)

@patch(
'archey.output.Distributions.get_local',
Expand Down Expand Up @@ -358,17 +373,11 @@ def test_preferred_distribution(self, _, get_local_mock):
'archey.output.Distributions.get_local',
return_value=Distributions.DEBIAN # Make Debian being selected.
)
@patch(
'archey.output.Configuration.get', # Disable `honor_ansi_color` option.
side_effect=(
lambda config_key: not (config_key == 'honor_ansi_color')
)
)
@patch(
'archey.output.print',
return_value=None # Let's nastily mute class' outputs.
)
def test_format_to_json(self, print_mock, _, __):
def test_format_to_json(self, print_mock, _):
"""Test how the `output` method handles JSON preferred formatting of entries"""
output = Output(format_to_json=True)
# We can't set the `name` attribute of a mock on its creation,
Expand Down
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"allow_overriding": true,
"parallel_loading": true,
"suppress_warnings": false,
"entries_color": "",
"honor_ansi_color": true,
"entries": [
{ "type": "User" },
Expand Down

0 comments on commit 3c4af91

Please sign in to comment.