[PATCH 1/2 v3] A function for resolving date format and order

Vratislav Podzimek vpodzime at redhat.com
Fri Oct 10 07:26:29 UTC 2014


On Thu, 2014-10-09 at 13:37 -0400, Anne Mulhern wrote:
> 
> 
> 
> ----- Original Message -----
> > From: "Vratislav Podzimek" <vpodzime at redhat.com>
> > To: anaconda-patches at lists.fedorahosted.org
> > Sent: Thursday, October 9, 2014 5:41:37 AM
> > Subject: [PATCH 1/2 v3] A function for resolving date format and order
> > 
> > It's not that easy to get right order of date fields (year, month, day) and
> > their formats so we should better have it in a standalone function with
> > tests.
> > 
> > Related: rhbz#1044233
> > Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
> > ---
> >  pyanaconda/localization.py                  | 87
> >  +++++++++++++++++++++++++++++
> >  tests/pyanaconda_tests/localization_test.py | 17 ++++++
> >  2 files changed, 104 insertions(+)
> > 
> > diff --git a/pyanaconda/localization.py b/pyanaconda/localization.py
> > index c95fa1d..2a2ed96 100644
> > --- a/pyanaconda/localization.py
> > +++ b/pyanaconda/localization.py
> > @@ -26,6 +26,7 @@ import re
> >  import langtable
> >  import locale as locale_mod
> >  import glob
> > +from collections import namedtuple
> >  
> >  from pyanaconda import constants
> >  from pyanaconda.iutil import upcase_first_letter
> > @@ -469,3 +470,89 @@ def load_firmware_language(lang):
> >  
> >      log.debug("Using UEFI PlatformLang '%s' ('%s') as our language.", d,
> >      locales[0])
> >      setup_locale(locales[0], lang)
> > +
> > +_DateFieldSpec = namedtuple("DateFieldSpec", ["format", "suffix"])
> > +
> > +def resolve_date_format(year, month, day, fail_safe=True):
> > +    """
> > +    Puts the year, month and day objects in the right order according to the
> > +    currently set locale and provides format specification for each of the
> > +    fields.
> > +
> > +    :param year: any object or value representing year
> > +    :type year: object
> > +    :param month: any object or value representing month
> > +    :type month: object
> > +    :param day: any object or value representing day
> > +    :type day: object
> > +    :param bool fail_safe: whether to fall back to default in case of
> > invalid
> > +                           format or raise exception instead
> > +    :returns: a pair where the first field contains a tuple with the year,
> > month
> > +              and day objects/values put in the right order and where the
> > second
> > +              field contains a tuple with three :class:`_DateFieldSpec`
> > objects
> > +              specifying formats respectively to the first (year, month,
> > day)
> > +              field
> > +    :rtype: tuple
> > +    :raise ValueError: in case currently set locale has unsupported date
> > +                       format and fail_safe is set to False
> > +
> > +    """
> > +
> > +    fail_safe_default = "%Y-%m-%d"
> > +
> 
> This looks like a should-be-capitalized constant.
Fixing locally.

> 
> > +    def order_terms_formats(fmt_str):
> > +        # see date (1), 'O' (not '0') is a mystery, 'E' is Buddhist
> > calendar, '(.*)'
> > +        # is an arbitrary suffix
> > +        field_spec_re = re.compile(r'([-_0OE^#]*)([yYmbBde])(.*)')
> > +
> > +        ordered_terms = []
> > +        ordered_formats = []
> 
> Please move these down to above the for loop that is their first use.
Fixing locally.

> 
> > +        # see date (1)
> > +        fmt_str = fmt_str.replace("%F", "%Y-%m-%d")
> > +
> > +        # e.g. "%d.%m.%Y" -> ['d.', 'm.', 'Y']
> > +        fields = fmt_str.split("%")[1:]
> > +
> > +        for field in fields:
> > +            match = field_spec_re.match(field)
> > +            if not match:
> > +                # ignore fields we are not interested in (like %A for
> > weekday name, etc.)
> > +                continue
> > +
> > +            prefix, item, suffix = match.groups()
> > +            if item in ("d", "e"):
> > +                # "e" is the same as "_d"
> > +                ordered_terms.append(day)
> > +            elif item in ("Y", "y"):
> > +                # 4-digit year, 2-digit year
> > +                ordered_terms.append(year)
> > +            elif item in ("m", "b", "B"):
> > +                # month number, short month name, long month name
> > +                ordered_terms.append(month)
> > +
> > +            # "%" + prefix + item gives a format for date/time formatting
> > functions
> > +            ordered_formats.append(_DateFieldSpec("%" + prefix + item,
> > suffix.strip()))
> > +
> > +        if len(ordered_terms) != 3 or len(ordered_formats) != 3:
> > +            raise ValueError("Not all fields successfully identified in the
> > format '%s'" % fmt_str)
> > +
> > +        return (tuple(ordered_terms), tuple(ordered_formats))
> > +
> > +    fmt_str = locale_mod.nl_langinfo(locale_mod.D_FMT)
> > +
> > +    if not fmt_str or "%" not in fmt_str:
> > +        if fail_safe:
> > +            # use some sane default
> > +            fmt_str = fail_safe_default
> > +        else:
> > +            raise ValueError("Invalid date format string for current locale:
> > '%s'" % fmt_str)
> > +
> > +    try:
> > +        return order_terms_formats(fmt_str)
> > +    except ValueError:
> > +        if not fail_safe:
> > +            raise
> > +        else:
> > +            # if this call fails too, something is going terribly wrong and
> > we
> > +            # should be informed about it
> > +            return order_terms_formats(fail_safe_default)
> > diff --git a/tests/pyanaconda_tests/localization_test.py
> > b/tests/pyanaconda_tests/localization_test.py
> > index 00ff31d..521fb4a 100644
> > --- a/tests/pyanaconda_tests/localization_test.py
> > +++ b/tests/pyanaconda_tests/localization_test.py
> > @@ -19,6 +19,8 @@
> >  #
> >  
> >  from pyanaconda import localization
> > +from pyanaconda.iutil import execReadlines
> > +import locale as locale_mod
> >  import unittest
> >  
> >  class ParsingTests(unittest.TestCase):
> > @@ -139,3 +141,18 @@ class LangcodeLocaleMatchingTests(unittest.TestCase):
> >          # no matches
> >          self.assertIsNone(localization.find_best_locale_match("pt_BR",
> >          ["en_BR", "en"]))
> >          self.assertIsNone(localization.find_best_locale_match("cs_CZ.UTF-8",
> >          ["en", "en.UTF-8"]))
> > +
> > +    def resolve_date_format_test(self):
> > +        """All locales' date formats should be properly resolved."""
> > +
> > +        locales = (line.strip() for line in execReadlines("locale", ["-a"]))
> > +        for locale in locales:
> > +            try:
> > +                locale_mod.setlocale(locale_mod.LC_ALL, locale)
> > +            except locale_mod.Error:
> > +                # cannot set locale (a bug in the locale module?)
> > +                continue
> > +
> > +            (order, formats) = localization.resolve_date_format(1, 2, 3,
> > fail_safe=False)
> > +            for i in (1, 2, 3):
> > +                self.assertIn(i, order)
> > --
> > 1.9.3
> > 
> > _______________________________________________
> > anaconda-patches mailing list
> > anaconda-patches at lists.fedorahosted.org
> > https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
> > 
> 
> Other than inline comments above, ack.
Nice, thanks!

-- 
Vratislav Podzimek

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



More information about the anaconda-patches mailing list