2016-07-28 03:41:13 +00:00
|
|
|
import re
|
|
|
|
|
2016-05-10 08:00:29 +00:00
|
|
|
BYTE = 1
|
|
|
|
KIBIBYTE = 1024 * BYTE
|
|
|
|
MIBIBYTE = 1024 * KIBIBYTE
|
|
|
|
GIBIBYTE = 1024 * MIBIBYTE
|
|
|
|
TEBIBYTE = 1024 * GIBIBYTE
|
|
|
|
PEBIBYTE = 1024 * TEBIBYTE
|
|
|
|
EXIBYTE = 1024 * PEBIBYTE
|
|
|
|
ZEBIBYTE = 1024 * EXIBYTE
|
|
|
|
YOBIBYTE = 1024 * ZEBIBYTE
|
|
|
|
|
|
|
|
UNIT_STRINGS = {
|
|
|
|
BYTE: 'b',
|
|
|
|
KIBIBYTE: 'KiB',
|
|
|
|
MIBIBYTE: 'MiB',
|
|
|
|
GIBIBYTE: 'GiB',
|
|
|
|
TEBIBYTE: 'TiB',
|
|
|
|
PEBIBYTE: 'PiB',
|
|
|
|
EXIBYTE: 'EiB',
|
|
|
|
ZEBIBYTE: 'ZiB',
|
|
|
|
YOBIBYTE: 'YiB',
|
|
|
|
}
|
2016-07-28 03:41:13 +00:00
|
|
|
UNITS_SORTED = sorted(UNIT_STRINGS.keys(), reverse=True)
|
|
|
|
|
|
|
|
def bytestring(size, force_unit=None):
|
|
|
|
'''
|
|
|
|
Convert a number into a binary-standard string.
|
2016-05-10 08:00:29 +00:00
|
|
|
|
2016-07-28 03:41:13 +00:00
|
|
|
force_unit:
|
|
|
|
If None, an appropriate size unit is chosen automatically.
|
|
|
|
Otherwise, you can provide one of the size constants to force that divisor.
|
|
|
|
'''
|
2016-05-10 08:00:29 +00:00
|
|
|
|
|
|
|
# choose which magnitutde to use as the divisor
|
2016-07-28 03:41:13 +00:00
|
|
|
if force_unit is None:
|
|
|
|
divisor = get_appropriate_divisor(size)
|
2016-05-10 08:00:29 +00:00
|
|
|
else:
|
2016-07-28 03:41:13 +00:00
|
|
|
divisor = force_unit
|
2016-05-10 08:00:29 +00:00
|
|
|
|
2016-07-28 03:41:13 +00:00
|
|
|
size_unit_string = UNIT_STRINGS[divisor]
|
|
|
|
size_string = '%.3f %s' % ((size / divisor), size_unit_string)
|
2016-05-10 08:00:29 +00:00
|
|
|
return size_string
|
|
|
|
|
2016-07-28 03:41:13 +00:00
|
|
|
def get_appropriate_divisor(size):
|
|
|
|
size = abs(size)
|
|
|
|
for unit in UNITS_SORTED:
|
|
|
|
if size >= unit:
|
|
|
|
appropriate_unit = unit
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
appropriate_unit = 1
|
|
|
|
return appropriate_unit
|
|
|
|
|
2016-05-10 08:00:29 +00:00
|
|
|
def parsebytes(string):
|
|
|
|
string = string.lower().replace(' ', '')
|
|
|
|
|
|
|
|
matches = re.findall('((\\.|\\d)+)', string)
|
|
|
|
if len(matches) == 0:
|
|
|
|
raise ValueError('No numbers found')
|
|
|
|
if len(matches) > 1:
|
|
|
|
raise ValueError('Too many numbers found')
|
|
|
|
byte_value = matches[0][0]
|
|
|
|
|
|
|
|
if not string.startswith(byte_value):
|
|
|
|
raise ValueError('Number is not at start of string')
|
|
|
|
|
|
|
|
string = string.replace(byte_value, '')
|
|
|
|
byte_value = float(byte_value)
|
|
|
|
if string == '':
|
|
|
|
return byte_value
|
|
|
|
|
|
|
|
reversed_units = {value.lower():key for (key, value) in UNIT_STRINGS.items()}
|
|
|
|
for (unit_string, multiplier) in reversed_units.items():
|
|
|
|
if string in (unit_string, unit_string[0], unit_string.replace('i', '')):
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise ValueError('Could not determine byte value of %s' % string)
|
|
|
|
|
|
|
|
return byte_value * multiplier
|