mirror of
https://github.com/python/cpython.git
synced 2025-10-12 01:43:12 +00:00
bpo-10379: add 'monetary' to format_string, deprecate format
Add the 'monetary' parameter to format_string so that all uses of format can be converted to format_string. Adjust the documentation accordingly, and add a deprecation warning when format is used.
This commit is contained in:
parent
c8fa45bac2
commit
1cf93a76c2
6 changed files with 83 additions and 54 deletions
|
@ -352,7 +352,7 @@ The :mod:`locale` module defines the following exception and functions:
|
||||||
sequence of strings.
|
sequence of strings.
|
||||||
|
|
||||||
|
|
||||||
.. function:: format(format, val, grouping=False, monetary=False)
|
.. function:: format_string(format, val, grouping=False, monetary=False)
|
||||||
|
|
||||||
Formats a number *val* according to the current :const:`LC_NUMERIC` setting.
|
Formats a number *val* according to the current :const:`LC_NUMERIC` setting.
|
||||||
The format follows the conventions of the ``%`` operator. For floating point
|
The format follows the conventions of the ``%`` operator. For floating point
|
||||||
|
@ -362,15 +362,23 @@ The :mod:`locale` module defines the following exception and functions:
|
||||||
If *monetary* is true, the conversion uses monetary thousands separator and
|
If *monetary* is true, the conversion uses monetary thousands separator and
|
||||||
grouping strings.
|
grouping strings.
|
||||||
|
|
||||||
Please note that this function will only work for exactly one %char specifier.
|
|
||||||
For whole format strings, use :func:`format_string`.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: format_string(format, val, grouping=False)
|
|
||||||
|
|
||||||
Processes formatting specifiers as in ``format % val``, but takes the current
|
Processes formatting specifiers as in ``format % val``, but takes the current
|
||||||
locale settings into account.
|
locale settings into account.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.7
|
||||||
|
The *monetary* keyword parameter was added.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: format(format, val, grouping=False, monetary=False)
|
||||||
|
|
||||||
|
Please note that this function works like format_string but will only work
|
||||||
|
for exactly one %char specifier.
|
||||||
|
|
||||||
|
For whole format strings, use :func:`format_string`.
|
||||||
|
|
||||||
|
.. deprecated:: 3.7
|
||||||
|
Use :meth:`format_string` instead
|
||||||
|
|
||||||
|
|
||||||
.. function:: currency(val, symbol=True, grouping=False, international=False)
|
.. function:: currency(val, symbol=True, grouping=False, international=False)
|
||||||
|
|
||||||
|
|
|
@ -76,16 +76,14 @@ Other Language Changes
|
||||||
======================
|
======================
|
||||||
|
|
||||||
* More than 255 arguments can now be passed to a function, and a function can
|
* More than 255 arguments can now be passed to a function, and a function can
|
||||||
now have more than 255 parameters.
|
now have more than 255 parameters. (Contributed by Serhiy Storchaka in
|
||||||
(Contributed by Serhiy Storchaka in :issue:`12844` and :issue:`18896`.)
|
:issue:`12844` and :issue:`18896`.)
|
||||||
|
|
||||||
* :meth:`bytes.fromhex` and :meth:`bytearray.fromhex` now ignore all ASCII
|
* :meth:`bytes.fromhex` and :meth:`bytearray.fromhex` now ignore all ASCII
|
||||||
whitespace, not only spaces.
|
whitespace, not only spaces. (Contributed by Robert Xiao in :issue:`28927`.)
|
||||||
(Contributed by Robert Xiao in :issue:`28927`.)
|
|
||||||
|
|
||||||
* :exc:`ImportError` now displays module name and module ``__file__`` path when
|
* :exc:`ImportError` now displays module name and module ``__file__`` path when
|
||||||
``from ... import ...`` fails.
|
``from ... import ...`` fails. (Contributed by Matthias Bussonnier in :issue:`29546`.)
|
||||||
(Contributed by Matthias Bussonnier in :issue:`29546`.)
|
|
||||||
|
|
||||||
|
|
||||||
New Modules
|
New Modules
|
||||||
|
@ -97,25 +95,32 @@ New Modules
|
||||||
Improved Modules
|
Improved Modules
|
||||||
================
|
================
|
||||||
|
|
||||||
|
locale
|
||||||
|
------
|
||||||
|
|
||||||
|
Added another argument *monetary* in :meth:`format_string` of :mod:`locale`.
|
||||||
|
If *monetary* is true, the conversion uses monetary thousands separator and
|
||||||
|
grouping strings. (Contributed by Garvit in :issue:`10379`.)
|
||||||
|
|
||||||
os
|
os
|
||||||
--
|
--
|
||||||
|
|
||||||
Added support for :class:`bytes` paths in :func:`~os.fwalk`.
|
Added support for :class:`bytes` paths in :func:`~os.fwalk`. (Contributed by
|
||||||
(Contributed by Serhiy Storchaka in :issue:`28682`.)
|
Serhiy Storchaka in :issue:`28682`.)
|
||||||
|
|
||||||
unittest.mock
|
unittest.mock
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The :const:`~unittest.mock.sentinel` attributes now preserve their identity
|
The :const:`~unittest.mock.sentinel` attributes now preserve their identity
|
||||||
when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`.
|
when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`. (Contributed by
|
||||||
(Contributed by Serhiy Storchaka in :issue:`20804`.)
|
Serhiy Storchaka in :issue:`20804`.)
|
||||||
|
|
||||||
xmlrpc.server
|
xmlrpc.server
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
:meth:`register_function` of :class:`xmlrpc.server.SimpleXMLRPCDispatcher` and
|
:meth:`register_function` of :class:`xmlrpc.server.SimpleXMLRPCDispatcher` and
|
||||||
its subclasses can be used as a decorator.
|
its subclasses can be used as a decorator. (Contributed by Xiang Zhang in
|
||||||
(Contributed by Xiang Zhang in :issue:`7769`.)
|
:issue:`7769`.)
|
||||||
|
|
||||||
urllib.parse
|
urllib.parse
|
||||||
------------
|
------------
|
||||||
|
@ -130,13 +135,13 @@ Optimizations
|
||||||
|
|
||||||
* Added two new opcodes: ``LOAD_METHOD`` and ``CALL_METHOD`` to avoid
|
* Added two new opcodes: ``LOAD_METHOD`` and ``CALL_METHOD`` to avoid
|
||||||
instantiation of bound method objects for method calls, which results
|
instantiation of bound method objects for method calls, which results
|
||||||
in method calls being faster up to 20%.
|
in method calls being faster up to 20%. (Contributed by Yury Selivanov and
|
||||||
(Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.)
|
INADA Naoki in :issue:`26110`.)
|
||||||
|
|
||||||
* Fast implementation from standard C library is now used for functions
|
* Fast implementation from standard C library is now used for functions
|
||||||
:func:`~math.tgamma`, :func:`~math.lgamma`, :func:`~math.erf` and
|
:func:`~math.tgamma`, :func:`~math.lgamma`, :func:`~math.erf` and
|
||||||
:func:`~math.erfc` in the :mod:`math` module.
|
:func:`~math.erfc` in the :mod:`math` module. (Contributed by Serhiy
|
||||||
(Contributed by Serhiy Storchaka in :issue:`26121`.)
|
Storchaka in :issue:`26121`.)
|
||||||
|
|
||||||
|
|
||||||
Build and C API Changes
|
Build and C API Changes
|
||||||
|
@ -154,8 +159,8 @@ Build and C API Changes
|
||||||
``char *``. (Contributed by Serhiy Storchaka in :issue:`28761`.)
|
``char *``. (Contributed by Serhiy Storchaka in :issue:`28761`.)
|
||||||
|
|
||||||
* The result of :c:func:`PyUnicode_AsUTF8AndSize` and :c:func:`PyUnicode_AsUTF8`
|
* The result of :c:func:`PyUnicode_AsUTF8AndSize` and :c:func:`PyUnicode_AsUTF8`
|
||||||
is now of type ``const char *`` rather of ``char *``.
|
is now of type ``const char *`` rather of ``char *``. (Contributed by Serhiy
|
||||||
(Contributed by Serhiy Storchaka in :issue:`28769`.)
|
Storchaka in :issue:`28769`.)
|
||||||
|
|
||||||
* Added functions :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices`.
|
* Added functions :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices`.
|
||||||
(Contributed by Serhiy Storchaka in :issue:`27867`.)
|
(Contributed by Serhiy Storchaka in :issue:`27867`.)
|
||||||
|
@ -169,6 +174,9 @@ Deprecated
|
||||||
``0x03050400`` and ``0x03060000`` (not including) or ``0x03060100`` or
|
``0x03050400`` and ``0x03060000`` (not including) or ``0x03060100`` or
|
||||||
higher. (Contributed by Serhiy Storchaka in :issue:`27867`.)
|
higher. (Contributed by Serhiy Storchaka in :issue:`27867`.)
|
||||||
|
|
||||||
|
- Deprecated :meth:`format` from :mod:`locale`, use the :meth:`format_string`
|
||||||
|
instead. (Contributed by Garvit in :issue:`10379`.)
|
||||||
|
|
||||||
- Methods
|
- Methods
|
||||||
:meth:`MetaPathFinder.find_module() <importlib.abc.MetaPathFinder.find_module>`
|
:meth:`MetaPathFinder.find_module() <importlib.abc.MetaPathFinder.find_module>`
|
||||||
(replaced by
|
(replaced by
|
||||||
|
@ -181,8 +189,8 @@ Deprecated
|
||||||
by Matthias Bussonnier in :issue:`29576`)
|
by Matthias Bussonnier in :issue:`29576`)
|
||||||
|
|
||||||
- Using non-integer value for selecting a plural form in :mod:`gettext` is
|
- Using non-integer value for selecting a plural form in :mod:`gettext` is
|
||||||
now deprecated. It never correctly worked.
|
now deprecated. It never correctly worked. (Contributed by Serhiy Storchaka
|
||||||
(Contributed by Serhiy Storchaka in :issue:`28692`.)
|
in :issue:`28692`.)
|
||||||
|
|
||||||
|
|
||||||
Changes in the C API
|
Changes in the C API
|
||||||
|
@ -229,8 +237,8 @@ Changes in the Python API
|
||||||
|
|
||||||
* A format string argument for :meth:`string.Formatter.format`
|
* A format string argument for :meth:`string.Formatter.format`
|
||||||
is now :ref:`positional-only <positional-only_parameter>`.
|
is now :ref:`positional-only <positional-only_parameter>`.
|
||||||
Passing it as a keyword argument was deprecated in Python 3.5.
|
Passing it as a keyword argument was deprecated in Python 3.5. (Contributed
|
||||||
(Contributed by Serhiy Storchaka in :issue:`29193`.)
|
by Serhiy Storchaka in :issue:`29193`.)
|
||||||
|
|
||||||
* Attributes :attr:`~http.cookies.Morsel.key`,
|
* Attributes :attr:`~http.cookies.Morsel.key`,
|
||||||
:attr:`~http.cookies.Morsel.value` and
|
:attr:`~http.cookies.Morsel.value` and
|
||||||
|
@ -244,8 +252,8 @@ Changes in the Python API
|
||||||
``ClassDef`` AST nodes now have a new ``docstring`` field.
|
``ClassDef`` AST nodes now have a new ``docstring`` field.
|
||||||
The first statement in their body is not considered as a docstring
|
The first statement in their body is not considered as a docstring
|
||||||
anymore. ``co_firstlineno`` and ``co_lnotab`` of code object for class
|
anymore. ``co_firstlineno`` and ``co_lnotab`` of code object for class
|
||||||
and module are affected by this change.
|
and module are affected by this change. (Contributed by INADA Naoki and
|
||||||
(Contributed by INADA Naoki and Eugene Toder in :issue:`29463`.)
|
Eugene Toder in :issue:`29463`.)
|
||||||
|
|
||||||
* The *mode* argument of :func:`os.makedirs` no longer affects the file
|
* The *mode* argument of :func:`os.makedirs` no longer affects the file
|
||||||
permission bits of newly-created intermediate-level directories.
|
permission bits of newly-created intermediate-level directories.
|
||||||
|
|
|
@ -17,6 +17,7 @@ import re
|
||||||
import collections
|
import collections
|
||||||
from builtins import str as _builtin_str
|
from builtins import str as _builtin_str
|
||||||
import functools
|
import functools
|
||||||
|
import warnings
|
||||||
|
|
||||||
# Try importing the _locale module.
|
# Try importing the _locale module.
|
||||||
#
|
#
|
||||||
|
@ -180,19 +181,6 @@ def _strip_padding(s, amount):
|
||||||
_percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
|
_percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
|
||||||
r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
|
r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
|
||||||
|
|
||||||
def format(percent, value, grouping=False, monetary=False, *additional):
|
|
||||||
"""Returns the locale-aware substitution of a %? specifier
|
|
||||||
(percent).
|
|
||||||
|
|
||||||
additional is for format strings which contain one or more
|
|
||||||
'*' modifiers."""
|
|
||||||
# this is only for one-percent-specifier strings and this should be checked
|
|
||||||
match = _percent_re.match(percent)
|
|
||||||
if not match or len(match.group())!= len(percent):
|
|
||||||
raise ValueError(("format() must be given exactly one %%char "
|
|
||||||
"format specifier, %s not valid") % repr(percent))
|
|
||||||
return _format(percent, value, grouping, monetary, *additional)
|
|
||||||
|
|
||||||
def _format(percent, value, grouping=False, monetary=False, *additional):
|
def _format(percent, value, grouping=False, monetary=False, *additional):
|
||||||
if additional:
|
if additional:
|
||||||
formatted = percent % ((value,) + additional)
|
formatted = percent % ((value,) + additional)
|
||||||
|
@ -217,10 +205,13 @@ def _format(percent, value, grouping=False, monetary=False, *additional):
|
||||||
formatted = _strip_padding(formatted, seps)
|
formatted = _strip_padding(formatted, seps)
|
||||||
return formatted
|
return formatted
|
||||||
|
|
||||||
def format_string(f, val, grouping=False):
|
def format_string(f, val, grouping=False, monetary=False):
|
||||||
"""Formats a string in the same way that the % formatting would use,
|
"""Formats a string in the same way that the % formatting would use,
|
||||||
but takes the current locale into account.
|
but takes the current locale into account.
|
||||||
Grouping is applied if the third parameter is true."""
|
|
||||||
|
Grouping is applied if the third parameter is true.
|
||||||
|
Conversion uses monetary thousands separator and grouping strings if
|
||||||
|
forth parameter monetary is true."""
|
||||||
percents = list(_percent_re.finditer(f))
|
percents = list(_percent_re.finditer(f))
|
||||||
new_f = _percent_re.sub('%s', f)
|
new_f = _percent_re.sub('%s', f)
|
||||||
|
|
||||||
|
@ -230,7 +221,7 @@ def format_string(f, val, grouping=False):
|
||||||
if perc.group()[-1]=='%':
|
if perc.group()[-1]=='%':
|
||||||
new_val.append('%')
|
new_val.append('%')
|
||||||
else:
|
else:
|
||||||
new_val.append(format(perc.group(), val, grouping))
|
new_val.append(_format(perc.group(), val, grouping, monetary))
|
||||||
else:
|
else:
|
||||||
if not isinstance(val, tuple):
|
if not isinstance(val, tuple):
|
||||||
val = (val,)
|
val = (val,)
|
||||||
|
@ -244,13 +235,27 @@ def format_string(f, val, grouping=False):
|
||||||
new_val.append(_format(perc.group(),
|
new_val.append(_format(perc.group(),
|
||||||
val[i],
|
val[i],
|
||||||
grouping,
|
grouping,
|
||||||
False,
|
monetary,
|
||||||
*val[i+1:i+1+starcount]))
|
*val[i+1:i+1+starcount]))
|
||||||
i += (1 + starcount)
|
i += (1 + starcount)
|
||||||
val = tuple(new_val)
|
val = tuple(new_val)
|
||||||
|
|
||||||
return new_f % val
|
return new_f % val
|
||||||
|
|
||||||
|
def format(percent, value, grouping=False, monetary=False, *additional):
|
||||||
|
"""Deprecated, use format_string instead."""
|
||||||
|
warnings.warn(
|
||||||
|
"This method will be removed in a future version of Python."
|
||||||
|
"Use 'locale.format_string()' instead.",
|
||||||
|
DeprecationWarning, stacklevel=2
|
||||||
|
)
|
||||||
|
|
||||||
|
match = _percent_re.match(percent)
|
||||||
|
if not match or len(match.group())!= len(percent):
|
||||||
|
raise ValueError(("format() must be given exactly one %%char "
|
||||||
|
"format specifier, %s not valid") % repr(percent))
|
||||||
|
return _format(percent, value, grouping, monetary, *additional)
|
||||||
|
|
||||||
def currency(val, symbol=True, grouping=False, international=False):
|
def currency(val, symbol=True, grouping=False, international=False):
|
||||||
"""Formats val according to the currency settings
|
"""Formats val according to the currency settings
|
||||||
in the current locale."""
|
in the current locale."""
|
||||||
|
@ -262,7 +267,7 @@ def currency(val, symbol=True, grouping=False, international=False):
|
||||||
raise ValueError("Currency formatting is not possible using "
|
raise ValueError("Currency formatting is not possible using "
|
||||||
"the 'C' locale.")
|
"the 'C' locale.")
|
||||||
|
|
||||||
s = format('%%.%if' % digits, abs(val), grouping, monetary=True)
|
s = _format('%%.%if' % digits, abs(val), grouping, monetary=True)
|
||||||
# '<' and '>' are markers if the sign must be inserted between symbol and value
|
# '<' and '>' are markers if the sign must be inserted between symbol and value
|
||||||
s = '<' + s + '>'
|
s = '<' + s + '>'
|
||||||
|
|
||||||
|
@ -298,7 +303,7 @@ def currency(val, symbol=True, grouping=False, international=False):
|
||||||
|
|
||||||
def str(val):
|
def str(val):
|
||||||
"""Convert float to string, taking the locale into account."""
|
"""Convert float to string, taking the locale into account."""
|
||||||
return format("%.12g", val)
|
return _format("%.12g", val)
|
||||||
|
|
||||||
def delocalize(string):
|
def delocalize(string):
|
||||||
"Parses a string as a normalized number according to the locale settings."
|
"Parses a string as a normalized number according to the locale settings."
|
||||||
|
@ -327,7 +332,7 @@ def atoi(string):
|
||||||
def _test():
|
def _test():
|
||||||
setlocale(LC_ALL, "")
|
setlocale(LC_ALL, "")
|
||||||
#do grouping
|
#do grouping
|
||||||
s1 = format("%d", 123456789,1)
|
s1 = format_string("%d", 123456789,1)
|
||||||
print(s1, "is", atoi(s1))
|
print(s1, "is", atoi(s1))
|
||||||
#standard formatting
|
#standard formatting
|
||||||
s1 = str(3.14)
|
s1 = str(3.14)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import unittest
|
||||||
import locale
|
import locale
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
import codecs
|
||||||
|
import warnings
|
||||||
|
|
||||||
class BaseLocalizedTest(unittest.TestCase):
|
class BaseLocalizedTest(unittest.TestCase):
|
||||||
#
|
#
|
||||||
|
@ -197,6 +198,10 @@ class EnUSNumberFormatting(BaseFormattingTest):
|
||||||
self._test_format("%+10.f", -4200, grouping=0, out='-4200'.rjust(10))
|
self._test_format("%+10.f", -4200, grouping=0, out='-4200'.rjust(10))
|
||||||
self._test_format("%-10.f", 4200, grouping=0, out='4200'.ljust(10))
|
self._test_format("%-10.f", 4200, grouping=0, out='4200'.ljust(10))
|
||||||
|
|
||||||
|
def test_format_deprecation(self):
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
locale.format("%-10.f", 4200, grouping=True)
|
||||||
|
|
||||||
def test_complex_formatting(self):
|
def test_complex_formatting(self):
|
||||||
# Spaces in formatting string
|
# Spaces in formatting string
|
||||||
self._test_format_string("One million is %i", 1000000, grouping=1,
|
self._test_format_string("One million is %i", 1000000, grouping=1,
|
||||||
|
|
|
@ -381,8 +381,8 @@ class TypesTests(unittest.TestCase):
|
||||||
|
|
||||||
for i in range(-10, 10):
|
for i in range(-10, 10):
|
||||||
x = 1234567890.0 * (10.0 ** i)
|
x = 1234567890.0 * (10.0 ** i)
|
||||||
self.assertEqual(locale.format('%g', x, grouping=True), format(x, 'n'))
|
self.assertEqual(locale.format_string('%g', x, grouping=True), format(x, 'n'))
|
||||||
self.assertEqual(locale.format('%.10g', x, grouping=True), format(x, '.10n'))
|
self.assertEqual(locale.format_string('%.10g', x, grouping=True), format(x, '.10n'))
|
||||||
|
|
||||||
@run_with_locale('LC_NUMERIC', 'en_US.UTF8')
|
@run_with_locale('LC_NUMERIC', 'en_US.UTF8')
|
||||||
def test_int__format__locale(self):
|
def test_int__format__locale(self):
|
||||||
|
@ -390,7 +390,7 @@ class TypesTests(unittest.TestCase):
|
||||||
|
|
||||||
x = 123456789012345678901234567890
|
x = 123456789012345678901234567890
|
||||||
for i in range(0, 30):
|
for i in range(0, 30):
|
||||||
self.assertEqual(locale.format('%d', x, grouping=True), format(x, 'n'))
|
self.assertEqual(locale.format_string('%d', x, grouping=True), format(x, 'n'))
|
||||||
|
|
||||||
# move to the next integer to test
|
# move to the next integer to test
|
||||||
x = x // 10
|
x = x // 10
|
||||||
|
|
|
@ -397,6 +397,9 @@ Library
|
||||||
- bpo-29534: Fixed different behaviour of Decimal.from_float()
|
- bpo-29534: Fixed different behaviour of Decimal.from_float()
|
||||||
for _decimal and _pydecimal. Thanks Andrew Nester.
|
for _decimal and _pydecimal. Thanks Andrew Nester.
|
||||||
|
|
||||||
|
- bpo-10379: locale.format_string now supports the 'monetary' keyword argument,
|
||||||
|
and locale.format is deprecated.
|
||||||
|
|
||||||
- Issue #28556: Various updates to typing module: typing.Counter, typing.ChainMap,
|
- Issue #28556: Various updates to typing module: typing.Counter, typing.ChainMap,
|
||||||
improved ABC caching, etc. Original PRs by Jelle Zijlstra, Ivan Levkivskyi,
|
improved ABC caching, etc. Original PRs by Jelle Zijlstra, Ivan Levkivskyi,
|
||||||
Manuel Krebber, and Łukasz Langa.
|
Manuel Krebber, and Łukasz Langa.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue