From e126547c070fbc080562abb08e16a2c93a8a805d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 12 Apr 2021 14:17:40 +0200 Subject: bpo-34311: Add locale.localize (GH-15275) * Add method localize to the locale module * Update the documentation of the locale module --- Doc/library/locale.rst | 8 +++++++ Lib/locale.py | 16 ++++++++++--- Lib/test/test_locale.py | 28 ++++++++++++++++++++++ .../2019-08-14-13-19-50.bpo-33731.9esS0d.rst | 2 ++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-08-14-13-19-50.bpo-33731.9esS0d.rst diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 0a77be4..60d0c59 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -427,6 +427,14 @@ The :mod:`locale` module defines the following exception and functions: .. versionadded:: 3.5 +.. function:: localize(string, grouping=False, monetary=False) + + Converts a normalized number string into a formatted string following the + :const:`LC_NUMERIC` settings. + + .. versionadded:: 3.10 + + .. function:: atof(string) Converts a string to a floating point number, following the :const:`LC_NUMERIC` diff --git a/Lib/locale.py b/Lib/locale.py index ee841e8..6d4f519 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -185,8 +185,14 @@ def _format(percent, value, grouping=False, monetary=False, *additional): formatted = percent % ((value,) + additional) else: formatted = percent % value + if percent[-1] in 'eEfFgGdiu': + formatted = _localize(formatted, grouping, monetary) + return formatted + +# Transform formatted as locale number according to the locale settings +def _localize(formatted, grouping=False, monetary=False): # floats and decimal ints need special action! - if percent[-1] in 'eEfFgG': + if '.' in formatted: seps = 0 parts = formatted.split('.') if grouping: @@ -196,7 +202,7 @@ def _format(percent, value, grouping=False, monetary=False, *additional): formatted = decimal_point.join(parts) if seps: formatted = _strip_padding(formatted, seps) - elif percent[-1] in 'diu': + else: seps = 0 if grouping: formatted, seps = _group(formatted, monetary=monetary) @@ -267,7 +273,7 @@ def currency(val, symbol=True, grouping=False, international=False): raise ValueError("Currency formatting is not possible using " "the 'C' locale.") - s = _format('%%.%if' % digits, abs(val), grouping, monetary=True) + s = _localize(f'{abs(val):.{digits}f}', grouping, monetary=True) # '<' and '>' are markers if the sign must be inserted between symbol and value s = '<' + s + '>' @@ -323,6 +329,10 @@ def delocalize(string): string = string.replace(dd, '.') return string +def localize(string, grouping=False, monetary=False): + """Parses a string as locale number according to the locale settings.""" + return _localize(string, grouping, monetary) + def atof(string, func=float): "Parses a string as a float according to the locale settings." return func(delocalize(string)) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index 4bb4c55..2c788f2 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -1,3 +1,4 @@ +from decimal import Decimal from test.support import verbose, is_android from test.support.warnings_helper import check_warnings import unittest @@ -636,5 +637,32 @@ class TestfrFRDelocalizeTest(FrFRCookedTest, BaseDelocalizeTest): self._test_atoi('50 000', 50000) +class BaseLocalizeTest(BaseLocalizedTest): + + def _test_localize(self, value, out, grouping=False): + self.assertEqual(locale.localize(value, grouping=grouping), out) + + +class TestEnUSLocalize(EnUSCookedTest, BaseLocalizeTest): + + def test_localize(self): + self._test_localize('50000.00', '50000.00') + self._test_localize( + '{0:.16f}'.format(Decimal('1.15')), '1.1500000000000000') + + +class TestCLocalize(CCookedTest, BaseLocalizeTest): + + def test_localize(self): + self._test_localize('50000.00', '50000.00') + + +class TestfrFRLocalize(FrFRCookedTest, BaseLocalizeTest): + + def test_localize(self): + self._test_localize('50000.00', '50000,00') + self._test_localize('50000.00', '50 000,00', grouping=True) + + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2019-08-14-13-19-50.bpo-33731.9esS0d.rst b/Misc/NEWS.d/next/Library/2019-08-14-13-19-50.bpo-33731.9esS0d.rst new file mode 100644 index 0000000..2fedb06 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-08-14-13-19-50.bpo-33731.9esS0d.rst @@ -0,0 +1,2 @@ +Provide a locale.localize() function, which converts a normalized number string +into a locale format. -- cgit v0.12