| Total Complexity | 50 |
| Total Lines | 201 |
| Duplicated Lines | 0 % |
Complex classes like glances.GlancesStats 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 -*- |
||
| 42 | class GlancesStats(object): |
||
| 43 | |||
| 44 | """This class stores, updates and gives stats.""" |
||
| 45 | |||
| 46 | def __init__(self, config=None, args=None): |
||
| 47 | # Set the argument instance |
||
| 48 | self.args = args |
||
| 49 | |||
| 50 | # Set the config instance |
||
| 51 | self.config = config |
||
| 52 | |||
| 53 | # Load plugins and export modules |
||
| 54 | self.load_plugins_and_exports(self.args) |
||
| 55 | |||
| 56 | # Load the limits |
||
| 57 | self.load_limits(config) |
||
| 58 | |||
| 59 | def __getattr__(self, item): |
||
| 60 | """Overwrite the getattr method in case of attribute is not found. |
||
| 61 | |||
| 62 | The goal is to dynamically generate the following methods: |
||
| 63 | - getPlugname(): return Plugname stat in JSON format |
||
| 64 | """ |
||
| 65 | # Check if the attribute starts with 'get' |
||
| 66 | if item.startswith('get'): |
||
| 67 | # Get the plugin name |
||
| 68 | plugname = item[len('get'):].lower() |
||
| 69 | # Get the plugin instance |
||
| 70 | plugin = self._plugins[plugname] |
||
| 71 | if hasattr(plugin, 'get_stats'): |
||
| 72 | # The method get_stats exist, return it |
||
| 73 | return getattr(plugin, 'get_stats') |
||
| 74 | else: |
||
| 75 | # The method get_stats is not found for the plugin |
||
| 76 | raise AttributeError(item) |
||
| 77 | else: |
||
| 78 | # Default behavior |
||
| 79 | raise AttributeError(item) |
||
| 80 | |||
| 81 | def load_plugins_and_exports(self, args): |
||
| 82 | """Wrapper to load both plugins and export modules.""" |
||
| 83 | # Init the plugins dict |
||
| 84 | self._plugins = collections.defaultdict(dict) |
||
| 85 | # Load the plugins |
||
| 86 | self.load_plugins(args=args) |
||
| 87 | |||
| 88 | # Init the export modules dict |
||
| 89 | self._exports = collections.defaultdict(dict) |
||
| 90 | # Load the export modules |
||
| 91 | self.load_exports(args=args) |
||
| 92 | |||
| 93 | # Restoring system path |
||
| 94 | sys.path = sys_path |
||
| 95 | |||
| 96 | def load_plugins(self, args=None): |
||
| 97 | """Load all plugins in the 'plugins' folder.""" |
||
| 98 | header = "glances_" |
||
| 99 | for item in os.listdir(plugins_path): |
||
| 100 | if (item.startswith(header) and |
||
| 101 | item.endswith(".py") and |
||
| 102 | item != (header + "plugin.py")): |
||
| 103 | # Import the plugin |
||
| 104 | plugin = __import__(os.path.basename(item)[:-3]) |
||
| 105 | # Add the plugin to the dictionary |
||
| 106 | # The key is the plugin name |
||
| 107 | # for example, the file glances_xxx.py |
||
| 108 | # generate self._plugins_list["xxx"] = ... |
||
| 109 | plugin_name = os.path.basename(item)[len(header):-3].lower() |
||
| 110 | if plugin_name == 'help': |
||
| 111 | self._plugins[plugin_name] = plugin.Plugin(args=args, config=self.config) |
||
| 112 | else: |
||
| 113 | self._plugins[plugin_name] = plugin.Plugin(args=args) |
||
| 114 | # Log plugins list |
||
| 115 | logger.debug("Available plugins list: {0}".format(self.getAllPlugins())) |
||
| 116 | |||
| 117 | def load_exports(self, args=None): |
||
| 118 | """Load all export modules in the 'exports' folder.""" |
||
| 119 | if args is None: |
||
| 120 | return False |
||
| 121 | header = "glances_" |
||
| 122 | # Transform the arguments list into a dict |
||
| 123 | # The aim is to chec if the export module should be loaded |
||
| 124 | args_var = vars(locals()['args']) |
||
| 125 | for item in os.listdir(exports_path): |
||
| 126 | export_name = os.path.basename(item)[len(header):-3].lower() |
||
| 127 | if (item.startswith(header) and |
||
| 128 | item.endswith(".py") and |
||
| 129 | item != (header + "export.py") and |
||
| 130 | item != (header + "history.py") and |
||
| 131 | args_var['export_' + export_name] is not None and |
||
| 132 | args_var['export_' + export_name] is not False): |
||
| 133 | # Import the export module |
||
| 134 | export_module = __import__(os.path.basename(item)[:-3]) |
||
| 135 | # Add the export to the dictionary |
||
| 136 | # The key is the module name |
||
| 137 | # for example, the file glances_xxx.py |
||
| 138 | # generate self._exports_list["xxx"] = ... |
||
| 139 | self._exports[export_name] = export_module.Export(args=args, config=self.config) |
||
| 140 | # Log plugins list |
||
| 141 | logger.debug("Available exports modules list: {0}".format(self.getExportList())) |
||
| 142 | return True |
||
| 143 | |||
| 144 | def getAllPlugins(self): |
||
| 145 | """Return the plugins list.""" |
||
| 146 | return [p for p in self._plugins] |
||
| 147 | |||
| 148 | def getExportList(self): |
||
| 149 | """Return the exports modules list.""" |
||
| 150 | return [p for p in self._exports] |
||
| 151 | |||
| 152 | def load_limits(self, config=None): |
||
| 153 | """Load the stats limits.""" |
||
| 154 | # For each plugins, call the init_limits method |
||
| 155 | for p in self._plugins: |
||
| 156 | # logger.debug("Load limits for %s" % p) |
||
| 157 | self._plugins[p].load_limits(config) |
||
| 158 | |||
| 159 | def update(self): |
||
| 160 | """Wrapper method to update the stats.""" |
||
| 161 | # For standalone and server modes |
||
| 162 | # For each plugins, call the update method |
||
| 163 | for p in self._plugins: |
||
| 164 | # logger.debug("Update %s stats" % p) |
||
| 165 | self._plugins[p].update() |
||
| 166 | |||
| 167 | def export(self, input_stats=None): |
||
| 168 | """Export all the stats. |
||
| 169 | |||
| 170 | Each export module is ran in a dedicated thread. |
||
| 171 | """ |
||
| 172 | # threads = [] |
||
| 173 | input_stats = input_stats or {} |
||
| 174 | |||
| 175 | for e in self._exports: |
||
| 176 | logger.debug("Export stats using the %s module" % e) |
||
| 177 | thread = threading.Thread(target=self._exports[e].update, |
||
| 178 | args=(input_stats,)) |
||
| 179 | # threads.append(thread) |
||
| 180 | thread.start() |
||
| 181 | |||
| 182 | def getAll(self): |
||
| 183 | """Return all the stats (list).""" |
||
| 184 | return [self._plugins[p].get_raw() for p in self._plugins] |
||
| 185 | |||
| 186 | def getAllExports(self): |
||
| 187 | """ |
||
| 188 | Return all the stats to be exported (list). |
||
| 189 | Default behavor is to export all the stat |
||
| 190 | """ |
||
| 191 | return [self._plugins[p].get_export() for p in self._plugins] |
||
| 192 | |||
| 193 | def getAllAsDict(self): |
||
| 194 | """Return all the stats (dict).""" |
||
| 195 | # Python > 2.6 |
||
| 196 | # {p: self._plugins[p].get_raw() for p in self._plugins} |
||
| 197 | ret = {} |
||
| 198 | for p in self._plugins: |
||
| 199 | ret[p] = self._plugins[p].get_raw() |
||
| 200 | return ret |
||
| 201 | |||
| 202 | def getAllLimits(self): |
||
| 203 | """Return the plugins limits list.""" |
||
| 204 | return [self._plugins[p].limits for p in self._plugins] |
||
| 205 | |||
| 206 | def getAllLimitsAsDict(self): |
||
| 207 | """Return all the stats limits (dict).""" |
||
| 208 | ret = {} |
||
| 209 | for p in self._plugins: |
||
| 210 | ret[p] = self._plugins[p].limits |
||
| 211 | return ret |
||
| 212 | |||
| 213 | def getAllViews(self): |
||
| 214 | """Return the plugins views.""" |
||
| 215 | return [self._plugins[p].get_views() for p in self._plugins] |
||
| 216 | |||
| 217 | def getAllViewsAsDict(self): |
||
| 218 | """Return all the stats views (dict).""" |
||
| 219 | ret = {} |
||
| 220 | for p in self._plugins: |
||
| 221 | ret[p] = self._plugins[p].get_views() |
||
| 222 | return ret |
||
| 223 | |||
| 224 | def get_plugin_list(self): |
||
| 225 | """Return the plugin list.""" |
||
| 226 | return self._plugins |
||
| 227 | |||
| 228 | def get_plugin(self, plugin_name): |
||
| 229 | """Return the plugin name.""" |
||
| 230 | if plugin_name in self._plugins: |
||
| 231 | return self._plugins[plugin_name] |
||
| 232 | else: |
||
| 233 | return None |
||
| 234 | |||
| 235 | def end(self): |
||
| 236 | """End of the Glances stats.""" |
||
| 237 | # Close export modules |
||
| 238 | for e in self._exports: |
||
| 239 | self._exports[e].exit() |
||
| 240 | # Close plugins |
||
| 241 | for p in self._plugins: |
||
| 242 | self._plugins[p].exit() |
||
| 243 | |||
| 403 |