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, Optional 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: Optional[str]) -> Optional[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 is None: 153 return None 154 155 if interface_type in smartctl_type_dict: 156 return smartctl_type_dict[interface_type] 157 elif 'megaraid,' in interface_type: 158 return interface_type 159 else: 160 return None 161 162 163def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Optional[Dict[str, Any]]: 164 if obj is None: 165 return None 166 167 if hasattr(obj, '__getstate__'): 168 obj_state = obj.__getstate__() 169 if obj_state is not None: 170 return obj_state 171 172 if not hasattr(obj, '__dict__'): 173 return obj 174 175 prop_names = dir(obj) 176 177 if deep_copy: 178 ret = copy.deepcopy(vars(obj)) 179 else: 180 ret = copy.copy(vars(obj)) 181 182 available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType'] 183 recursion_types = ['object', 184 'NvmeError', 'NvmeSelfTest', 'NvmeAttributes', 185 'AtaAttributes', 'Attribute', 186 ] 187 188 for prop_name in prop_names: 189 prop_val = getattr(obj, prop_name) 190 prop_val_type_name = type(prop_val).__name__ 191 192 if (prop_name[0] != '_'): 193 # Get properties from objects 194 if (prop_val_type_name in available_types) and (prop_name not in ret): 195 # Check if prop_val has __getstate__ method, if so, call it 196 if hasattr(prop_val, '__getstate__'): 197 prop_val_state = prop_val.__getstate__() 198 if prop_val_state is not None: 199 ret[prop_name] = prop_val 200 continue # Do not do recursion 201 202 ret[prop_name] = prop_val 203 204 # Do recursion 205 if recursive: 206 if prop_val_type_name in recursion_types: 207 ret[prop_name] = get_object_properties( 208 prop_val, deep_copy, remove_private, recursive) 209 elif prop_val_type_name == 'list': 210 ret[prop_name] = [] 211 for item in prop_val: 212 if type(item).__name__ in recursion_types: 213 ret[prop_name].append(get_object_properties( 214 item, deep_copy, remove_private, recursive)) 215 else: 216 ret[prop_name].append(item) 217 elif prop_val_type_name == 'dict': 218 ret[prop_name] = {} 219 for key, value in prop_val.items(): 220 if type(value).__name__ in recursion_types: 221 ret[prop_name][key] = get_object_properties( 222 value, deep_copy, remove_private, recursive) 223 else: 224 ret[prop_name][key] = value 225 226 if remove_private: 227 for key in ret.keys(): 228 if key[0] == '_': 229 del ret[key] 230 231 return ret 232 233 234__all__ = ['smartctl_type', 'SMARTCTL_PATH', 235 'all_in', 'any_in', 'get_object_properties']
141def smartctl_type(interface_type: Optional[str]) -> Optional[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 is None: 154 return None 155 156 if interface_type in smartctl_type_dict: 157 return smartctl_type_dict[interface_type] 158 elif 'megaraid,' in interface_type: 159 return interface_type 160 else: 161 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
164def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Optional[Dict[str, Any]]: 165 if obj is None: 166 return None 167 168 if hasattr(obj, '__getstate__'): 169 obj_state = obj.__getstate__() 170 if obj_state is not None: 171 return obj_state 172 173 if not hasattr(obj, '__dict__'): 174 return obj 175 176 prop_names = dir(obj) 177 178 if deep_copy: 179 ret = copy.deepcopy(vars(obj)) 180 else: 181 ret = copy.copy(vars(obj)) 182 183 available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType'] 184 recursion_types = ['object', 185 'NvmeError', 'NvmeSelfTest', 'NvmeAttributes', 186 'AtaAttributes', 'Attribute', 187 ] 188 189 for prop_name in prop_names: 190 prop_val = getattr(obj, prop_name) 191 prop_val_type_name = type(prop_val).__name__ 192 193 if (prop_name[0] != '_'): 194 # Get properties from objects 195 if (prop_val_type_name in available_types) and (prop_name not in ret): 196 # Check if prop_val has __getstate__ method, if so, call it 197 if hasattr(prop_val, '__getstate__'): 198 prop_val_state = prop_val.__getstate__() 199 if prop_val_state is not None: 200 ret[prop_name] = prop_val 201 continue # Do not do recursion 202 203 ret[prop_name] = prop_val 204 205 # Do recursion 206 if recursive: 207 if prop_val_type_name in recursion_types: 208 ret[prop_name] = get_object_properties( 209 prop_val, deep_copy, remove_private, recursive) 210 elif prop_val_type_name == 'list': 211 ret[prop_name] = [] 212 for item in prop_val: 213 if type(item).__name__ in recursion_types: 214 ret[prop_name].append(get_object_properties( 215 item, deep_copy, remove_private, recursive)) 216 else: 217 ret[prop_name].append(item) 218 elif prop_val_type_name == 'dict': 219 ret[prop_name] = {} 220 for key, value in prop_val.items(): 221 if type(value).__name__ in recursion_types: 222 ret[prop_name][key] = get_object_properties( 223 value, deep_copy, remove_private, recursive) 224 else: 225 ret[prop_name][key] = value 226 227 if remove_private: 228 for key in ret.keys(): 229 if key[0] == '_': 230 del ret[key] 231 232 return ret