[PATCH 1/2 v3] A function for resolving date format and order
Anne Mulhern
amulhern at redhat.com
Thu Oct 9 17:37:40 UTC 2014
----- 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.
> + 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.
> + # 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.
- mulhern
More information about the anaconda-patches
mailing list