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

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

    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

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

     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,

def any_in(search_in, *searched_items): View Source

    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

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

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