On Mon, 2015-03-02 at 13:45 -0300, Crístian Viana wrote:
The new function "kimchi.utils.convert_data_size" can be
used to convert
values from different units, e.g. converting 5 GiB to MiB, 1 GiB to B.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
src/kimchi/i18n.py | 2 +
src/kimchi/utils.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+)
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 2af0be6..df5422f 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -267,6 +267,8 @@ messages = {
"KCHUTILS0001E": _("Invalid URI %(uri)s"),
"KCHUTILS0002E": _("Timeout while running command '%(cmd)s'
after %(seconds)s seconds"),
"KCHUTILS0003E": _("Unable to choose a virtual machine name"),
+ "KCHUTILS0004E": _("Invalid data value '%(value)s'"),
+ "KCHUTILS0005E": _("Invalid data unit '%(unit)s'"),
"KCHVMSTOR0002E": _("Invalid storage type. Types supported:
'cdrom', 'disk'"),
"KCHVMSTOR0003E": _("The path '%(value)s' is not a valid
local/remote path for the device"),
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py
index fc5245f..a04d3cf 100644
--- a/src/kimchi/utils.py
+++ b/src/kimchi/utils.py
@@ -388,3 +388,148 @@ def get_unique_file_name(all_names, name):
max_num = max(max_num, int(match.group(re_group_num)))
return u'%s (%d)' % (name, max_num + 1)
+
+
+def convert_data_size(value, src_unit, dst_unit=None):
s/src_unit/src_unit=None
As explained below, both second and third arguments can be None and then
automatically converted to use DEFAULT_UNIT.
I tried "convert_data_size(4)" and got the error:
TypeError: convert_data_size() takes at least 2 arguments (1 given)
+ """Convert a data value from one unit to another
unit
+ (e.g. 'MiB' -> 'GiB').
+
+ The data units supported by this function are made up of one prefix and one
+ suffix, both optional. The valid prefixes are those defined in the SI
+ (i.e. metric system) and those defined by the IEC, and the valid suffixes
+ indicate if the base unit is bit or byte. Take a look at the tables below
+ for the possible values:
+
+ Prefixes:
+
+ ================================== ===================================
+ PREFIX (SI) | DESCRIPTION | VALUE PREFIX (IEC) | DESCRIPTION | VALUE
+ ================================== ===================================
+ k | kilo | 1000 Ki | kibi | 1024
+ ---------------------------------- -----------------------------------
+ M | mega | 1000^2 Mi | mebi | 1024^2
+ ---------------------------------- -----------------------------------
+ G | giga | 1000^3 Gi | gibi | 1024^3
+ ---------------------------------- -----------------------------------
+ T | tera | 1000^4 Ti | tebi | 1024^4
+ ---------------------------------- -----------------------------------
+ P | peta | 1000^5 Pi | pebi | 1024^5
+ ---------------------------------- -----------------------------------
+ E | exa | 1000^6 Ei | exbi | 1024^6
+ ---------------------------------- -----------------------------------
+ Z | zetta | 1000^7 Zi | zebi | 1024^7
+ ---------------------------------- -----------------------------------
+ Y | yotta | 1000^8 Yi | yobi | 1024^8
+ ================================== ===================================
+
+ Suffixes:
+
+ ====================
+ SUFFIX | DESCRIPTION
+ ====================
+ b | bit
+ --------------------
+ B | byte
+ ====================
+
+ See
http://en.wikipedia.org/wiki/Binary_prefix for more details on
+ those units.
+
+ If a wrong prefix or suffix is provided, an error will be raised.
+
+ Examples:
+ convert_data_size(5, 'MiB', 'KiB') -> 5120.0
+ convert_data_size(5, 'MiB', 'M') -> 5.24288
+ convert_data_size(5, 'MiB', 'GiB') -> 0.0048828125
+ convert_data_size(5, 'MiB', 'Tb') -> 4.194304e-05
+ convert_data_size(5, 'MiB') -> 5242880.0
+ convert_data_size(5, 'mib') -> #ERROR# (invalid src_unit)
+
+ Parameters:
+ value -- the value to be converted, in the unit specified by 'src_unit'.
+ this parameter can be of any type which can be cast to float
+ (e.g. int, float, str).
+ src_unit -- the unit of 'value', as described above.
+ if 'src_unit' is empty, the unit 'B' (byte) will be
used.
+ dst_unit -- the unit of the return value.
+ if 'dst_unit' is empty, the unit 'B' (byte) will be
used.
+
+ Return:
+ A float number representing 'value' ('src_unit') converted to
'dst_unit'.
+ """
+ SI_PREFIXES = ['k', 'M', 'G', 'T', 'P',
'E', 'Z', 'Y']
I guess you can add a new line here, as you did between
SUFFIXES_WITH_MULT and DEFAULT_SUFFIX.
+ # The IEC prefixes are the equivalent SI prefixes + 'i'
+ # but, exceptionally, 'k' becomes 'Ki' instead of 'ki'.
+ IEC_PREFIXES = map(lambda p: 'Ki' if p == 'k' else p + 'i',
SI_PREFIXES)
New line here.
+ PREFIXES_BY_BASE = {1000: SI_PREFIXES,
+ 1024: IEC_PREFIXES}
+
+ SUFFIXES_WITH_MULT = {'b': 1,
+ 'B': 8}
+ DEFAULT_SUFFIX = 'B'
+
+ DEFAULT_UNIT = 'B'
+
+ # set the default units
+ if not src_unit:
+ src_unit = DEFAULT_UNIT
+ if not dst_unit:
+ dst_unit = DEFAULT_UNIT
+
+ # set the default suffix
+ if src_unit[-1] not in SUFFIXES_WITH_MULT:
+ src_unit += DEFAULT_SUFFIX
+ if dst_unit[-1] not in SUFFIXES_WITH_MULT:
+ dst_unit += DEFAULT_SUFFIX
+
+ # split prefix and suffix for better parsing
+ src_p = src_unit[:-1]
+ src_s = src_unit[-1]
+ dst_p = dst_unit[:-1]
+ dst_s = dst_unit[-1]
+
+ # validate parameters
+ try:
+ value = float(value)
+ except TypeError:
+ raise InvalidParameter('KCHUTILS0004E', {'value': value})
+ if src_p != '' and src_p not in (SI_PREFIXES + IEC_PREFIXES):
+ raise InvalidParameter('KCHUTILS0005E', {'unit': src_unit})
+ if src_s not in SUFFIXES_WITH_MULT:
+ raise InvalidParameter('KCHUTILS0005E', {'unit': src_unit})
+ if dst_p != '' and dst_p not in (SI_PREFIXES + IEC_PREFIXES):
+ raise InvalidParameter('KCHUTILS0005E', {'unit': dst_unit})
+ if dst_s not in SUFFIXES_WITH_MULT:
+ raise InvalidParameter('KCHUTILS0005E', {'unit': dst_unit})
+
+ # convert 'value' to the most basic unit (bits)...
+ bits = value
+
+ for suffix, mult in SUFFIXES_WITH_MULT.iteritems():
+ if src_s == suffix:
+ bits *= mult
+ break
+
+ if src_p != '':
+ for base, prefixes in PREFIXES_BY_BASE.iteritems():
+ for i, p in enumerate(prefixes):
+ if src_p == p:
+ bits *= base**(i + 1)
+ break
+
+ # ...then convert the value in bits to the destination unit
+ ret = bits
+
+ for suffix, mult in SUFFIXES_WITH_MULT.iteritems():
+ if dst_s == suffix:
+ ret /= float(mult)
+ break
+
+ if dst_p != '':
+ for base, prefixes in PREFIXES_BY_BASE.iteritems():
+ for i, p in enumerate(prefixes):
+ if dst_p == p:
+ ret /= float(base)**(i + 1)
+ break
+
+ return ret
--
Paulo Ricardo Paz Vital <pvital(a)gmail.com>