"""WizardKit: Standard Functions""" # vim: sts=2 sw=2 ts=2 import logging import platform import re import time # STATIC VARIABLES LOG = logging.getLogger(__name__) PLATFORM = platform.system() REGEX_SIZE_STRING = re.compile( r'(?P\-?\d+\.?\d*)\s*(?P[PTGMKB])(?PI?)B?' ) # Exception Classes class GenericAbort(Exception): """Exception used for aborts selected by the user at runtime.""" class GenericError(Exception): """Exception used when the built-in exceptions don't fit.""" class GenericWarning(Exception): """Exception used to highlight non-critical events. NOTE: Avoiding built-in warning exceptions in case the warnings filter has been changed from the default. """ # Functions def bytes_to_string(size, decimals=0, use_binary=True): """Convert size into a human-readable format, returns str. [Doctest] >>> bytes_to_string(10) '10 B' >>> bytes_to_string(10_000_000) '10 MiB' >>> bytes_to_string(10_000_000, decimals=2) '9.54 MiB' >>> bytes_to_string(10_000_000, decimals=2, use_binary=False) '10.00 MB' >>> bytes_to_string(-10_000_000, decimals=4) '-9.5367 MiB' """ LOG.debug( 'size: %s, decimals: %s, use_binary: %s', size, decimals, use_binary, ) scale = 1024 if use_binary else 1000 size = float(size) suffix = ' ' if use_binary else ' ' units = list('KMGTPEZY') # Convert to sensible units while units: if abs(size) < scale: break size /= scale suffix = units.pop(0) size_str = ( f'{size:0.{decimals}f} {suffix}' f'{"iB" if use_binary and suffix.strip() else "B"}' ) # Done LOG.debug('string: %s', size_str) return size_str def sleep(seconds=2): """Simple wrapper for time.sleep.""" time.sleep(seconds) def string_to_bytes(size, assume_binary=False): """Convert human-readable size str to bytes and return an int.""" LOG.debug('size: %s, assume_binary: %s', size, assume_binary) scale = 1000 size = str(size) # Check if given a bare number (no units) try: tmp = float(size) except ValueError: # Ignore and try parsing below pass else: # Return as int assuming input value was in bytes size = int(tmp) LOG.debug('bytes: %s', size) return size # Parse string tmp = REGEX_SIZE_STRING.search(size.upper()) if not tmp: raise ValueError(f'Invalid size string: {size}') # Set scale if tmp.group('binary') or assume_binary: scale = 1024 # Convert to bytes size = float(tmp.group('size')) units = tmp.group('units') if units == 'P': size *= scale ** 5 if units == 'T': size *= scale ** 4 elif units == 'G': size *= scale ** 3 elif units == 'M': size *= scale ** 2 elif units == 'K': size *= scale ** 1 elif units == 'B': size *= scale ** 0 size = int(size) # Done LOG.debug('bytes: %s', size) return size if __name__ == '__main__': print("This file is not meant to be called directly.")