pySMART.utils API documentation

# pySMART.utils

This module contains generic utilities and configuration information for use by the other submodules of the `pySMART` package.

View Source

      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
     86def get_trace_logger(name:str='pySMART') -> TraceLogger:
     87    configure_trace_logging()
     88    return logging.getLogger(name)
     89
     90def log_trace(msg: str, *args, **kwargs):
     91    try:
     92        get_trace_logger().trace(msg, *args, **kwargs)
     93    except Exception as e:
     94        get_trace_logger().debug(f"Exception while logging trace info: {e}")
     95        get_trace_logger().debug(msg, *args, **kwargs)
     96
     97
     98def any_in(search_in, *searched_items):
     99    """
    100    return True if any of searched_items is in search_in otherwise False.
    101    raise
    102    """
    103    assert len(searched_items) > 0
    104    return any(map(lambda one: one in search_in, searched_items))
    105
    106
    107def all_in(search_in, *searched_items):
    108    """
    109    return True if all of searched_items are in search_in otherwise False
    110    does not care about duplicates in searched_items potentially evaluates all of them,
    111    """
    112    assert len(searched_items) > 0
    113    return all(map(lambda one: one in search_in, searched_items))
    114
    115
    116smartctl_type_dict = {
    117    'ata': 'ata',
    118    'csmi': 'ata',
    119    'nvme': 'nvme',
    120    'sas': 'scsi',
    121    'sat': 'sat',
    122    'sata': 'ata',
    123    'scsi': 'scsi',
    124    'atacam': 'atacam',
    125    'sntasmedia': 'sntasmedia'
    126}
    127"""
    128**(dict of str):** Contains actual interface types (ie: sas, csmi) as keys and
    129the corresponding smartctl interface type (ie: scsi, ata) as values.
    130"""
    131
    132SMARTCTL_PATH = which('smartctl')
    133
    134
    135def smartctl_isvalid_type(interface_type: str) -> bool:
    136    """Tests if the interface_type is supported
    137
    138    Args:
    139        interface_type (str): An internal interface_type
    140
    141    Returns:
    142        bool: True if the type is supported, false z
    143    """
    144    if interface_type in smartctl_type_dict:
    145        return True
    146    elif 'megaraid,' in interface_type:
    147        return True
    148    else:
    149        return False
    150
    151
    152def smartctl_type(interface_type: Optional[str]) -> Optional[str]:
    153    """This method basically searchs on smartctl_type_dict to convert from internal
    154       smartctl interface type to an understable type for smartctl. However, further
    155       transforms may be performed for some special interfaces
    156
    157    Args:
    158        interface_type (str): An internal representation of an smartctl interface type
    159
    160    Returns:
    161        str: Returns the corresponding smartctl interface_type that matches with the internal interface representation.
    162             In case it is not supported, None would be returned
    163    """
    164    if interface_type is None:
    165        return None
    166
    167    if interface_type in smartctl_type_dict:
    168        return smartctl_type_dict[interface_type]
    169    elif 'megaraid,' in interface_type:
    170        return interface_type
    171    else:
    172        return None
    173
    174
    175def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Optional[Dict[str, Any]]:
    176    if obj is None:
    177        return None
    178
    179    if not hasattr(obj, '__dict__'):
    180        return obj
    181
    182    prop_names = dir(obj)
    183
    184    if deep_copy:
    185        ret = copy.deepcopy(vars(obj))
    186    else:
    187        ret = copy.copy(vars(obj))
    188
    189    available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType']
    190    recursion_types = ['object',
    191                       'NvmeError', 'NvmeSelfTest', 'NvmeAttributes',
    192                       'AtaAttributes',
    193                       'SCSIAttributes', 'Diagnostics',
    194                       'Attribute', 'TestEntry',
    195                       ]
    196
    197    for prop_name in prop_names:
    198        prop_val = getattr(obj, prop_name)
    199        prop_val_type_name = type(prop_val).__name__
    200
    201        if (prop_name[0] != '_'):
    202            # Get properties from objects
    203            if (prop_val_type_name in available_types) and (prop_name not in ret):
    204                # Check if prop_val has __getstate__ method, if so, call it
    205                # if hasattr(prop_val, '__getstate__'):
    206                #    prop_val_state = prop_val.__getstate__()
    207                #    if prop_val_state is not None:
    208                #        ret[prop_name] = prop_val
    209                #        continue  # Do not do recursion
    210
    211                ret[prop_name] = prop_val
    212
    213            # Do recursion
    214            if recursive:
    215                if prop_val_type_name in recursion_types:
    216                    ret[prop_name] = get_object_properties(
    217                        prop_val, deep_copy, remove_private, recursive)
    218                elif prop_val_type_name == 'list':
    219                    ret[prop_name] = []
    220                    for item in prop_val:
    221                        if type(item).__name__ in recursion_types:
    222                            ret[prop_name].append(get_object_properties(
    223                                item, deep_copy, remove_private, recursive))
    224                        else:
    225                            ret[prop_name].append(item)
    226                elif prop_val_type_name == 'dict':
    227                    ret[prop_name] = {}
    228                    for key, value in prop_val.items():
    229                        if type(value).__name__ in recursion_types:
    230                            ret[prop_name][key] = get_object_properties(
    231                                value, deep_copy, remove_private, recursive)
    232                        else:
    233                            ret[prop_name][key] = value
    234
    235    if remove_private:
    236        for key in ret.keys():
    237            if key[0] == '_':
    238                del ret[key]
    239
    240    return ret
    241
    242
    243__all__ = ['smartctl_type', 'SMARTCTL_PATH',
    244           'all_in', 'any_in', 'get_object_properties']

def smartctl_type(interface_type: Optional[str]) -> Optional[str]: View Source

    153def smartctl_type(interface_type: Optional[str]) -> Optional[str]:
    154    """This method basically searchs on smartctl_type_dict to convert from internal
    155       smartctl interface type to an understable type for smartctl. However, further
    156       transforms may be performed for some special interfaces
    157
    158    Args:
    159        interface_type (str): An internal representation of an smartctl interface type
    160
    161    Returns:
    162        str: Returns the corresponding smartctl interface_type that matches with the internal interface representation.
    163             In case it is not supported, None would be returned
    164    """
    165    if interface_type is None:
    166        return None
    167
    168    if interface_type in smartctl_type_dict:
    169        return smartctl_type_dict[interface_type]
    170    elif 'megaraid,' in interface_type:
    171        return interface_type
    172    else:
    173        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

SMARTCTL_PATH = None
def all_in(search_in, *searched_items): View Source

    108def all_in(search_in, *searched_items):
    109    """
    110    return True if all of searched_items are in search_in otherwise False
    111    does not care about duplicates in searched_items potentially evaluates all of them,
    112    """
    113    assert len(searched_items) > 0
    114    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,

def any_in(search_in, *searched_items): View Source

     99def any_in(search_in, *searched_items):
    100    """
    101    return True if any of searched_items is in search_in otherwise False.
    102    raise
    103    """
    104    assert len(searched_items) > 0
    105    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

def get_object_properties( obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Optional[Dict[str, Any]]: View Source

    176def get_object_properties(obj: Any, deep_copy: bool = True, remove_private: bool = False, recursive: bool = True) -> Optional[Dict[str, Any]]:
    177    if obj is None:
    178        return None
    179
    180    if not hasattr(obj, '__dict__'):
    181        return obj
    182
    183    prop_names = dir(obj)
    184
    185    if deep_copy:
    186        ret = copy.deepcopy(vars(obj))
    187    else:
    188        ret = copy.copy(vars(obj))
    189
    190    available_types = ['dict', 'str', 'int', 'float', 'list', 'NoneType']
    191    recursion_types = ['object',
    192                       'NvmeError', 'NvmeSelfTest', 'NvmeAttributes',
    193                       'AtaAttributes',
    194                       'SCSIAttributes', 'Diagnostics',
    195                       'Attribute', 'TestEntry',
    196                       ]
    197
    198    for prop_name in prop_names:
    199        prop_val = getattr(obj, prop_name)
    200        prop_val_type_name = type(prop_val).__name__
    201
    202        if (prop_name[0] != '_'):
    203            # Get properties from objects
    204            if (prop_val_type_name in available_types) and (prop_name not in ret):
    205                # Check if prop_val has __getstate__ method, if so, call it
    206                # if hasattr(prop_val, '__getstate__'):
    207                #    prop_val_state = prop_val.__getstate__()
    208                #    if prop_val_state is not None:
    209                #        ret[prop_name] = prop_val
    210                #        continue  # Do not do recursion
    211
    212                ret[prop_name] = prop_val
    213
    214            # Do recursion
    215            if recursive:
    216                if prop_val_type_name in recursion_types:
    217                    ret[prop_name] = get_object_properties(
    218                        prop_val, deep_copy, remove_private, recursive)
    219                elif prop_val_type_name == 'list':
    220                    ret[prop_name] = []
    221                    for item in prop_val:
    222                        if type(item).__name__ in recursion_types:
    223                            ret[prop_name].append(get_object_properties(
    224                                item, deep_copy, remove_private, recursive))
    225                        else:
    226                            ret[prop_name].append(item)
    227                elif prop_val_type_name == 'dict':
    228                    ret[prop_name] = {}
    229                    for key, value in prop_val.items():
    230                        if type(value).__name__ in recursion_types:
    231                            ret[prop_name][key] = get_object_properties(
    232                                value, deep_copy, remove_private, recursive)
    233                        else:
    234                            ret[prop_name][key] = value
    235
    236    if remove_private:
    237        for key in ret.keys():
    238            if key[0] == '_':
    239                del ret[key]
    240
    241    return ret