Plugin.msg_curse()   F
last analyzed

Complexity

Conditions 21

Size

Total Lines 68
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 43
nop 3
dl 0
loc 68
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like glances.plugins.glances_quicklook.Plugin.msg_curse() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
6
#
7
# SPDX-License-Identifier: LGPL-3.0-only
8
#
9
10
"""Quicklook plugin."""
11
12
from glances.cpu_percent import cpu_percent
13
from glances.outputs.glances_bars import Bar
14
from glances.outputs.glances_sparklines import Sparkline
15
from glances.plugins.glances_plugin import GlancesPlugin
16
17
import psutil
18
19
20
# Define the history items list
21
# All items in this list will be historised if the --enable-history tag is set
22
items_history_list = [
23
    {'name': 'cpu', 'description': 'CPU percent usage', 'y_unit': '%'},
24
    {'name': 'percpu', 'description': 'PERCPU percent usage', 'y_unit': '%'},
25
    {'name': 'mem', 'description': 'MEM percent usage', 'y_unit': '%'},
26
    {'name': 'swap', 'description': 'SWAP percent usage', 'y_unit': '%'},
27
]
28
29
30
class Plugin(GlancesPlugin):
31
    """Glances quicklook plugin.
32
33
    'stats' is a dictionary.
34
    """
35
36
    def __init__(self, args=None, config=None):
37
        """Init the quicklook plugin."""
38
        super(Plugin, self).__init__(args=args, config=config, items_history_list=items_history_list)
39
        # We want to display the stat in the curse interface
40
        self.display_curse = True
41
42
    @GlancesPlugin._check_decorator
43
    @GlancesPlugin._log_result_decorator
44
    def update(self):
45
        """Update quicklook stats using the input method."""
46
        # Init new stats
47
        stats = self.get_init_value()
48
49
        # Grab quicklook stats: CPU, MEM and SWAP
50
        if self.input_method == 'local':
51
            # Get the latest CPU percent value
52
            stats['cpu'] = cpu_percent.get()
53
            stats['percpu'] = cpu_percent.get(percpu=True)
54
55
            # Use the psutil lib for the memory (virtual and swap)
56
            stats['mem'] = psutil.virtual_memory().percent
57
            try:
58
                stats['swap'] = psutil.swap_memory().percent
59
            except RuntimeError:
60
                # Correct issue in Illumos OS (see #1767)
61
                stats['swap'] = None
62
63
            # Get additional information
64
            cpu_info = cpu_percent.get_info()
65
            stats['cpu_name'] = cpu_info['cpu_name']
66
            stats['cpu_hz_current'] = (
67
                self._mhz_to_hz(cpu_info['cpu_hz_current']) if cpu_info['cpu_hz_current'] is not None else None
68
            )
69
            stats['cpu_hz'] = self._mhz_to_hz(cpu_info['cpu_hz']) if cpu_info['cpu_hz'] is not None else None
70
71
        elif self.input_method == 'snmp':
72
            # Not available
73
            pass
74
75
        # Update the stats
76
        self.stats = stats
77
78
        return self.stats
79
80
    def update_views(self):
81
        """Update stats views."""
82
        # Call the father's method
83
        super(Plugin, self).update_views()
84
85
        # Add specifics information
86
        # Alert only
87
        for key in ['cpu', 'mem', 'swap']:
88
            if key in self.stats:
89
                self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
90
91
    def msg_curse(self, args=None, max_width=10):
92
        """Return the list to display in the UI."""
93
        # Init the return message
94
        ret = []
95
96
        # Only process if stats exist...
97
        if not self.stats or self.is_disabled():
98
            return ret
99
100
        # Define the data: Bar (default behavior) or Sparkline
101
        sparkline_tag = False
102
        if self.args.sparkline and self.history_enable() and not self.args.client:
103
            data = Sparkline(max_width)
104
            sparkline_tag = data.available
105
        if not sparkline_tag:
106
            # Fallback to bar if Sparkline module is not installed
107
            data = Bar(max_width, percentage_char=self.get_conf_value('percentage_char', default=['|'])[0])
108
109
        # Build the string message
110
        if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats:
111
            msg_name = self.stats['cpu_name']
112
            if self.stats['cpu_hz_current'] and self.stats['cpu_hz']:
113
                msg_freq = ' - {:.2f}/{:.2f}GHz'.format(
114
                    self._hz_to_ghz(self.stats['cpu_hz_current']), self._hz_to_ghz(self.stats['cpu_hz'])
115
                )
116
            else:
117
                msg_freq = ''
118
            if len(msg_name + msg_freq) - 6 <= max_width:
119
                ret.append(self.curse_add_line(msg_name))
120
            ret.append(self.curse_add_line(msg_freq))
121
            ret.append(self.curse_new_line())
122
        for key in ['cpu', 'mem', 'swap']:
123
            if key == 'cpu' and args.percpu:
124
                if sparkline_tag:
125
                    raw_cpu = self.get_raw_history(item='percpu', nb=data.size)
0 ignored issues
show
introduced by
The variable data does not seem to be defined in case self.args.sparkline and ...le() and BooleanNotNode on line 102 is False. Are you sure this can never be the case?
Loading history...
126
                for cpu_index, cpu in enumerate(self.stats['percpu']):
127
                    if sparkline_tag:
128
                        # Sparkline display an history
129
                        data.percents = [i[1][cpu_index]['total'] for i in raw_cpu]
0 ignored issues
show
introduced by
The variable raw_cpu does not seem to be defined for all execution paths.
Loading history...
130
                        # A simple padding in order to align metrics to the right
131
                        data.percents += [None] * (data.size - len(data.percents))
132
                    else:
133
                        # Bar only the last value
134
                        data.percent = cpu['total']
135
                    if cpu[cpu['key']] < 10:
136
                        msg = '{:3}{} '.format(key.upper(), cpu['cpu_number'])
137
                    else:
138
                        msg = '{:4} '.format(cpu['cpu_number'])
139
                    ret.extend(self._msg_create_line(msg, data, key))
140
                    ret.append(self.curse_new_line())
141
            else:
142
                if sparkline_tag:
143
                    # Sparkline display an history
144
                    data.percents = [i[1] for i in self.get_raw_history(item=key, nb=data.size)]
145
                    # A simple padding in order to align metrics to the right
146
                    data.percents += [None] * (data.size - len(data.percents))
147
                else:
148
                    # Bar only the last value
149
                    data.percent = self.stats[key]
150
                msg = '{:4} '.format(key.upper())
151
                ret.extend(self._msg_create_line(msg, data, key))
152
                ret.append(self.curse_new_line())
153
154
        # Remove the last new line
155
        ret.pop()
156
157
        # Return the message with decoration
158
        return ret
159
160
    def _msg_create_line(self, msg, data, key):
161
        """Create a new line to the Quick view."""
162
        return [
163
            self.curse_add_line(msg),
164
            self.curse_add_line(data.pre_char, decoration='BOLD'),
165
            self.curse_add_line(data.get(), self.get_views(key=key, option='decoration')),
166
            self.curse_add_line(data.post_char, decoration='BOLD'),
167
            self.curse_add_line('  '),
168
        ]
169
170
    def _hz_to_ghz(self, hz):
171
        """Convert Hz to Ghz."""
172
        return hz / 1000000000.0
173
174
    def _mhz_to_hz(self, hz):
175
        """Convert Mhz to Hz."""
176
        return hz * 1000000.0
177