Test Failed
Push — develop ( 29e3c5...0d1a1d )
by Nicolas
03:07
created

glances.outputs.glances_curses   F

Complexity

Total Complexity 182

Size/Duplication

Total Lines 1069
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 182
eloc 619
dl 0
loc 1069
rs 1.981
c 0
b 0
f 0

36 Methods

Rating   Name   Duplication   Size   Complexity  
A _GlancesCurses.new_column() 0 3 1
A _GlancesCurses.enable_fullquicklook() 0 5 2
A _GlancesCurses.disable_top() 0 4 2
B _GlancesCurses.update() 0 48 6
A _GlancesCurses.__init__() 0 48 2
A _GlancesCurses.end() 0 12 5
A _GlancesCurses.flush() 0 11 1
A _GlancesCurses.__get_stat_display() 0 34 5
A _GlancesCurses.get_stats_display_width() 0 16 5
F _GlancesCurses.display() 0 113 16
A _GlancesCurses.erase() 0 3 1
A _GlancesCurses.new_line() 0 3 1
C _GlancesCurses.display_popup() 0 77 11
A _GlancesCurses.init_column() 0 4 1
A _GlancesCurses.get_stats_display_height() 0 12 3
B _GlancesCurses.__display_left() 0 12 6
A _GlancesCurses.init_line() 0 4 1
A _GlancesCurses.wait() 0 3 1
A _GlancesCurses.disable_fullquicklook() 0 4 2
F _GlancesCurses.__display_top() 0 74 16
A _GlancesCurses._init_cursor() 0 8 3
A GlancesTextbox.do_command() 0 6 3
B _GlancesCurses.__display_right() 0 28 8
A _GlancesCurses.init_line_column() 0 4 1
A _GlancesCurses._init_history() 0 4 1
F _GlancesCurses._init_colors() 0 113 13
F _GlancesCurses.__catch_key() 0 82 26
A _GlancesCurses.get_key() 0 5 1
A _GlancesCurses.enable_top() 0 4 2
A _GlancesCurses.loop_position() 0 6 3
A _GlancesCurses.__display_header() 0 27 3
A _GlancesCurses.is_theme() 0 3 1
A GlancesTextbox.__init__() 0 2 1
A _GlancesCurses.load_config() 0 7 3
A _GlancesCurses.set_cursor() 0 12 3
F _GlancesCurses.display_plugin() 0 91 22

How to fix   Complexity   

Complexity

Complex classes like glances.outputs.glances_curses 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 -*-
0 ignored issues
show
coding-style introduced by
Too many lines in module (1068/1000)
Loading history...
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
"""Curses interface class."""
21
from __future__ import unicode_literals
22
23
import re
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
Unused Code introduced by
The import re seems to be unused.
Loading history...
24
import sys
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
25
26
from glances.compat import to_ascii, nativestr, b, u, itervalues
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
Unused Code introduced by
Unused to_ascii imported from glances.compat
Loading history...
Unused Code introduced by
Unused b imported from glances.compat
Loading history...
27
from glances.globals import MACOS, WINDOWS
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
28
from glances.logger import logger
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
29
from glances.events import glances_events
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
30
from glances.processes import glances_processes
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
31
from glances.timer import Timer
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
32
33
# Import curses library for "normal" operating system
34
if not WINDOWS:
35
    try:
36
        import curses
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
37
        import curses.panel
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
38
        from curses.textpad import Textbox
0 ignored issues
show
introduced by
import missing from __future__ import absolute_import
Loading history...
39
    except ImportError:
40
        logger.critical("Curses module not found. Glances cannot start in standalone mode.")
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (92/80).

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

Loading history...
41
        sys.exit(1)
42
43
44
class _GlancesCurses(object):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (33/7)
Loading history...
best-practice introduced by
Too many public methods (24/20)
Loading history...
45
46
    """This class manages the curses display (and key pressed).
47
48
    Note: It is a private class, use GlancesCursesClient or GlancesCursesBrowser.
0 ignored issues
show
Coding Style introduced by
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...
49
    """
50
51
    _hotkeys = {
52
        '0': {'switch': 'disable_irix'},
53
        '1': {'switch': 'percpu'},
54
        '2': {'switch': 'disable_left_sidebar'},
55
        '3': {'switch': 'disable_quicklook'},
56
        '6': {'switch': 'meangpu'},
57
        '/': {'switch': 'process_short_name'},
58
        'A': {'switch': 'disable_amps'},
59
        'b': {'switch': 'byte'},
60
        'B': {'switch': 'diskio_iops'},
61
        'C': {'switch': 'disable_cloud'},
62
        'D': {'switch': 'disable_docker'},
63
        'd': {'switch': 'disable_diskio'},
64
        'F': {'switch': 'fs_free_space'},
65
        'g': {'switch': 'generate_graph'},
66
        'G': {'switch': 'disable_gpu'},
67
        'h': {'switch': 'help_tag'},
68
        'I': {'switch': 'disable_ip'},
69
        'k': {'switch': 'disable_connections'},
70
        'l': {'switch': 'disable_alert'},
71
        'M': {'switch': 'reset_minmax_tag'},
72
        'n': {'switch': 'disable_network'},
73
        'N': {'switch': 'disable_now'},
74
        'P': {'switch': 'disable_ports'},
75
        'Q': {'switch': 'enable_irq'},
76
        'R': {'switch': 'disable_raid'},
77
        's': {'switch': 'disable_sensors'},
78
        'S': {'switch': 'sparkline'},
79
        'T': {'switch': 'network_sum'},
80
        'U': {'switch': 'network_cumul'},
81
        'W': {'switch': 'disable_wifi'},
82
        # Processes sort hotkeys
83
        'a': {'auto_sort': True, 'sort_key': 'cpu_percent'},
84
        'c': {'auto_sort': False, 'sort_key': 'cpu_percent'},
85
        'i': {'auto_sort': False, 'sort_key': 'io_counters'},
86
        'm': {'auto_sort': False, 'sort_key': 'memory_percent'},
87
        'p': {'auto_sort': False, 'sort_key': 'name'},
88
        't': {'auto_sort': False, 'sort_key': 'cpu_times'},
89
        'u': {'auto_sort': False, 'sort_key': 'username'},
90
    }
91
92
    _sort_loop = ['cpu_percent', 'memory_percent', 'username',
93
                  'cpu_times', 'io_counters', 'name']
94
95
    # Define top menu
96
    _top = ['quicklook', 'cpu', 'percpu', 'gpu', 'mem', 'memswap', 'load']
97
    _quicklook_max_width = 68
98
99
    # Define left sidebar
100
    _left_sidebar = ['network', 'connections', 'wifi', 'ports', 'diskio', 'fs',
101
                     'irq', 'folders', 'raid', 'sensors', 'now']
102
    _left_sidebar_min_width = 23
103
    _left_sidebar_max_width = 34
104
105
    # Define right sidebar
106
    _right_sidebar = ['docker', 'processcount', 'amps', 'processlist', 'alert']
107
108
    def __init__(self, config=None, args=None):
109
        # Init
110
        self.config = config
111
        self.args = args
112
113
        # Init windows positions
114
        self.term_w = 80
115
        self.term_h = 24
116
117
        # Space between stats
118
        self.space_between_column = 3
119
        self.space_between_line = 2
120
121
        # Init the curses screen
122
        self.screen = curses.initscr()
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
123
        if not self.screen:
124
            logger.critical("Cannot init the curses library.\n")
125
            sys.exit(1)
126
127
        # Load the 'outputs' section of the configuration file
128
        # - Init the theme (default is black)
129
        self.theme = {'name': 'black'}
130
131
        # Load configuration file
132
        self.load_config(config)
133
134
        # Init cursor
135
        self._init_cursor()
136
137
        # Init the colors
138
        self._init_colors()
139
140
        # Init main window
141
        self.term_window = self.screen.subwin(0, 0)
142
143
        # Init edit filter tag
144
        self.edit_filter = False
145
146
        # Init the process min/max reset
147
        self.args.reset_minmax_tag = False
148
149
        # Catch key pressed with non blocking mode
150
        self.term_window.keypad(1)
151
        self.term_window.nodelay(1)
152
        self.pressedkey = -1
153
154
        # History tag
155
        self._init_history()
156
157
    def load_config(self, config):
158
        """Load the outputs section of the configuration file."""
159
        # Load the theme
160
        if config is not None and config.has_section('outputs'):
161
            logger.debug('Read the outputs section in the configuration file')
162
            self.theme['name'] = config.get_value('outputs', 'curse_theme', default='black')
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (92/80).

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

Loading history...
163
            logger.debug('Theme for the curse interface: {}'.format(self.theme['name']))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (88/80).

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

Loading history...
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
164
165
    def is_theme(self, name):
166
        """Return True if the theme *name* should be used."""
167
        return getattr(self.args, 'theme_' + name) or self.theme['name'] == name
168
169
    def _init_history(self):
170
        """Init the history option."""
171
172
        self.reset_history_tag = False
173
174
    def _init_cursor(self):
175
        """Init cursors."""
176
177
        if hasattr(curses, 'noecho'):
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
178
            curses.noecho()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named noecho.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
179
        if hasattr(curses, 'cbreak'):
180
            curses.cbreak()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named cbreak.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
181
        self.set_cursor(0)
182
183
    def _init_colors(self):
184
        """Init the Curses color layout."""
185
186
        # Set curses options
187
        try:
188
            if hasattr(curses, 'start_color'):
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
189
                curses.start_color()
190
            if hasattr(curses, 'use_default_colors'):
191
                curses.use_default_colors()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named use_default_colors.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
192
        except Exception as e:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
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...
193
            logger.warning('Error initializing terminal color ({})'.format(e))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
194
195
        # Init colors
196
        if self.args.disable_bold:
197
            A_BOLD = 0
0 ignored issues
show
Coding Style Naming introduced by
The name A_BOLD 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...
198
            self.args.disable_bg = True
199
        else:
200
            A_BOLD = curses.A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name A_BOLD 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...
201
202
        self.title_color = A_BOLD
203
        self.title_underline_color = A_BOLD | curses.A_UNDERLINE
204
        self.help_color = A_BOLD
205
206
        if curses.has_colors():
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named has_colors.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
207
            # The screen is compatible with a colored design
208
            if self.is_theme('white'):
209
                # White theme: black ==> white
210
                curses.init_pair(1, curses.COLOR_BLACK, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
211
            else:
212
                curses.init_pair(1, curses.COLOR_WHITE, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
213
            if self.args.disable_bg:
214
                curses.init_pair(2, curses.COLOR_RED, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
215
                curses.init_pair(3, curses.COLOR_GREEN, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
216
                curses.init_pair(4, curses.COLOR_BLUE, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
217
                curses.init_pair(5, curses.COLOR_MAGENTA, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
218
            else:
219
                curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_RED)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
220
                curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_GREEN)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
221
                curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
222
                curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_MAGENTA)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
223
            curses.init_pair(6, curses.COLOR_RED, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
224
            curses.init_pair(7, curses.COLOR_GREEN, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
225
            curses.init_pair(8, curses.COLOR_BLUE, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
226
227
            # Colors text styles
228
            if curses.COLOR_PAIRS > 8:
229
                try:
230
                    curses.init_pair(9, curses.COLOR_MAGENTA, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
231
                except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
232
                    if self.is_theme('white'):
233
                        curses.init_pair(9, curses.COLOR_BLACK, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
234
                    else:
235
                        curses.init_pair(9, curses.COLOR_WHITE, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
236
                try:
237
                    curses.init_pair(10, curses.COLOR_CYAN, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
238
                except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
239
                    if self.is_theme('white'):
240
                        curses.init_pair(10, curses.COLOR_BLACK, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
241
                    else:
242
                        curses.init_pair(10, curses.COLOR_WHITE, -1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named init_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
243
244
                self.ifWARNING_color2 = curses.color_pair(9) | A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name ifWARNING_color2 does not conform to the attribute 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...
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
245
                self.ifCRITICAL_color2 = curses.color_pair(6) | A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name ifCRITICAL_color2 does not conform to the attribute 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...
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
246
                self.filter_color = curses.color_pair(10) | A_BOLD
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
247
248
            self.no_color = curses.color_pair(1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
249
            self.default_color = curses.color_pair(3) | A_BOLD
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
250
            self.nice_color = curses.color_pair(9)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
251
            self.cpu_time_color = curses.color_pair(9)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
252
            self.ifCAREFUL_color = curses.color_pair(4) | A_BOLD
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
Coding Style Naming introduced by
The name ifCAREFUL_color does not conform to the attribute 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...
253
            self.ifWARNING_color = curses.color_pair(5) | A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name ifWARNING_color does not conform to the attribute 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...
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
254
            self.ifCRITICAL_color = curses.color_pair(2) | A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name ifCRITICAL_color does not conform to the attribute 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...
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
255
            self.default_color2 = curses.color_pair(7)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
256
            self.ifCAREFUL_color2 = curses.color_pair(8) | A_BOLD
0 ignored issues
show
Coding Style Naming introduced by
The name ifCAREFUL_color2 does not conform to the attribute 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...
Bug introduced by
The Module curses does not seem to have a member named color_pair.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
257
258
        else:
259
            # The screen is NOT compatible with a colored design
260
            # switch to B&W text styles
261
            self.no_color = curses.A_NORMAL
262
            self.default_color = curses.A_NORMAL
263
            self.nice_color = A_BOLD
264
            self.cpu_time_color = A_BOLD
265
            self.ifCAREFUL_color = curses.A_UNDERLINE
266
            self.ifWARNING_color = A_BOLD
267
            self.ifCRITICAL_color = curses.A_REVERSE
268
            self.default_color2 = curses.A_NORMAL
269
            self.ifCAREFUL_color2 = curses.A_UNDERLINE
270
            self.ifWARNING_color2 = A_BOLD
271
            self.ifCRITICAL_color2 = curses.A_REVERSE
272
            self.filter_color = A_BOLD
273
274
        # Define the colors list (hash table) for stats
275
        self.colors_list = {
276
            'DEFAULT': self.no_color,
277
            'UNDERLINE': curses.A_UNDERLINE,
278
            'BOLD': A_BOLD,
279
            'SORT': A_BOLD,
280
            'OK': self.default_color2,
281
            'MAX': self.default_color2 | curses.A_BOLD,
282
            'FILTER': self.filter_color,
283
            'TITLE': self.title_color,
284
            'PROCESS': self.default_color2,
285
            'STATUS': self.default_color2,
286
            'NICE': self.nice_color,
287
            'CPU_TIME': self.cpu_time_color,
288
            'CAREFUL': self.ifCAREFUL_color2,
289
            'WARNING': self.ifWARNING_color2,
290
            'CRITICAL': self.ifCRITICAL_color2,
291
            'OK_LOG': self.default_color,
292
            'CAREFUL_LOG': self.ifCAREFUL_color,
293
            'WARNING_LOG': self.ifWARNING_color,
294
            'CRITICAL_LOG': self.ifCRITICAL_color,
295
            'PASSWORD': curses.A_PROTECT
296
        }
297
298
    def set_cursor(self, value):
0 ignored issues
show
Coding Style introduced by
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...
299
        """Configure the curse cursor apparence.
300
301
        0: invisible
302
        1: visible
303
        2: very visible
304
        """
305
        if hasattr(curses, 'curs_set'):
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
306
            try:
307
                curses.curs_set(value)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named curs_set.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
308
            except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
309
                pass
310
311
    # def get_key(self, window):
312
    #     # Catch ESC key AND numlock key (issue #163)
313
    #     keycode = [0, 0]
314
    #     keycode[0] = window.getch()
315
    #     keycode[1] = window.getch()
316
    #
317
    #     if keycode != [-1, -1]:
318
    #         logger.debug("Keypressed (code: %s)" % keycode)
319
    #
320
    #     if keycode[0] == 27 and keycode[1] != -1:
321
    #         # Do not escape on specials keys
322
    #         return -1
323
    #     else:
324
    #         return keycode[0]
325
326
    def get_key(self, window):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Coding Style introduced by
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...
327
        # @TODO: Check issue #163
328
        ret = window.getch()
329
        logger.debug("Keypressed (code: %s)" % ret)
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
330
        return ret
331
332
    def __catch_key(self, return_to_browser=False):
333
        # Catch the pressed key
334
        self.pressedkey = self.get_key(self.term_window)
335
336
        # Actions (available in the global hotkey dict)...
337
        for hotkey in self._hotkeys:
338
            if self.pressedkey == ord(hotkey) and 'switch' in self._hotkeys[hotkey]:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

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

Loading history...
339
                setattr(self.args,
340
                        self._hotkeys[hotkey]['switch'],
341
                        not getattr(self.args,
342
                                    self._hotkeys[hotkey]['switch']))
343
            if self.pressedkey == ord(hotkey) and 'auto_sort' in self._hotkeys[hotkey]:
0 ignored issues
show
Coding Style introduced by
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...
344
                setattr(glances_processes,
345
                        'auto_sort',
346
                        self._hotkeys[hotkey]['auto_sort'])
347
            if self.pressedkey == ord(hotkey) and 'sort_key' in self._hotkeys[hotkey]:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (86/80).

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

Loading history...
348
                setattr(glances_processes,
349
                        'sort_key',
350
                        self._hotkeys[hotkey]['sort_key'])
351
352
        # Other actions...
353
        if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'):
354
            # 'ESC'|'q' > Quit
355
            if return_to_browser:
356
                logger.info("Stop Glances client and return to the browser")
357
            else:
358
                logger.info("Stop Glances (keypressed: {})".format(self.pressedkey))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (84/80).

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

Loading history...
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
359
        elif self.pressedkey == ord('\n'):
360
            # 'ENTER' > Edit the process filter
361
            self.edit_filter = not self.edit_filter
362
        elif self.pressedkey == ord('4'):
363
            self.args.full_quicklook = not self.args.full_quicklook
364
            if self.args.full_quicklook:
365
                self.enable_fullquicklook()
366
            else:
367
                self.disable_fullquicklook()
368
        elif self.pressedkey == ord('5'):
369
            self.args.disable_top = not self.args.disable_top
370
            if self.args.disable_top:
371
                self.disable_top()
372
            else:
373
                self.enable_top()
374
        elif self.pressedkey == ord('e'):
375
            # 'e' > Enable/Disable process extended
376
            self.args.enable_process_extended = not self.args.enable_process_extended
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (85/80).

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

Loading history...
377
            if not self.args.enable_process_extended:
378
                glances_processes.disable_extended()
379
            else:
380
                glances_processes.enable_extended()
381
        elif self.pressedkey == ord('E'):
382
            # 'E' > Erase the process filter
383
            glances_processes.process_filter = None
384
        elif self.pressedkey == ord('f'):
385
            # 'f' > Show/hide fs / folder stats
386
            self.args.disable_fs = not self.args.disable_fs
387
            self.args.disable_folders = not self.args.disable_folders
388
        elif self.pressedkey == ord('w'):
389
            # 'w' > Delete finished warning logs
390
            glances_events.clean()
391
        elif self.pressedkey == ord('x'):
392
            # 'x' > Delete finished warning and critical logs
393
            glances_events.clean(critical=True)
394
        elif self.pressedkey == ord('z'):
395
            # 'z' > Enable or disable processes
396
            self.args.disable_process = not self.args.disable_process
397
            if self.args.disable_process:
398
                glances_processes.disable()
399
            else:
400
                glances_processes.enable()
401
        elif self.pressedkey == curses.KEY_LEFT:
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
402
            # "<" (left arrow) navigation through process sort
403
            setattr(glances_processes, 'auto_sort', False)
404
            next_sort = (self.loop_position() - 1) % len(self._sort_loop)
405
            glances_processes.sort_key = self._sort_loop[next_sort]
406
        elif self.pressedkey == curses.KEY_RIGHT:
407
            # ">" (right arrow) navigation through process sort
408
            setattr(glances_processes, 'auto_sort', False)
409
            next_sort = (self.loop_position() + 1) % len(self._sort_loop)
410
            glances_processes.sort_key = self._sort_loop[next_sort]
411
412
        # Return the key code
413
        return self.pressedkey
414
415
    def loop_position(self):
416
        """Return the current sort in the loop"""
417
        for i, v in enumerate(self._sort_loop):
0 ignored issues
show
Coding Style Naming introduced by
The name v 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...
418
            if v == glances_processes.sort_key:
419
                return i
420
        return 0
421
422
    def disable_top(self):
423
        """Disable the top panel"""
424
        for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap', 'load']:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
425
            setattr(self.args, 'disable_' + p, True)
426
427
    def enable_top(self):
428
        """Enable the top panel"""
429
        for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap', 'load']:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
430
            setattr(self.args, 'disable_' + p, False)
431
432
    def disable_fullquicklook(self):
433
        """Disable the full quicklook mode"""
434
        for p in ['quicklook', 'cpu', 'gpu', 'mem', 'memswap']:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
435
            setattr(self.args, 'disable_' + p, False)
436
437
    def enable_fullquicklook(self):
438
        """Disable the full quicklook mode"""
439
        self.args.disable_quicklook = False
440
        for p in ['cpu', 'gpu', 'mem', 'memswap']:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
441
            setattr(self.args, 'disable_' + p, True)
442
443
    def end(self):
0 ignored issues
show
Coding Style introduced by
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...
444
        """Shutdown the curses window."""
445
        if hasattr(curses, 'echo'):
0 ignored issues
show
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
446
            curses.echo()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named echo.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
447
        if hasattr(curses, 'nocbreak'):
448
            curses.nocbreak()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named nocbreak.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
449
        if hasattr(curses, 'curs_set'):
450
            try:
451
                curses.curs_set(1)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named curs_set.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
452
            except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
453
                pass
454
        curses.endwin()
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named endwin.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
455
456
    def init_line_column(self):
457
        """Init the line and column position for the curses interface."""
458
        self.init_line()
459
        self.init_column()
460
461
    def init_line(self):
462
        """Init the line position for the curses interface."""
463
        self.line = 0
0 ignored issues
show
Coding Style introduced by
The attribute line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
464
        self.next_line = 0
0 ignored issues
show
Coding Style introduced by
The attribute next_line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
465
466
    def init_column(self):
467
        """Init the column position for the curses interface."""
468
        self.column = 0
0 ignored issues
show
Coding Style introduced by
The attribute column was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
469
        self.next_column = 0
0 ignored issues
show
Coding Style introduced by
The attribute next_column was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
470
471
    def new_line(self):
472
        """New line in the curses interface."""
473
        self.line = self.next_line
0 ignored issues
show
Coding Style introduced by
The attribute line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
474
475
    def new_column(self):
476
        """New column in the curses interface."""
477
        self.column = self.next_column
0 ignored issues
show
Coding Style introduced by
The attribute column was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
478
479
    def __get_stat_display(self, stats, layer):
0 ignored issues
show
Unused Code introduced by
The argument layer seems to be unused.
Loading history...
480
        """Return a dict of dict with all the stats display.
481
        stats: Global stats dict
482
        layer: ~ cs_status
483
            "None": standalone or server mode
484
            "Connected": Client is connected to a Glances server
485
            "SNMP": Client is connected to a SNMP server
486
            "Disconnected": Client is disconnected from the server
487
488
        :returns: dict of dict
489
            * key: plugin name
490
            * value: dict returned by the get_stats_display Plugin method
491
        """
492
        ret = {}
493
494
        for p in stats.getPluginsList(enable=False):
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
495
            if p == 'quicklook' or p == 'processlist':
496
                # processlist is done later
497
                # because we need to know how many processes could be displayed
498
                continue
499
500
            # Compute the plugin max size
501
            plugin_max_width = None
502
            if p in self._left_sidebar:
503
                plugin_max_width = max(self._left_sidebar_min_width,
504
                                       self.screen.getmaxyx()[1] - 105)
505
                plugin_max_width = min(self._left_sidebar_max_width,
506
                                       plugin_max_width)
507
508
            # Get the view
509
            ret[p] = stats.get_plugin(p).get_stats_display(args=self.args,
510
                                                           max_width=plugin_max_width)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (86/80).

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

Loading history...
511
512
        return ret
513
514
    def display(self, stats, cs_status=None):
515
        """Display stats on the screen.
516
517
        stats: Stats database to display
518
        cs_status:
519
            "None": standalone or server mode
520
            "Connected": Client is connected to a Glances server
521
            "SNMP": Client is connected to a SNMP server
522
            "Disconnected": Client is disconnected from the server
523
524
        Return:
525
            True if the stats have been displayed
526
            False if the help have been displayed
527
        """
528
        # Init the internal line/column for Glances Curses
529
        self.init_line_column()
530
531
        # Update the stats messages
532
        ###########################
533
534
        # Get all the plugins but quicklook and proceslist
535
        self.args.cs_status = cs_status
536
        __stat_display = self.__get_stat_display(stats, layer=cs_status)
537
538
        # Adapt number of processes to the available space
539
        max_processes_displayed = (
540
            self.screen.getmaxyx()[0] - 11 -
541
            (0 if 'docker' not in __stat_display else
542
                self.get_stats_display_height(__stat_display["docker"])) -
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (remove 3 spaces).
Loading history...
543
            (0 if 'processcount' not in __stat_display else
544
                self.get_stats_display_height(__stat_display["processcount"])) -
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (remove 3 spaces).
Loading history...
545
            (0 if 'amps' not in __stat_display else
546
                self.get_stats_display_height(__stat_display["amps"])) -
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (remove 3 spaces).
Loading history...
547
            (0 if 'alert' not in __stat_display else
548
                self.get_stats_display_height(__stat_display["alert"])))
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (remove 3 spaces).
Loading history...
549
550
        try:
551
            if self.args.enable_process_extended:
552
                max_processes_displayed -= 4
553
        except AttributeError:
554
            pass
555
        if max_processes_displayed < 0:
556
            max_processes_displayed = 0
557
        if (glances_processes.max_processes is None or
558
                glances_processes.max_processes != max_processes_displayed):
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (remove 4 spaces).
Loading history...
559
            logger.debug("Set number of displayed processes to {}".format(max_processes_displayed))
0 ignored issues
show
Coding Style introduced by
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
Use formatting in logging functions and pass the parameters as arguments
Loading history...
560
            glances_processes.max_processes = max_processes_displayed
561
562
        # Get the processlist
563
        __stat_display["processlist"] = stats.get_plugin(
564
            'processlist').get_stats_display(args=self.args)
565
566
        # Display the stats on the curses interface
567
        ###########################################
568
569
        # Help screen (on top of the other stats)
570
        if self.args.help_tag:
571
            # Display the stats...
572
            self.display_plugin(
573
                stats.get_plugin('help').get_stats_display(args=self.args))
574
            # ... and exit
575
            return False
576
577
        # =====================================
578
        # Display first line (system+ip+uptime)
579
        # Optionnaly: Cloud on second line
580
        # =====================================
581
        self.__display_header(__stat_display)
582
583
        # ==============================================================
584
        # Display second line (<SUMMARY>+CPU|PERCPU+<GPU>+LOAD+MEM+SWAP)
585
        # ==============================================================
586
        self.__display_top(__stat_display, stats)
587
588
        # ==================================================================
589
        # Display left sidebar (NETWORK+PORTS+DISKIO+FS+SENSORS+Current time)
590
        # ==================================================================
591
        self.__display_left(__stat_display)
592
593
        # ====================================
594
        # Display right stats (process and co)
595
        # ====================================
596
        self.__display_right(__stat_display)
597
598
        # =====================
599
        # Others popup messages
600
        # =====================
601
602
        # Display edit filter popup
603
        # Only in standalone mode (cs_status is None)
604
        if self.edit_filter and cs_status is None:
605
            new_filter = self.display_popup(
606
                'Process filter pattern: \n\n' +
607
                'Examples:\n' +
608
                '- python\n' +
609
                '- .*python.*\n' +
610
                '- /usr/lib.*\n' +
611
                '- name:.*nautilus.*\n' +
612
                '- cmdline:.*glances.*\n' +
613
                '- username:nicolargo\n' +
614
                '- username:^root        ',
615
                is_input=True,
616
                input_value=glances_processes.process_filter_input)
617
            glances_processes.process_filter = new_filter
618
        elif self.edit_filter and cs_status is not None:
619
            self.display_popup('Process filter only available in standalone mode')
0 ignored issues
show
Coding Style introduced by
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...
620
        self.edit_filter = False
621
622
        # Display graph generation popup
623
        if self.args.generate_graph:
624
            self.display_popup('Generate graph in {}'.format(self.args.export_graph_path))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (90/80).

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

Loading history...
625
626
        return True
627
628
    def __display_header(self, stat_display):
629
        """Display the firsts lines (header) in the Curses interface.
630
631
        system + ip + uptime
632
        (cloud)
633
        """
634
        # First line
635
        self.new_line()
636
        self.space_between_column = 0
637
        l_uptime = 1
638
        for i in ['system', 'ip', 'uptime']:
639
            if i in stat_display:
640
                l_uptime += self.get_stats_display_width(stat_display[i])
641
        self.display_plugin(
642
            stat_display["system"],
643
            display_optional=(self.screen.getmaxyx()[1] >= l_uptime))
644
        self.space_between_column = 3
645
        self.new_column()
646
        self.display_plugin(stat_display["ip"])
647
        self.new_column()
648
        self.display_plugin(
649
            stat_display["uptime"],
650
            add_space=-(self.get_stats_display_width(stat_display["cloud"]) != 0))
0 ignored issues
show
Coding Style introduced by
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...
651
        # Second line (optional)
652
        self.init_column()
653
        self.new_line()
654
        self.display_plugin(stat_display["cloud"])
655
656
    def __display_top(self, stat_display, stats):
657
        """Display the second line in the Curses interface.
658
659
        <QUICKLOOK> + CPU|PERCPU + <GPU> + MEM + SWAP + LOAD
660
        """
661
        self.init_column()
662
        self.new_line()
663
664
        # Init quicklook
665
        stat_display['quicklook'] = {'msgdict': []}
666
667
        # Dict for plugins width
668
        plugin_widths = {}
669
        for p in self._top:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
670
            plugin_widths[p] = self.get_stats_display_width(stat_display.get(p, 0)) if hasattr(self.args, 'disable_' + p) else 0
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (128/80).

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

Loading history...
671
672
        # Width of all plugins
673
        stats_width = sum(itervalues(plugin_widths))
674
675
        # Number of plugin but quicklook
676
        stats_number = sum([int(stat_display[p]['msgdict'] != []) for p in self._top if not getattr(self.args, 'disable_' + p)])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (128/80).

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

Loading history...
677
678
        if not self.args.disable_quicklook:
679
            # Quick look is in the place !
680
            if self.args.full_quicklook:
681
                quicklook_width = self.screen.getmaxyx()[1] - (stats_width + 8 + stats_number * self.space_between_column)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (122/80).

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

Loading history...
682
            else:
683
                quicklook_width = min(self.screen.getmaxyx()[1] - (stats_width + 8 + stats_number * self.space_between_column),
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (127/80).

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

Loading history...
684
                                      self._quicklook_max_width - 5)
685
            try:
686
                stat_display["quicklook"] = stats.get_plugin(
687
                    'quicklook').get_stats_display(max_width=quicklook_width, args=self.args)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (93/80).

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

Loading history...
688
            except AttributeError as e:
0 ignored issues
show
Coding Style Naming introduced by
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...
689
                logger.debug("Quicklook plugin not available (%s)" % e)
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
690
            else:
691
                plugin_widths['quicklook'] = self.get_stats_display_width(stat_display["quicklook"])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (100/80).

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

Loading history...
692
                stats_width = sum(itervalues(plugin_widths)) + 1
693
            self.space_between_column = 1
694
            self.display_plugin(stat_display["quicklook"])
695
            self.new_column()
696
697
        # Compute spaces between plugins
698
        # Note: Only one space between Quicklook and others
699
        plugin_display_optional = {}
700
        for p in self._top:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
701
            plugin_display_optional[p] = True
702
        if stats_number > 1:
703
            self.space_between_column = max(1, int((self.screen.getmaxyx()[1] - stats_width) / (stats_number - 1)))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/80).

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

Loading history...
introduced by
division w/o __future__ statement
Loading history...
704
            for p in ['mem', 'cpu']:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
705
                # No space ? Remove optional stats
706
                if self.space_between_column < 3:
707
                    plugin_display_optional[p] = False
708
                    plugin_widths[p] = self.get_stats_display_width(stat_display[p], without_option=True) if hasattr(self.args, 'disable_' + p) else 0
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (150/80).

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

Loading history...
709
                    stats_width = sum(itervalues(plugin_widths)) + 1
710
                    self.space_between_column = max(1, int((self.screen.getmaxyx()[1] - stats_width) / (stats_number - 1)))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (123/80).

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

Loading history...
introduced by
division w/o __future__ statement
Loading history...
711
        else:
712
            self.space_between_column = 0
713
714
        # Display CPU, MEM, SWAP and LOAD
715
        for p in self._top:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
716
            if p == 'quicklook':
717
                continue
718
            if p in stat_display:
719
                self.display_plugin(stat_display[p],
720
                                    display_optional=plugin_display_optional[p])
721
            if p is not 'load':
722
                # Skip last column
723
                self.new_column()
724
725
        # Space between column
726
        self.space_between_column = 3
727
728
        # Backup line position
729
        self.saved_line = self.next_line
0 ignored issues
show
Coding Style introduced by
The attribute saved_line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
730
731
    def __display_left(self, stat_display):
732
        """Display the left sidebar in the Curses interface."""
733
        self.init_column()
734
735
        if self.args.disable_left_sidebar:
736
            return
737
738
        for p in self._left_sidebar:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
739
            if ((hasattr(self.args, 'enable_' + p) or
740
                 hasattr(self.args, 'disable_' + p)) and p in stat_display):
741
                self.new_line()
742
                self.display_plugin(stat_display[p])
743
744
    def __display_right(self, stat_display):
745
        """Display the right sidebar in the Curses interface.
746
747
        docker + processcount + amps + processlist + alert
748
        """
749
        # Do not display anything if space is not available...
750
        if self.screen.getmaxyx()[1] < self._left_sidebar_min_width:
751
            return
752
753
        # Restore line position
754
        self.next_line = self.saved_line
0 ignored issues
show
Coding Style introduced by
The attribute next_line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
755
756
        # Display right sidebar
757
        self.new_column()
758
        for p in self._right_sidebar:
0 ignored issues
show
Coding Style Naming introduced by
The name p 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...
759
            if ((hasattr(self.args, 'enable_' + p) or
760
                 hasattr(self.args, 'disable_' + p)) and p in stat_display):
761
                if p not in p:
762
                    # Catch for issue #1470
763
                    continue
764
                self.new_line()
765
                if p == 'processlist':
766
                    self.display_plugin(stat_display['processlist'],
767
                                        display_optional=(self.screen.getmaxyx()[1] > 102),
0 ignored issues
show
Coding Style introduced by
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...
768
                                        display_additional=(not MACOS),
769
                                        max_y=(self.screen.getmaxyx()[0] - self.get_stats_display_height(stat_display['alert']) - 2))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (133/80).

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

Loading history...
770
                else:
771
                    self.display_plugin(stat_display[p])
772
773
    def display_popup(self, message,
0 ignored issues
show
best-practice introduced by
Too many arguments (8/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (18/15).
Loading history...
774
                      size_x=None, size_y=None,
775
                      duration=3,
776
                      is_input=False,
777
                      input_size=30,
778
                      input_value=None):
779
        """
780
        Display a centered popup.
781
782
        If is_input is False:
783
         Display a centered popup with the given message during duration seconds
784
         If size_x and size_y: set the popup size
785
         else set it automatically
786
         Return True if the popup could be displayed
787
788
        If is_input is True:
789
         Display a centered popup with the given message and a input field
790
         If size_x and size_y: set the popup size
791
         else set it automatically
792
         Return the input string or None if the field is empty
793
        """
794
        # Center the popup
795
        sentence_list = message.split('\n')
796
        if size_x is None:
797
            size_x = len(max(sentence_list, key=len)) + 4
798
            # Add space for the input field
799
            if is_input:
800
                size_x += input_size
801
        if size_y is None:
802
            size_y = len(sentence_list) + 4
803
        screen_x = self.screen.getmaxyx()[1]
804
        screen_y = self.screen.getmaxyx()[0]
805
        if size_x > screen_x or size_y > screen_y:
806
            # No size to display the popup => abord
807
            return False
808
        pos_x = int((screen_x - size_x) / 2)
0 ignored issues
show
introduced by
division w/o __future__ statement
Loading history...
809
        pos_y = int((screen_y - size_y) / 2)
0 ignored issues
show
introduced by
division w/o __future__ statement
Loading history...
810
811
        # Create the popup
812
        popup = curses.newwin(size_y, size_x, pos_y, pos_x)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named newwin.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
813
814
        # Fill the popup
815
        popup.border()
816
817
        # Add the message
818
        for y, m in enumerate(message.split('\n')):
0 ignored issues
show
Coding Style Naming introduced by
The name y 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...
Coding Style Naming introduced by
The name m 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...
819
            popup.addnstr(2 + y, 2, m, len(m))
820
821
        if is_input and not WINDOWS:
822
            # Create a subwindow for the text field
823
            subpop = popup.derwin(1, input_size, 2, 2 + len(m))
0 ignored issues
show
Bug introduced by
The loop variable m might not be defined here.
Loading history...
introduced by
The variable m does not seem to be defined in case the for loop on line 818 is not entered. Are you sure this can never be the case?
Loading history...
824
            subpop.attron(self.colors_list['FILTER'])
825
            # Init the field with the current value
826
            if input_value is not None:
827
                subpop.addnstr(0, 0, input_value, len(input_value))
828
            # Display the popup
829
            popup.refresh()
830
            subpop.refresh()
831
            # Create the textbox inside the subwindows
832
            self.set_cursor(2)
833
            self.term_window.keypad(1)
834
            textbox = GlancesTextbox(subpop, insert_mode=False)
0 ignored issues
show
introduced by
The variable GlancesTextbox does not seem to be defined in case BooleanNotNode on line 1057 is False. Are you sure this can never be the case?
Loading history...
835
            textbox.edit()
836
            self.set_cursor(0)
837
            self.term_window.keypad(0)
838
            if textbox.gather() != '':
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
839
                logger.debug(
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
840
                    "User enters the following string: %s" % textbox.gather())
841
                return textbox.gather()[:-1]
842
            else:
843
                logger.debug("User centers an empty string")
844
                return None
845
        else:
846
            # Display the popup
847
            popup.refresh()
848
            self.wait(duration * 1000)
849
            return True
850
851
    def display_plugin(self, plugin_stats,
0 ignored issues
show
best-practice introduced by
Too many arguments (6/5)
Loading history...
852
                       display_optional=True,
853
                       display_additional=True,
854
                       max_y=65535,
855
                       add_space=0):
856
        """Display the plugin_stats on the screen.
857
858
        If display_optional=True display the optional stats
859
        If display_additional=True display additionnal stats
860
        max_y: do not display line > max_y
861
        add_space: add x space (line) after the plugin
862
        """
863
        # Exit if:
864
        # - the plugin_stats message is empty
865
        # - the display tag = False
866
        if plugin_stats is None or not plugin_stats['msgdict'] or not plugin_stats['display']:
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (94/80).

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

Loading history...
867
            # Exit
868
            return 0
869
870
        # Get the screen size
871
        screen_x = self.screen.getmaxyx()[1]
872
        screen_y = self.screen.getmaxyx()[0]
873
874
        # Set the upper/left position of the message
875
        if plugin_stats['align'] == 'right':
876
            # Right align (last column)
877
            display_x = screen_x - self.get_stats_display_width(plugin_stats)
878
        else:
879
            display_x = self.column
880
        if plugin_stats['align'] == 'bottom':
881
            # Bottom (last line)
882
            display_y = screen_y - self.get_stats_display_height(plugin_stats)
883
        else:
884
            display_y = self.line
885
886
        # Display
887
        x = display_x
0 ignored issues
show
Coding Style Naming introduced by
The name x 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...
888
        x_max = x
889
        y = display_y
0 ignored issues
show
Coding Style Naming introduced by
The name y 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...
890
        for m in plugin_stats['msgdict']:
0 ignored issues
show
Coding Style Naming introduced by
The name m 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...
891
            # New line
892
            if m['msg'].startswith('\n'):
893
                # Go to the next line
894
                y += 1
0 ignored issues
show
Coding Style Naming introduced by
The name y 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...
895
                # Return to the first column
896
                x = display_x
0 ignored issues
show
Coding Style Naming introduced by
The name x 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...
897
                continue
898
            # Do not display outside the screen
899
            if x < 0:
900
                continue
901
            if not m['splittable'] and (x + len(m['msg']) > screen_x):
902
                continue
903
            if y < 0 or (y + 1 > screen_y) or (y > max_y):
904
                break
905
            # If display_optional = False do not display optional stats
906
            if not display_optional and m['optional']:
907
                continue
908
            # If display_additional = False do not display additional stats
909
            if not display_additional and m['additional']:
910
                continue
911
            # Is it possible to display the stat with the current screen size
912
            # !!! Crach if not try/except... Why ???
913
            try:
914
                self.term_window.addnstr(y, x,
915
                                         m['msg'],
916
                                         # Do not disply outside the screen
917
                                         screen_x - x,
918
                                         self.colors_list[m['decoration']])
919
            except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
920
                pass
921
            else:
922
                # New column
923
                # Python 2: we need to decode to get real screen size because
924
                # UTF-8 special tree chars occupy several bytes.
925
                # Python 3: strings are strings and bytes are bytes, all is
926
                # good.
927
                try:
928
                    x += len(u(m['msg']))
0 ignored issues
show
Coding Style Naming introduced by
The name x 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...
929
                except UnicodeDecodeError:
930
                    # Quick and dirty hack for issue #745
931
                    pass
932
                if x > x_max:
933
                    x_max = x
934
935
        # Compute the next Glances column/line position
936
        self.next_column = max(
0 ignored issues
show
Coding Style introduced by
The attribute next_column was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
937
            self.next_column, x_max + self.space_between_column)
938
        self.next_line = max(self.next_line, y + self.space_between_line)
0 ignored issues
show
Coding Style introduced by
The attribute next_line was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
939
940
        # Have empty lines after the plugins
941
        self.next_line += add_space
942
943
    def erase(self):
944
        """Erase the content of the screen."""
945
        self.term_window.erase()
946
947
    def flush(self, stats, cs_status=None):
948
        """Clear and update the screen.
949
950
        stats: Stats database to display
951
        cs_status:
952
            "None": standalone or server mode
953
            "Connected": Client is connected to the server
954
            "Disconnected": Client is disconnected from the server
955
        """
956
        self.erase()
957
        self.display(stats, cs_status=cs_status)
958
959
    def update(self,
960
               stats,
961
               duration=3,
962
               cs_status=None,
963
               return_to_browser=False):
964
        """Update the screen.
965
966
        INPUT
967
        stats: Stats database to display
968
        duration: duration of the loop
969
        cs_status:
970
            "None": standalone or server mode
971
            "Connected": Client is connected to the server
972
            "Disconnected": Client is disconnected from the server
973
        return_to_browser:
974
            True: Do not exist, return to the browser list
975
            False: Exit and return to the shell
976
977
        OUTPUT
978
        True: Exit key has been pressed
979
        False: Others cases...
980
        """
981
        # Flush display
982
        self.flush(stats, cs_status=cs_status)
983
984
        # If the duration is < 0 (update + export time > refresh_time)
985
        # Then display the interface and log a message
986
        if duration <= 0:
987
            logger.warning('Update and export time higher than refresh_time.')
988
            duration = 0.1
989
990
        # Wait duration (in s) time
991
        exitkey = False
992
        countdown = Timer(duration)
993
        # Set the default timeout (in ms) for the getch method
994
        self.term_window.timeout(int(duration * 1000))
995
        while not countdown.finished() and not exitkey:
996
            # Getkey
997
            pressedkey = self.__catch_key(return_to_browser=return_to_browser)
998
            # Is it an exit key ?
999
            exitkey = (pressedkey == ord('\x1b') or pressedkey == ord('q'))
1000
            if not exitkey and pressedkey > -1:
1001
                # Redraw display
1002
                self.flush(stats, cs_status=cs_status)
1003
                # Overwrite the timeout with the countdown
1004
                self.term_window.timeout(int(countdown.get() * 1000))
1005
1006
        return exitkey
1007
1008
    def wait(self, delay=100):
0 ignored issues
show
Unused Code introduced by
The argument delay seems to be unused.
Loading history...
Coding Style introduced by
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...
1009
        """Wait delay in ms"""
1010
        curses.napms(100)
0 ignored issues
show
Bug introduced by
The Module curses does not seem to have a member named napms.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
introduced by
The variable curses does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
1011
1012
    def get_stats_display_width(self, curse_msg, without_option=False):
0 ignored issues
show
Coding Style introduced by
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...
1013
        """Return the width of the formatted curses message."""
1014
        try:
1015
            if without_option:
1016
                # Size without options
1017
                c = len(max(''.join([(u(u(nativestr(i['msg'])).encode('ascii', 'replace')) if not i['optional'] else "")
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (120/80).

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

Loading history...
Coding Style Naming introduced by
The name c 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...
1018
                                     for i in curse_msg['msgdict']]).split('\n'), key=len))
0 ignored issues
show
Coding Style introduced by
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...
1019
            else:
1020
                # Size with all options
1021
                c = len(max(''.join([u(u(nativestr(i['msg'])).encode('ascii', 'replace'))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (89/80).

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

Loading history...
Coding Style Naming introduced by
The name c 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...
1022
                                     for i in curse_msg['msgdict']]).split('\n'), key=len))
0 ignored issues
show
Coding Style introduced by
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...
1023
        except Exception as e:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
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...
1024
            logger.debug('ERROR: Can not compute plugin width ({})'.format(e))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
1025
            return 0
1026
        else:
1027
            return c
1028
1029
    def get_stats_display_height(self, curse_msg):
0 ignored issues
show
Coding Style introduced by
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...
1030
        r"""Return the height of the formatted curses message.
1031
1032
        The height is defined by the number of '\n' (new line).
1033
        """
1034
        try:
1035
            c = [i['msg'] for i in curse_msg['msgdict']].count('\n')
0 ignored issues
show
Coding Style Naming introduced by
The name c 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...
1036
        except Exception as e:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
Coding Style Naming introduced by
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...
1037
            logger.debug('ERROR: Can not compute plugin height ({})'.format(e))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
1038
            return 0
1039
        else:
1040
            return c + 1
1041
1042
1043
class GlancesCursesStandalone(_GlancesCurses):
1044
1045
    """Class for the Glances curse standalone."""
1046
1047
    pass
1048
1049
1050
class GlancesCursesClient(_GlancesCurses):
1051
1052
    """Class for the Glances curse client."""
1053
1054
    pass
1055
1056
1057
if not WINDOWS:
1058
    class GlancesTextbox(Textbox, object):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
introduced by
The variable Textbox does not seem to be defined in case BooleanNotNode on line 34 is False. Are you sure this can never be the case?
Loading history...
1059
1060
        def __init__(self, *args, **kwargs):
0 ignored issues
show
introduced by
Useless super delegation in method '__init__'
Loading history...
1061
            super(GlancesTextbox, self).__init__(*args, **kwargs)
0 ignored issues
show
introduced by
The variable GlancesTextbox does not seem to be defined in case BooleanNotNode on line 1057 is False. Are you sure this can never be the case?
Loading history...
1062
1063
        def do_command(self, ch):
1064
            if ch == 10:  # Enter
1065
                return 0
1066
            if ch == 127:  # Back
1067
                return 8
1068
            return super(GlancesTextbox, self).do_command(ch)
0 ignored issues
show
introduced by
The variable GlancesTextbox does not seem to be defined in case BooleanNotNode on line 1057 is False. Are you sure this can never be the case?
Loading history...
1069