From 1f03b03aa1412c0ba59dc6a8779c490b451e4ea8 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Thu, 18 May 2023 19:41:40 +0200 Subject: Some errors... --- glances/outputs/glances_rich.py | 2 +- glances/plugins/plugin/model.py | 136 +++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 50 deletions(-) diff --git a/glances/outputs/glances_rich.py b/glances/outputs/glances_rich.py index f6dcbeb1..a4b5311e 100644 --- a/glances/outputs/glances_rich.py +++ b/glances/outputs/glances_rich.py @@ -26,7 +26,7 @@ import sys from glances.logger import logger from glances.keyboard import KBHit from glances.timer import Timer -from glances.compat import nativestr, u +from glances.globals import nativestr, u from glances.processes import glances_processes, sort_processes_key_list # Import curses library for "normal" operating system diff --git a/glances/plugins/plugin/model.py b/glances/plugins/plugin/model.py index d5869f0e..d7edadac 100644 --- a/glances/plugins/plugin/model.py +++ b/glances/plugins/plugin/model.py @@ -14,11 +14,12 @@ I am your father... """ import re +import json import copy import numbers from operator import itemgetter -from glances.globals import iterkeys, itervalues, listkeys, mean, nativestr, json_dumps, json_dumps_dictlist +from glances.globals import iterkeys, itervalues, listkeys, mean, nativestr from glances.actions import GlancesActions from glances.history import GlancesHistory from glances.logger import logger @@ -169,6 +170,16 @@ class GlancesPluginModel(object): """Return true if plugin is disabled.""" return not self.is_enabled(plugin_name=plugin_name) + def _json_dumps(self, d): + """Return the object 'd' in a JSON format. + + Manage the issue #815 for Windows OS + """ + try: + return json.dumps(d) + except UnicodeDecodeError: + return json.dumps(d, ensure_ascii=False) + def history_enable(self): return self.args is not None and not self.args.disable_history and self.get_items_history_list() is not None @@ -188,13 +199,13 @@ class GlancesPluginModel(object): def update_stats_history(self): """Update stats history.""" + # If the plugin data is a dict, the dict's key should be used + if self.get_key() is None: + item_name = '' + else: + item_name = self.get_key() # Build the history if self.get_export() and self.history_enable(): - # If the plugin data is a dict, the dict's key should be used - if self.get_key() is None: - item_name = '' - else: - item_name = self.get_key() for i in self.get_items_history_list(): if isinstance(self.get_export(), list): # Stats is a list of data @@ -262,9 +273,24 @@ class GlancesPluginModel(object): s = self.get_json_history(nb=nb) if item is None: - return json_dumps(s) + return self._json_dumps(s) - return json_dumps_dictlist(s, item) + if isinstance(s, dict): + try: + return self._json_dumps({item: s[item]}) + except KeyError as e: + logger.error("Cannot get item history {} ({})".format(item, e)) + return None + elif isinstance(s, list): + try: + # Source: + # http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list + return self._json_dumps({item: map(itemgetter(item), s)}) + except (KeyError, ValueError) as e: + logger.error("Cannot get item history {} ({})".format(item, e)) + return None + else: + return None def get_trend(self, item, nb=6): """Get the trend regarding to the last nb values. @@ -397,7 +423,7 @@ class GlancesPluginModel(object): def get_stats(self): """Return the stats object in JSON format.""" - return json_dumps(self.stats) + return self._json_dumps(self.stats) def get_json(self): """Return the stats object in JSON format.""" @@ -408,7 +434,23 @@ class GlancesPluginModel(object): Stats should be a list of dict (processlist, network...) """ - return json_dumps_dictlist(self.stats, item) + if isinstance(self.stats, dict): + try: + return self._json_dumps({item: self.stats[item]}) + except KeyError as e: + logger.error("Cannot get item {} ({})".format(item, e)) + return None + elif isinstance(self.stats, list): + try: + # Source: + # http://stackoverflow.com/questions/4573875/python-get-index-of-dictionary-item-in-list + # But https://github.com/nicolargo/glances/issues/1401 + return self._json_dumps({item: list(map(itemgetter(item), self.stats))}) + except (KeyError, ValueError) as e: + logger.error("Cannot get item {} ({})".format(item, e)) + return None + else: + return None def get_stats_value(self, item, value): """Return the stats object for a specific item=value in JSON format. @@ -421,7 +463,7 @@ class GlancesPluginModel(object): if not isinstance(value, int) and value.isdigit(): value = int(value) try: - return json_dumps({value: [i for i in self.stats if i[item] == value]}) + return self._json_dumps({value: [i for i in self.stats if i[item] == value]}) except (KeyError, ValueError) as e: logger.error("Cannot get item({})=value({}) ({})".format(item, value, e)) return None @@ -548,7 +590,7 @@ class GlancesPluginModel(object): def get_json_views(self, item=None, key=None, option=None): """Return the views (in JSON).""" - return json_dumps(self.get_views(item, key, option)) + return self._json_dumps(self.get_views(item, key, option)) def load_limits(self, config): """Load limits from the configuration file, if it exists.""" @@ -839,10 +881,11 @@ class GlancesPluginModel(object): Example for diskio: show=sda.* """ - # @TODO: possible optimisation: create a re.compile list - return any( - j for j in [re.fullmatch(i.lower(), value.lower()) for i in self.get_conf_value('show', header=header)] - ) + # TODO: possible optimisation: create a re.compile list + if self.get_conf_value('show', header=header) == []: + return True + else: + return any(j for j in [re.match(i, value) for i in self.get_conf_value('show', header=header)]) def is_hide(self, value, header=""): """Return True if the value is in the hide configuration list. @@ -852,17 +895,8 @@ class GlancesPluginModel(object): Example for diskio: hide=sda2,sda5,loop.* """ - # @TODO: possible optimisation: create a re.compile list - return any( - j for j in [re.fullmatch(i.lower(), value.lower()) for i in self.get_conf_value('hide', header=header)] - ) - - def is_display(self, value, header=""): - """Return True if the value should be displayed in the UI""" - if self.get_conf_value('show', header=header) != []: - return self.is_show(value, header=header) - else: - return not self.is_hide(value, header=header) + # TODO: possible optimisation: create a re.compile list + return any(j for j in [re.match(i, value) for i in self.get_conf_value('hide', header=header)]) def has_alias(self, header): """Return the alias name for the relative header it it exists otherwise None.""" @@ -1045,7 +1079,7 @@ class GlancesPluginModel(object): """Go to a new line.""" return self.curse_add_line('\n') - def curse_add_stat(self, key, width=None, header='', display_key=True, separator='', trailer=''): + def curse_add_stat(self, key, width=None, header='', separator='', trailer=''): """Return a list of dict messages with the 'key: value' result <=== width ===> @@ -1053,8 +1087,8 @@ class GlancesPluginModel(object): | | | | |_ trailer | | | |_ self.stats[key] | | |_ separator - | |_ 'short_name' description or key or nothing if display_key is True - |_ header + | |_ key + |_ trailer Instead of: msg = ' {:8}'.format('idle:') @@ -1070,9 +1104,7 @@ class GlancesPluginModel(object): return [] # Check if a shortname is defined - if not display_key: - key_name = '' - elif key in self.fields_description and 'short_name' in self.fields_description[key]: + if key in self.fields_description and 'short_name' in self.fields_description[key]: key_name = self.fields_description[key]['short_name'] else: key_name = key @@ -1111,28 +1143,33 @@ class GlancesPluginModel(object): if width is None: msg_item = header + '{}'.format(key_name) + separator - msg_template_float = '{:.1f}{}' - msg_template = '{}{}' + if unit_type == 'float': + msg_value = '{:.1f}{}'.format(value, unit_short) + trailer + elif 'min_symbol' in self.fields_description[key]: + msg_value = ( + '{}{}'.format( + self.auto_unit(int(value), min_symbol=self.fields_description[key]['min_symbol']), unit_short + ) + + trailer + ) + else: + msg_value = '{}{}'.format(int(value), unit_short) + trailer else: # Define the size of the message # item will be on the left # value will be on the right msg_item = header + '{:{width}}'.format(key_name, width=width - 7) + separator - msg_template_float = '{:5.1f}{}' - msg_template = '{:>5}{}' - - if unit_type == 'float': - msg_value = msg_template_float.format(value, unit_short) + trailer - elif 'min_symbol' in self.fields_description[key]: - msg_value = ( - msg_template.format( - self.auto_unit(int(value), min_symbol=self.fields_description[key]['min_symbol']), unit_short + if unit_type == 'float': + msg_value = '{:5.1f}{}'.format(value, unit_short) + trailer + elif 'min_symbol' in self.fields_description[key]: + msg_value = ( + '{:>5}{}'.format( + self.auto_unit(int(value), min_symbol=self.fields_description[key]['min_symbol']), unit_short + ) + + trailer ) - + trailer - ) - else: - msg_value = msg_template.format(int(value), unit_short) + trailer - + else: + msg_value = '{:>5}{}'.format(int(value), unit_short) + trailer decoration = self.get_views(key=key, option='decoration') optional = self.get_views(key=key, option='optional') @@ -1268,3 +1305,4 @@ class GlancesPluginModel(object): # Mandatory to call the decorator in child classes _check_decorator = staticmethod(_check_decorator) _log_result_decorator = staticmethod(_log_result_decorator) + -- cgit v1.2.3