pySMART.utils
This module contains generic utilities and configuration information for use
by the other submodules of the pySMART
package.
1# Copyright (C) 2014 Marc Herndon 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License, 5# version 2, as published by the Free Software Foundation. 6# 7# This program is distributed in the hope that it will be useful, 8# but WITHOUT ANY WARRANTY; without even the implied warranty of 9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10# GNU General Public License for more details. 11# 12# You should have received a copy of the GNU General Public License 13# along with this program; if not, write to the Free Software 14# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 15# MA 02110-1301, USA. 16# 17################################################################ 18""" 19This module contains generic utilities and configuration information for use 20by the other submodules of the `pySMART` package. 21""" 22 23import copy 24import io 25import logging 26import logging.handlers 27import os 28import traceback 29from typing import Dict, Any 30from shutil import which 31 32_srcfile = __file__ 33TRACE = logging.DEBUG - 5 34 35 36class TraceLogger(logging.Logger): 37 def __init__(self, name): 38 logging.Logger.__init__(self, name) 39 logging.addLevelName(TRACE, 'TRACE') 40 return 41 42 def trace(self, msg, *args, **kwargs): 43 self.log(TRACE, msg, *args, **kwargs) 44 45 def findCaller(self, stack_info=False, stacklevel=1): 46 """ 47 Overload built-in findCaller method 48 to omit not only logging/__init__.py but also the current file 49 """ 50 f = logging.currentframe() 51 # On some versions of IronPython, currentframe() returns None if 52 # IronPython isn't run with -X:Frames. 53 if f is not None: 54 f = f.f_back 55 orig_f = f 56 while f and stacklevel > 1: 57 f = f.f_back 58 stacklevel -= 1 59 if not f: 60 f = orig_f 61 rv = "(unknown file)", 0, "(unknown function)", None 62 while hasattr(f, "f_code"): 63 co = f.f_code 64 filename = os.path.normcase(co.co_filename) 65 if filename in (logging._srcfile, _srcfile): 66 f = f.f_back 67 continue 68 sinfo = None 69 if stack_info: 70 sio = io.StringIO() 71 sio.write('Stack (most recent call last):\n') 72 traceback.print_stack(f, file=sio) 73 sinfo = sio.getvalue() 74 if sinfo[-1] == '\n': 75 sinfo = sinfo[:-1] 76 sio.close() 77 rv = (co.co_filename, f.f_lineno, co.co_name, sinfo) 78 break 79 return rv 80 81 82def configure_trace_logging(): 83 if getattr(logging.handlers.logging.getLoggerClass(), 'trace', None) is None: 84 logging.setLoggerClass(TraceLogger) 85 86 87def any_in(search_in, *searched_items): 88 """ 89 return True if any of searched_items is in search_in otherwise False. 90 raise 91 """ 92 assert len(searched_items) > 0 93 return any(map(lambda one: one in search_in, searched_items)) 94 95 96def all_in(search_in, *searched_items): 97 """ 98 return True if all of searched_items are in search_in otherwise False 99 does not care about duplicates in searched_items potentially evaluates all of them, 100 """ 101 assert len(searched_items) > 0 102 return all(map(lambda one: one in search_in, searched_items)) 103 104 105smartctl_type_dict = { 106 'ata': 'ata', 107 'csmi': 'ata', 108 'nvme': 'nvme', 109 'sas': 'scsi', 110 'sat': 'sat', 111 'sata': 'ata', 112 'scsi': 'scsi', 113 'atacam': 'atacam' 114} 115""" 116**(dict of str):** Contains actual interface types (ie: sas, csmi) as keys and 117the corresponding smartctl interface type (ie: scsi, ata) as values. 118""" 119 120SMARTCTL_PATH = which('smartctl') 121 122 123def smartctl_isvalid_type(interface_type: str) -> bool: 124 """Tests if the interface_type is supported 125 126 Args: 127 interface_type (str): An internal interface_type 128 129 Returns: 130 bool: True if the type is supported, false z 131 """ 132 if interface_type in smartctl_type_dict: 133 return True 134 elif 'megaraid,' in interface_type: 135 return True 136 else: 137 return False 138 139 140def smartctl_type(interface_type: str) -> str: 141 """This method basically searchs on smartctl_type_dict to convert from internal 142 smartctl interface type to an understable type for smartctl. However, further 143 transforms may be performed for some special interfaces 144 145 Args: 146 interface_type (str): An internal representation of an smartctl interface type 147 148 Returns: 149 str: Returns the corresponding smartctl interface_type that matches with the internal interface representation. 150 In case it is not supported, None would be returned 151 """ 152 if interface_type in smartctl_type_dict: 153 return smartctl_type_dict[interface_type] 154 elif 'megaraid,' in interface_type: 155 return interface_type 156 else: 157 return None 158 159 160def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Dict[str, Any]: 161 if obj is None: 162 return None 163 164 if not hasattr(obj, '__dict__'): 165 return obj 166 167 prop_names = dir(obj) 168 169 if deep_copy: 170 ret = copy.deepcopy(vars(obj)) 171 else: 172 ret = vars(obj) 173 174 available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType'] 175 recursion_types = ['object', 'NvmeError'] 176 177 for prop_name in prop_names: 178 prop_val = getattr(obj, prop_name) 179 prop_val_type_name = type(prop_val).__name__ 180 181 if (prop_name[0] != '_'): 182 # Get properties from objects 183 if (prop_val_type_name in available_types) and (prop_name not in ret): 184 ret[prop_name] = prop_val 185 186 # Do recursion 187 if recursive: 188 if prop_val_type_name in recursion_types: 189 ret[prop_name] = get_object_properties( 190 prop_val, deep_copy, remove_private, recursive) 191 elif prop_val_type_name == 'list': 192 ret[prop_name] = [] 193 for item in prop_val: 194 if type(item).__name__ in recursion_types: 195 ret[prop_name].append(get_object_properties( 196 item, deep_copy, remove_private, recursive)) 197 else: 198 ret[prop_name].append(item) 199 elif prop_val_type_name == 'dict': 200 ret[prop_name] = {} 201 for key, value in prop_val.items(): 202 if type(value).__name__ in recursion_types: 203 ret[prop_name][key] = get_object_properties( 204 value, deep_copy, remove_private, recursive) 205 else: 206 ret[prop_name][key] = value 207 208 if remove_private: 209 for key in ret.keys(): 210 if key[0] == '_': 211 del ret[key] 212 213 return ret 214 215 216__all__ = ['smartctl_type', 'SMARTCTL_PATH', 217 'all_in', 'any_in', 'get_object_properties']
141def smartctl_type(interface_type: str) -> str: 142 """This method basically searchs on smartctl_type_dict to convert from internal 143 smartctl interface type to an understable type for smartctl. However, further 144 transforms may be performed for some special interfaces 145 146 Args: 147 interface_type (str): An internal representation of an smartctl interface type 148 149 Returns: 150 str: Returns the corresponding smartctl interface_type that matches with the internal interface representation. 151 In case it is not supported, None would be returned 152 """ 153 if interface_type in smartctl_type_dict: 154 return smartctl_type_dict[interface_type] 155 elif 'megaraid,' in interface_type: 156 return interface_type 157 else: 158 return None
This method basically searchs on smartctl_type_dict to convert from internal smartctl interface type to an understable type for smartctl. However, further transforms may be performed for some special interfaces
Args: interface_type (str): An internal representation of an smartctl interface type
Returns: str: Returns the corresponding smartctl interface_type that matches with the internal interface representation. In case it is not supported, None would be returned
97def all_in(search_in, *searched_items): 98 """ 99 return True if all of searched_items are in search_in otherwise False 100 does not care about duplicates in searched_items potentially evaluates all of them, 101 """ 102 assert len(searched_items) > 0 103 return all(map(lambda one: one in search_in, searched_items))
return True if all of searched_items are in search_in otherwise False does not care about duplicates in searched_items potentially evaluates all of them,
88def any_in(search_in, *searched_items): 89 """ 90 return True if any of searched_items is in search_in otherwise False. 91 raise 92 """ 93 assert len(searched_items) > 0 94 return any(map(lambda one: one in search_in, searched_items))
return True if any of searched_items is in search_in otherwise False. raise
161def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Dict[str, Any]: 162 if obj is None: 163 return None 164 165 if not hasattr(obj, '__dict__'): 166 return obj 167 168 prop_names = dir(obj) 169 170 if deep_copy: 171 ret = copy.deepcopy(vars(obj)) 172 else: 173 ret = vars(obj) 174 175 available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType'] 176 recursion_types = ['object', 'NvmeError'] 177 178 for prop_name in prop_names: 179 prop_val = getattr(obj, prop_name) 180 prop_val_type_name = type(prop_val).__name__ 181 182 if (prop_name[0] != '_'): 183 # Get properties from objects 184 if (prop_val_type_name in available_types) and (prop_name not in ret): 185 ret[prop_name] = prop_val 186 187 # Do recursion 188 if recursive: 189 if prop_val_type_name in recursion_types: 190 ret[prop_name] = get_object_properties( 191 prop_val, deep_copy, remove_private, recursive) 192 elif prop_val_type_name == 'list': 193 ret[prop_name] = [] 194 for item in prop_val: 195 if type(item).__name__ in recursion_types: 196 ret[prop_name].append(get_object_properties( 197 item, deep_copy, remove_private, recursive)) 198 else: 199 ret[prop_name].append(item) 200 elif prop_val_type_name == 'dict': 201 ret[prop_name] = {} 202 for key, value in prop_val.items(): 203 if type(value).__name__ in recursion_types: 204 ret[prop_name][key] = get_object_properties( 205 value, deep_copy, remove_private, recursive) 206 else: 207 ret[prop_name][key] = value 208 209 if remove_private: 210 for key in ret.keys(): 211 if key[0] == '_': 212 del ret[key] 213 214 return ret