136 lines
3 KiB
Python
136 lines
3 KiB
Python
"""WizardKit: Standard Functions"""
|
|
# vim: sts=2 sw=2 ts=2
|
|
|
|
import logging
|
|
import platform
|
|
import re
|
|
import time
|
|
|
|
from typing import Union
|
|
|
|
|
|
# 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: Union[float, int],
|
|
decimals: int = 0,
|
|
use_binary: bool = True) -> str:
|
|
"""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: Union[int, float] = 2) -> None:
|
|
"""Simple wrapper for time.sleep."""
|
|
time.sleep(seconds)
|
|
|
|
|
|
def string_to_bytes(size: Union[float, int, str], assume_binary: bool = False) -> int:
|
|
"""Convert human-readable size 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.")
|