archey4/archey/configuration.py
Samuel FORESTIER 930f4cfdfb
[GPU] Adds support for multiple GPUs (and fixes their display order) (#71)
> Closes #61 (multi-GPU support)

 * Fixes GPU display order (new order: 3D -> VGA -> Display) 

 * Adds support for multiple GPUs displayed at once.

 * Adds option for multi-line GPU output with new configuration option.

 * Modifies `Output` to havean `append` method prototype similar to `list.append`.

 * Automatically sets entries' outputs as 'Not detected' when their `value` is falsy.

Co-authored-by: Michael Bromilow <12384431+ingrinder@users.noreply.github.com>
2020-05-17 02:54:55 +00:00

127 lines
4.2 KiB
Python

"""Archey configuration module"""
import os
import sys
import json
from archey.singleton import Singleton
class Configuration(metaclass=Singleton):
"""
The default needed configuration which will be used by Archey is present below.
Values present in the `self.config` dictionary below are needed.
New optional values may be added with `_update_recursive()` method.
"""
def __init__(self):
self._config = {
'colors_palette': {
'use_unicode': False,
'honor_ansi_color': True
},
'default_strings': {
'no_address': 'No Address',
'not_detected': 'Not detected',
'virtual_environment': 'Virtual Environment'
},
'gpu': {
'one_line': True,
'max_count': 2
},
'ip_settings': {
'lan_ip_max_count': 2,
'lan_ip_v6_support': True,
'wan_ip_v6_support': True
},
'limits': {
'ram': {
'warning': 33.3,
'danger': 66.7
},
'disk': {
'warning': 50,
'danger': 75
}
},
'temperature': {
'char_before_unit': ' ',
'sensors_chipsets': [],
'use_fahrenheit': False
},
'timeout': {
'ipv4_detection': 1,
'ipv6_detection': 1
}
}
# Let's "save" `STDERR` file descriptor for `suppress_warnings` option
self._stderr = sys.stderr
# Now, let's load each optional configuration file in a "regular" order
self.load_configuration('/etc/archey4/')
self.load_configuration(os.path.expanduser('~/.config/archey4/'))
self.load_configuration(os.path.dirname(os.path.realpath(__file__)))
def get(self, key, default=None):
"""
A binding method to imitate the `dict.get()` behavior.
"""
return self._config.get(key, default)
def load_configuration(self, path):
"""
A method handling configuration loading from a JSON file.
It will try to load any `config.json` present under `path`.
"""
# If a previous configuration file has denied overriding...
if not self._config.get('allow_overriding', True):
# ... don't load this one.
return
path = os.path.join(path, 'config.json')
try:
with open(path) as file:
self._update_recursive(self._config, json.load(file))
# If the user does not want any warning to appear : 2> /dev/null
if self._config.get('suppress_warnings', False):
# One more if statement to avoid multiple `open` calls.
if sys.stderr == self._stderr:
sys.stderr = open(os.devnull, 'w')
else:
# One more if statement to avoid useless assignments and...
# ... for closing previously opened new file descriptor.
if sys.stderr != self._stderr:
sys.stderr.close()
sys.stderr = self._stderr
except FileNotFoundError:
pass
# For backward compatibility with Python versions prior to 3.5.0
# we use `ValueError` instead of `json.JSONDecodeError`.
except ValueError as error:
print('Warning: {0} ({1})'.format(error, path), file=sys.stderr)
def _update_recursive(self, old_dict, new_dict):
"""
A method for recursively merging dictionaries as...
... `dict.update()` is not able to do this.
Original snippet taken from here :
https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
"""
for key, value in new_dict.items():
if key in old_dict and isinstance(old_dict[key], dict) \
and isinstance(value, dict):
self._update_recursive(old_dict[key], value)
else:
old_dict[key] = value
def __del__(self):
if sys.stderr != self._stderr:
sys.stderr.close()
sys.stderr = self._stderr