Skip to content

Commit 2b5219e

Browse files
committed
bpo-34311: Add locale.localize
This allow to format Decimal without losing precision by using the new format syntax and than localize the result.
1 parent 34a49aa commit 2b5219e

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

Doc/library/locale.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,14 @@ The :mod:`locale` module defines the following exception and functions:
423423
.. versionadded:: 3.5
424424

425425

426+
.. function:: localize(string, grouping=False, monetary=False)
427+
428+
Converts a normalized number string into a formatted string following the
429+
:const:`LC_NUMERIC` settings.
430+
431+
.. versionadded:: 3.9
432+
433+
426434
.. function:: atof(string)
427435

428436
Converts a string to a floating point number, following the :const:`LC_NUMERIC`

Lib/locale.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,14 @@ def _format(percent, value, grouping=False, monetary=False, *additional):
185185
formatted = percent % ((value,) + additional)
186186
else:
187187
formatted = percent % value
188+
if percent[-1] in 'eEfFgGdiu':
189+
formatted = _localize(formatted, grouping, monetary)
190+
return formatted
191+
192+
# Transform formatted as locale number according to the locale settings
193+
def _localize(formatted, grouping=False, monetary=False):
188194
# floats and decimal ints need special action!
189-
if percent[-1] in 'eEfFgG':
195+
if '.' in formatted:
190196
seps = 0
191197
parts = formatted.split('.')
192198
if grouping:
@@ -196,7 +202,7 @@ def _format(percent, value, grouping=False, monetary=False, *additional):
196202
formatted = decimal_point.join(parts)
197203
if seps:
198204
formatted = _strip_padding(formatted, seps)
199-
elif percent[-1] in 'diu':
205+
else:
200206
seps = 0
201207
if grouping:
202208
formatted, seps = _group(formatted, monetary=monetary)
@@ -267,7 +273,7 @@ def currency(val, symbol=True, grouping=False, international=False):
267273
raise ValueError("Currency formatting is not possible using "
268274
"the 'C' locale.")
269275

270-
s = _format('%%.%if' % digits, abs(val), grouping, monetary=True)
276+
s = _localize(f'{abs(val):.{digits}f}', grouping, monetary=True)
271277
# '<' and '>' are markers if the sign must be inserted between symbol and value
272278
s = '<' + s + '>'
273279

@@ -323,6 +329,10 @@ def delocalize(string):
323329
string = string.replace(dd, '.')
324330
return string
325331

332+
def localize(string, grouping=False, monetary=False):
333+
"""Parses a string as locale number according to the locale settings."""
334+
return _localize(string, grouping, monetary)
335+
326336
def atof(string, func=float):
327337
"Parses a string as a float according to the locale settings."
328338
return func(delocalize(string))

Lib/test/test_locale.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from decimal import Decimal
12
from test.support import verbose, is_android, check_warnings
23
import unittest
34
import locale
@@ -629,5 +630,32 @@ def test_atoi(self):
629630
self._test_atoi('50 000', 50000)
630631

631632

633+
class BaseLocalizeTest(BaseLocalizedTest):
634+
635+
def _test_localize(self, value, out, grouping=False):
636+
self.assertEqual(locale.localize(value, grouping=grouping), out)
637+
638+
639+
class TestEnUSLocalize(EnUSCookedTest, BaseLocalizeTest):
640+
641+
def test_localize(self):
642+
self._test_localize('50000.00', '50000.00')
643+
self._test_localize(
644+
'{0:.16f}'.format(Decimal('1.15')), '1.1500000000000000')
645+
646+
647+
class TestCLocalize(CCookedTest, BaseLocalizeTest):
648+
649+
def test_localize(self):
650+
self._test_localize('50000.00', '50000.00')
651+
652+
653+
class TestfrFRLocalize(FrFRCookedTest, BaseLocalizeTest):
654+
655+
def test_localize(self):
656+
self._test_localize('50000.00', '50000,00')
657+
self._test_localize('50000.00', '50 000,00', grouping=True)
658+
659+
632660
if __name__ == '__main__':
633661
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Provide a locale.localize() function, which converts a normalized number string
2+
into a locale format.

0 commit comments

Comments
 (0)