WizardKit/scripts/wk/std.py

131 lines
2.9 KiB
Python

"""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<size>\-?\d+\.?\d*)\s*(?P<units>[PTGMKB])(?P<binary>I?)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.")