Source code for diskinfo.utils

#
#    Module `utils`: implements utility functions.
#    Peter Sulyok (C) 2022-2026.
#
from typing import List, Tuple, Union
from pyudev import Device


[docs] def _read_file(path, encoding: str = "utf-8") -> str: """Reads the text content of the specified file. The function will hide :py:obj:`IOError` and :py:obj:`FileNotFound` exceptions during the file operations. The result bytes will be read with the specified encoding and stripped. Args: path (str): file path encoding (str): encoding (default is `utf-8`) Returns: str: file content text Example: An example about the use of the function:: >>> from diskinfo import * >>> _read_file("/sys/block/sda/dev") "8:0" """ result: str = "" try: with open(path, "rt", encoding=encoding) as file: result = file.read().strip() except OSError: pass return result
[docs] def size_in_hrf(size_value: int, units: int = 0) -> Tuple[float, str]: """Returns the size in a human-readable form. Args: size_value (int): number of bytes units (int): unit system will be used for the calculation and in the result: - 0 metric units (default) - 1 IEC units - 2 legacy units Read more about `units here <https://en.wikipedia.org/wiki/Byte>`_. Returns: Tuple[float, str]: size in human-readable form, proper unit Raises: ValueError: in case of invalid input parameters (negative size, invalid units) Example: An example about the use of the function:: >>> from diskinfo import * >>> size = 12839709879873 >>> s, u = size_in_hrf(size) >>> print(f"{s:.1f} {u}") 12.8 TB >>> s, u = size_in_hrf(size, units=1) >>> print(f"{s:.1f} {u}") 11.7 TiB """ metric_units: List[str] = ["B", "kB", "MB", "GB", "TB", "PB", "EB"] iec_units: List[str] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"] legacy_units: List[str] = ["B", "KB", "MB", "GB", "TB", "PB", "EB"] divider: int # Divider for the specified unit. hrf_size: float # Result size hfr_unit: str # Result unit index: int = 0 # Unit index # Validate input parameters. if units not in (0, 1, 2): raise ValueError(f"Invalid units parameter ({units}).") if size_value < 0: raise ValueError(f"Invalid size value ({size_value}).") # Set up the proper divider. if units == 0: divider = 1000 elif units == 1: divider = 1024 else: divider = 1024 # Calculate the proper size. hrf_size = size_value number_of_units = len(metric_units) for index in range(number_of_units): if hrf_size < divider: break hrf_size /= divider # Identify the proper unit for the calculated size. if units == 0: hfr_unit = metric_units[index] elif units == 1: hfr_unit = iec_units[index] else: hfr_unit = legacy_units[index] return hrf_size, hfr_unit
[docs] def time_in_hrf(time: int, unit: int = 0, short_format: bool = False) -> Tuple[float, str]: """Returns the amount of time in a human-readable form. Args: time (int): time value unit (int): unit of the input time value - 0 seconds - 1 minutes - 2 hours - 3 days - 4 years short_format (bool): result unit in short format (e.g. `min` instead of `minute`) Returns: Tuple[float, str]: time in human-readable form, proper unit Raises: ValueError: in case of invalid input parameters (negative time, invalid unit) Example: An example about the use of the function:: >>> from diskinfo import * >>> hours = 6517 >>> t, u = time_in_hrf(hours, unit=2) >>> print(f"{t:.1f} {u}") 271.5 day >>> days = 2401 >>> t, u = time_in_hrf(hours, unit=3, short_format=True) >>> print(f"{t:.1f} {u}") 6.6 yr """ time_long_units: List[str] = ["second", "minute", "hour", "day", "year"] time_short_units: List[str] = ["s", "min", "h", "d", "yr"] time_dividers: List[int] = [60, 60, 24, 365, 1] divider: int # Divider for the specified unit. hrf_time: float # Result size hfr_unit: str # Result unit index: int # Unit index # Validate input parameters. if time < 0: raise ValueError(f"Invalid input time value ({time}).") length = len(time_long_units) - 1 if unit < 0 or unit > length: raise ValueError(f"Invalid input unit ({unit}).") # Calculate the proper time. hrf_time = time index = unit while index < length: divider = time_dividers[index] if hrf_time < divider: break hrf_time /= divider index += 1 # Identify the proper unit for the calculated time. if short_format: hfr_unit = time_short_units[index] else: hfr_unit = time_long_units[index] return hrf_time, hfr_unit
def _pyudev_getint(device: Device, key: str, default_value: int = None) -> Union[int, None]: """Returns an integer attribute value of a pyudev.Device() class. The function hides the ValueError exception in case of conversion error and returns the `default_value`. Args: device (pyudev.Device): pyudev.Device() class key (str): attribute key default_value (int): default int value in case of missing attribute Returns: Union[int, None]: int attribute value or None Example: An example about the use of the function:: >>> from diskinfo import * >>> from pyudev import * >>> c = Context() >>> d = Devices.from_name(c, "block", "sda1") >>> print(_pyudev_getint(d, "ID_PART_ENTRY_SIZE")) 20000409264 """ value: str # Read the value for the specified device attribute. value = device.get(key) # Convert the value string to integer if the key exists. if value: try: return int(value) except ValueError: pass # Otherwise return the default value. return default_value def _pyudev_getenc(dev: Device, key: str) -> Union[str, None]: """Returns one of the device attribute key pairs. There are udev attributes key pairs (e.g. `ID_MODEL` and `ID_MODEL_ENC`), where this function first tries to read and decode the `_ENC` version of the key then the simple key if the previous one does not exist. Args: device (pyudev.Device): pyudev.Device() class key (str): attribute key Returns: Union[str, None]: str attribute value or None Example: An example about the use of the function:: >>> from diskinfo import * >>> from pyudev import * >>> c = Context() >>> d = Devices.from_name(c, "block", "sda") >>> print(_pyudev_getenc(d, "ID_MODEL")) Samsung SSD 850 PRO 1TB """ value: str # Read and decode the `_ENC` key. value = dev.get(key + "_ENC") if value: if "\\x20" in value: return value.replace("\\x20", " ").strip() # Read the simple key. return dev.get(key) # End