[PATCH] Accept both English and localized sizes in Size specs.

Vratislav Podzimek vpodzime at redhat.com
Wed Jan 22 08:45:47 UTC 2014


On Tue, 2014-01-21 at 14:47 -0500, David Shea wrote:
> _parseSpec will accept both English and localized size specs, either
> with a period or a localized radix character. Size.humanReadable will
> always return the localized version of a Size.
> ---
>  blivet/size.py     | 114 +++++++++++++++++++++++++++++++++++++++++------------
>  tests/size_test.py |  44 +++++++++++++++++++++
>  2 files changed, 132 insertions(+), 26 deletions(-)
> 
> diff --git a/blivet/size.py b/blivet/size.py
> index 189313c..dd0fc7f 100644
> --- a/blivet/size.py
> +++ b/blivet/size.py
> @@ -20,6 +20,8 @@
>  # Red Hat Author(s): David Cantrell <dcantrell at redhat.com>
>  
>  import re
> +import string
> +import locale
>  from collections import namedtuple
>  
>  from decimal import Decimal
> @@ -58,17 +60,39 @@ _binaryPrefix = [_Prefix(1024, N_("kibi"), N_("Ki")),
>  _bytes = [N_('B'), N_('b'), N_('byte'), N_('bytes')]
>  _prefixes = _binaryPrefix + _decimalPrefix
>  
> -def _makeSpecs(prefix, abbr):
> +# Translated versions of the byte and prefix arrays
> +# All strings are decoded as utf-8 so that locale-specific upper/lower functions work
> +def _xlated_bytes():
> +    return [_(b).decode("utf-8") for b in _bytes]
> +
> +def _xlated_prefixes():
> +    return [_Prefix(p.factor, _(p.prefix).decode("utf-8"), _(p.abbr).decode("utf-8")) \
> +            for p in _prefixes]
> +
> +_ASCIIlower_table = string.maketrans(string.ascii_uppercase, string.ascii_lowercase)
> +def _lowerASCII(s):
> +    """Convert a string to lowercase using only ASCII character definitions."""
> +    return string.translate(s, _ASCIIlower_table)
> +
> +def _makeSpecs(prefix, abbr, xlate):
>      """ Internal method used to generate a list of specifiers. """
>      specs = []
>  
>      if prefix:
> -        specs.append(prefix.lower() + _("byte"))
> -        specs.append(prefix.lower() + _("bytes"))
> +        if xlate:
> +            specs.append(prefix.lower() + _("byte").decode("utf-8"))
> +            specs.append(prefix.lower() + _("bytes").decode("utf-8"))
> +        else:
> +            specs.append(_lowerASCII(prefix) + "byte")
> +            specs.append(_lowerASCII(prefix) + "bytes")
>  
>      if abbr:
> -        specs.append(abbr.lower() + _("b"))
> -        specs.append(abbr.lower())
> +        if xlate:
> +            specs.append(abbr.lower() + _("b").decode("utf-8"))
> +            specs.append(abbr.lower())
> +        else:
> +            specs.append(_lowerASCII(abbr) + "b")
> +            specs.append(_lowerASCII(abbr))
>  
>      return specs
>  
> @@ -77,11 +101,15 @@ def _parseSpec(spec):
>      if not spec:
>          raise ValueError("invalid size specification", spec)
>  
> -    # This regex isn't ideal, since \w matches both letters and digits,
> -    # but python doesn't provide a means to match only Unicode letters.
> -    # Probably the worst that will come of it is that bad specs will fail
> -    # more confusingly.
> -    m = re.match(r'(-?\s*[0-9.]+)\s*(\w*)$', spec.decode("utf-8").strip(), flags=re.UNICODE)
> +    # Replace the localized radix character with a .
> +    radix = locale.nl_langinfo(locale.RADIXCHAR)
> +    if radix != '.':
> +        spec = spec.replace(radix, '.')
> +
> +    # Match the string using only digit/space/not-space, since the
> +    # string might be non-English and contain non-letter characters
> +    # that Python doesn't understand as parts of words.
> +    m = re.match(r'(-?\s*[0-9.]+)\s*([^\s]*)$', spec.strip())
>      if not m:
>          raise ValueError("invalid size specification", spec)
>  
> @@ -90,14 +118,45 @@ def _parseSpec(spec):
>      except InvalidOperation:
>          raise ValueError("invalid size specification", spec)
>  
> -    specifier = m.groups()[1].lower()
> -    bytes_xlated = [_(b) for b in _bytes]
> -    if not specifier or specifier in bytes_xlated:
> +    # Only attempt to parse as English if all characters are ASCII
> +    try:
> +        specifier = m.groups()[1]
> +
> +        # This will raise UnicodeDecodeError if specifier contains non-ascii
> +        # characters
> +        specifier = specifier.decode("ascii")
> +
> +        # Convert back to a str type to match the _bytes and _prefixes arrays
> +        specifier = str(specifier)
Any reason for assigning the value returned by specifier.decode("ascii")
to the specifier variable and then restoring it back? You could just
call the decode method without assigning the result anywhere or, if
pylint dies by a terrible death on that, assign it to a different,
temporary variable.

Otherwise this looks much better than the previous version to me.
Thanks, ACK!

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list