Plugin.msg_curse()   F
last analyzed

Complexity

Conditions 18

Size

Total Lines 66
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 43
nop 3
dl 0
loc 66
rs 1.2
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
# Copyright (C) 2019 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""Quicklook plugin."""
21
22
from glances.cpu_percent import cpu_percent
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
23
from glances.logger import logger
0 ignored issues
show
introduced by Nicolas Hennion
import missing from __future__ import absolute_import
Loading history...
24
from glances.outputs.glances_bars import Bar
0 ignored issues
show
introduced by Nicolas Hennion
import missing from __future__ import absolute_import
Loading history...
25
from glances.outputs.glances_sparklines import Sparkline
0 ignored issues
show
introduced by Nicolas Hennion
import missing from __future__ import absolute_import
Loading history...
26
from glances.plugins.glances_plugin import GlancesPlugin
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
27
28
import psutil
0 ignored issues
show
introduced by Alessio Sergi
import missing from __future__ import absolute_import
Loading history...
introduced by Alessio Sergi
Unable to import 'psutil'
Loading history...
29
30
# Import plugin specific dependency
31
try:
32
    from cpuinfo import cpuinfo
0 ignored issues
show
introduced by Nicolas Hennion
import missing from __future__ import absolute_import
Loading history...
33
except ImportError as e:
0 ignored issues
show
Coding Style Naming introduced by Nicolas Hennion
The name e does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
34
    cpuinfo_tag = False
0 ignored issues
show
Coding Style Naming introduced by Nicolas Hennion
The name cpuinfo_tag does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
35
    logger.warning("Missing Python Lib ({}), Quicklook plugin will not display CPU info".format(e))
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (99/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
introduced by Nicolas Hennion
Use formatting in logging functions and pass the parameters as arguments
Loading history...
36
else:
37
    cpuinfo_tag = True
0 ignored issues
show
Coding Style Naming introduced by Nicolas Hennion
The name cpuinfo_tag does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
38
39
40
# Define the history items list
41
# All items in this list will be historised if the --enable-history tag is set
42
items_history_list = [{'name': 'cpu',
0 ignored issues
show
Coding Style Naming introduced by Nicolas Hennion
The name items_history_list does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
43
                       'description': 'CPU percent usage',
44
                       'y_unit': '%'},
45
                      {'name': 'percpu',
46
                       'description': 'PERCPU percent usage',
47
                       'y_unit': '%'},
48
                      {'name': 'mem',
49
                       'description': 'MEM percent usage',
50
                       'y_unit': '%'},
51
                      {'name': 'swap',
52
                       'description': 'SWAP percent usage',
53
                       'y_unit': '%'}]
54
55
56
class Plugin(GlancesPlugin):
57
    """Glances quicklook plugin.
58
59
    'stats' is a dictionary.
60
    """
61
62
    def __init__(self, args=None, config=None):
63
        """Init the quicklook plugin."""
64
        super(Plugin, self).__init__(args=args,
65
                                     config=config,
66
                                     items_history_list=items_history_list)
67
        # We want to display the stat in the curse interface
68
        self.display_curse = True
69
70
    @GlancesPlugin._check_decorator
71
    @GlancesPlugin._log_result_decorator
72
    def update(self):
73
        """Update quicklook stats using the input method."""
74
        # Init new stats
75
        stats = self.get_init_value()
76
77
        # Grab quicklook stats: CPU, MEM and SWAP
78
        if self.input_method == 'local':
79
            # Get the latest CPU percent value
80
            stats['cpu'] = cpu_percent.get()
81
            stats['percpu'] = cpu_percent.get(percpu=True)
82
            # Use the psutil lib for the memory (virtual and swap)
83
            stats['mem'] = psutil.virtual_memory().percent
84
            stats['swap'] = psutil.swap_memory().percent
85
        elif self.input_method == 'snmp':
86
            # Not available
87
            pass
88
89
        # Optionnaly, get the CPU name/frequency
90
        # thanks to the cpuinfo lib: https://github.com/workhorsy/py-cpuinfo
91
        if cpuinfo_tag:
92
            cpu_info = cpuinfo.get_cpu_info()
93
            #  Check cpu_info (issue #881)
94
            if cpu_info is not None:
95
                stats['cpu_name'] = cpu_info.get('brand', 'CPU')
96
                if 'hz_actual_raw' in cpu_info:
97
                    stats['cpu_hz_current'] = cpu_info['hz_actual_raw'][0]
98
                if 'hz_advertised_raw' in cpu_info:
99
                    stats['cpu_hz'] = cpu_info['hz_advertised_raw'][0]
100
101
        # Update the stats
102
        self.stats = stats
103
104
        return self.stats
105
106
    def update_views(self):
107
        """Update stats views."""
108
        # Call the father's method
109
        super(Plugin, self).update_views()
110
111
        # Add specifics informations
112
        # Alert only
113
        for key in ['cpu', 'mem', 'swap']:
114
            if key in self.stats:
115
                self.views[key]['decoration'] = self.get_alert(self.stats[key], header=key)
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (91/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
116
117
    def msg_curse(self, args=None, max_width=10):
118
        """Return the list to display in the UI."""
119
        # Init the return message
120
        ret = []
121
122
        # Only process if stats exist...
123
        if not self.stats or self.is_disable():
124
            return ret
125
126
        # Define the data: Bar (default behavor) or Sparkline
127
        sparkline_tag = False
128
        if self.args.sparkline and self.history_enable():
129
            data = Sparkline(max_width)
130
            sparkline_tag = data.available
131
        if not sparkline_tag:
132
            # Fallback to bar if Sparkline module is not installed
133
            data = Bar(max_width,
134
                       percentage_char=self.get_conf_value('percentage_char',
135
                                                           default=['|'])[0])
136
137
        # Build the string message
138
        if 'cpu_name' in self.stats and 'cpu_hz_current' in self.stats and 'cpu_hz' in self.stats:
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (98/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
139
            msg_name = '{} - '.format(self.stats['cpu_name'])
140
            msg_freq = '{:.2f}/{:.2f}GHz'.format(self._hz_to_ghz(self.stats['cpu_hz_current']),
0 ignored issues
show
Coding Style introduced by Alessio Sergi
This line is too long as per the coding-style (95/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
141
                                                 self._hz_to_ghz(self.stats['cpu_hz']))
0 ignored issues
show
Coding Style introduced by Alessio Sergi
This line is too long as per the coding-style (87/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
142
            if len(msg_name + msg_freq) - 6 <= max_width:
143
                ret.append(self.curse_add_line(msg_name))
144
            ret.append(self.curse_add_line(msg_freq))
145
            ret.append(self.curse_new_line())
146
        for key in ['cpu', 'mem', 'swap']:
147
            if key == 'cpu' and args.percpu:
148
                if sparkline_tag:
149
                    raw_cpu = self.get_raw_history(item='percpu', nb=data.size)
0 ignored issues
show
introduced by Nicolas Hennion
The variable data does not seem to be defined in case self.args.sparkline and self.history_enable() on line 128 is False. Are you sure this can never be the case?
Loading history...
150
                for cpu_index, cpu in enumerate(self.stats['percpu']):
151
                    if sparkline_tag:
152
                        # Sparkline display an history
153
                        data.percents = [i[1][cpu_index]['total'] for i in raw_cpu]
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (83/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
introduced by Nicolas Hennion
The variable raw_cpu does not seem to be defined for all execution paths.
Loading history...
154
                        # A simple padding in order to align metrics to the right
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (81/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
155
                        data.percents += [None] * (data.size - len(data.percents))
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (82/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
156
                    else:
157
                        # Bar only the last value
158
                        data.percent = cpu['total']
159
                    if cpu[cpu['key']] < 10:
160
                        msg = '{:3}{} '.format(key.upper(), cpu['cpu_number'])
161
                    else:
162
                        msg = '{:4} '.format(cpu['cpu_number'])
163
                    ret.extend(self._msg_create_line(msg, data, key))
164
                    ret.append(self.curse_new_line())
165
            else:
166
                if sparkline_tag:
167
                    # Sparkline display an history
168
                    data.percents = [i[1] for i in self.get_raw_history(item=key, nb=data.size)]
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (96/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
169
                    # A simple padding in order to align metrics to the right
170
                    data.percents += [None] * (data.size - len(data.percents))
171
                else:
172
                    # Bar only the last value
173
                    data.percent = self.stats[key]
174
                msg = '{:4} '.format(key.upper())
175
                ret.extend(self._msg_create_line(msg, data, key))
176
                ret.append(self.curse_new_line())
177
178
        # Remove the last new line
179
        ret.pop()
180
181
        # Return the message with decoration
182
        return ret
183
184
    def _msg_create_line(self, msg, data, key):
185
        """Create a new line to the Quickview."""
186
        ret = []
187
188
        ret.append(self.curse_add_line(msg))
189
        ret.append(self.curse_add_line(data.pre_char, decoration='BOLD'))
190
        ret.append(self.curse_add_line(data.get(), self.get_views(key=key, option='decoration')))
0 ignored issues
show
Coding Style introduced by Nicolas Hennion
This line is too long as per the coding-style (97/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
191
        ret.append(self.curse_add_line(data.post_char, decoration='BOLD'))
192
        ret.append(self.curse_add_line('  '))
193
194
        return ret
195
196
    def _hz_to_ghz(self, hz):
0 ignored issues
show
Coding Style Naming introduced by Nicolas Hennion
The name hz does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by Nicolas Hennion
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
197
        """Convert Hz to Ghz."""
198
        return hz / 1000000000.0
199