[blivet:master+? 6/9] Rewrite _parseSpec()

mulhern amulhern at redhat.com
Thu Oct 23 17:57:06 UTC 2014


This fixes a bug where most English specifiers would not be parsed
unless the locale was a lot like English; after failing to be parsed
in the English section, they still got their chance to be parsed in
the locale-specific section, and if it was close enough, as it usually
is for me, it would be parsed there.

Add a method, _parseUnits(), which handles the parsing of the units
part of the spec. Abstract this for both translated and non-translated.

The change that introduced the bug was intended to make it so that
"8 M" was interpreted as "8 MiB", not "8 MB". This patch undoes that
change, so "8 M" is interpreted as "8 MB".

Signed-off-by: mulhern <amulhern at redhat.com>
---
 blivet/size.py | 82 ++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 45 insertions(+), 37 deletions(-)

diff --git a/blivet/size.py b/blivet/size.py
index 03ca084..f858c51 100644
--- a/blivet/size.py
+++ b/blivet/size.py
@@ -159,8 +159,42 @@ def _makeSpecs(prefix, abbr, xlate):
 
     return specs
 
+def _parseUnits(units, xlate):
+    """ Parse a unit specification and return corresponding factor.
+
+        :param units: a units specifier
+        :type units: any type of string like object
+        :param bool xlate: if True, units is translated
+
+        :returns: a numeric factor corresponding to the units, if found
+        :rtype: int or NoneType
+    """
+    if xlate:
+        units = units.lower()
+    else:
+        units = _lowerASCII(units)
+
+    for factor, prefix, abbr in [_EMPTY_PREFIX] + _BINARY_PREFIXES + _DECIMAL_PREFIXES:
+        check = _makeSpecs(prefix, abbr, xlate)
+        if units in check:
+            return factor
+
+    return None
+
 def _parseSpec(spec):
-    """ Parse string representation of size. """
+    """ Parse string representation of size.
+
+        :param spec: the specification of a size with, optionally, units
+        :type spec: any type of string like object
+        :returns: numeric value of the specification in bytes
+        :rtype: Decimal
+
+        :raises ValueError: if spec is unparseable
+
+        Tries to parse the spec first as English, if that fails, as
+        a locale specific string.
+    """
+
     if not spec:
         raise ValueError("invalid size specification", spec)
 
@@ -183,58 +217,32 @@ def _parseSpec(spec):
 
     specifier = m.groups()[1]
 
-    # Only attempt to parse as English if all characters are ASCII
+    # First try to parse as English.
     try:
-        # This will raise UnicodeDecodeError if specifier contains non-ascii
-        # characters
         if six.PY2:
-            spec_ascii = specifier.decode("ascii")
-            # Convert back to a str type for use with _lowerASCII
-            spec_ascii = str(spec_ascii)
+            spec_ascii = str(specifier.decode("ascii"))
         else:
-            # This will raise UnicodeEncodeError if specifier contains any non-ascii
-            # in Python3 `bytes` are new Python2 `str`
             spec_ascii = bytes(specifier, 'ascii')
-
-        # Use the ASCII-only lowercase mapping
-        spec_ascii = _lowerASCII(spec_ascii)
     except (UnicodeDecodeError, UnicodeEncodeError):
+        # String contains non-ascii characters, so can not be English.
         pass
     else:
-        if spec_ascii and not spec_ascii.endswith("b"):
-            spec_ascii += "ib"
-
-        if spec_ascii in _BYTES or not spec_ascii:
-            return size
-
-        for factor, prefix, abbr in _PREFIXES:
-            check = _makeSpecs(prefix, abbr, False)
-
-            if spec_ascii in check:
-                return size * factor
+        factor = _parseUnits(spec_ascii, False)
+        if factor is not None:
+            return size * factor
 
-    # No English match found, try localized size specs. Convert the
-    # specifier to a unicode string if it's not one already.
+    # No English match found, try localized size specs.
     if six.PY2:
         if isinstance(specifier, unicode):
             spec_local = specifier
         else:
             spec_local = specifier.decode("utf-8")
     else:
-        # str = unicode in Python3
         spec_local = specifier
 
-    # Use the locale-specific lowercasing
-    spec_local = spec_local.lower()
-
-    if spec_local in _xlated_bytes():
-        return size
-
-    for factor, prefix, abbr in _xlated_prefixes():
-        check  = _makeSpecs(prefix, abbr, True)
-
-        if spec_local in check:
-            return size * factor
+    factor = _parseUnits(spec_local, True)
+    if factor is not None:
+        return size * factor
 
     raise ValueError("invalid size specification", spec)
 
-- 
1.9.3



More information about the anaconda-patches mailing list