241 lines
7.8 KiB
Diff
241 lines
7.8 KiB
Diff
diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst
|
|
index b04442bc162..9a0c570533a 100644
|
|
--- a/Doc/library/locale.rst
|
|
+++ b/Doc/library/locale.rst
|
|
@@ -147,6 +147,16 @@ The :mod:`locale` module defines the following exception and functions:
|
|
| ``CHAR_MAX`` | Nothing is specified in this locale. |
|
|
+--------------+-----------------------------------------+
|
|
|
|
+ The function sets temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC``
|
|
+ locale to decode ``decimal_point`` and ``thousands_sep`` byte strings if
|
|
+ they are non-ASCII or longer than 1 byte, and the ``LC_NUMERIC`` locale is
|
|
+ different than the ``LC_CTYPE`` locale. This temporary change affects other
|
|
+ threads.
|
|
+
|
|
+ .. versionchanged:: 3.6.5
|
|
+ The function now sets temporarily the ``LC_CTYPE`` locale to the
|
|
+ ``LC_NUMERIC`` locale in some cases.
|
|
+
|
|
|
|
.. function:: nl_langinfo(option)
|
|
|
|
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
|
|
index 196a4c00056..d8a1647e8b5 100644
|
|
--- a/Doc/library/stdtypes.rst
|
|
+++ b/Doc/library/stdtypes.rst
|
|
@@ -1599,6 +1599,20 @@ expression support in the :mod:`re` module).
|
|
See :ref:`formatstrings` for a description of the various formatting options
|
|
that can be specified in format strings.
|
|
|
|
+ .. note::
|
|
+ When formatting a number (:class:`int`, :class:`float`, :class:`float`
|
|
+ and subclasses) with the ``n`` type (ex: ``'{:n}'.format(1234)``), the
|
|
+ function sets temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC``
|
|
+ locale to decode ``decimal_point`` and ``thousands_sep`` fields of
|
|
+ :c:func:`localeconv` if they are non-ASCII or longer than 1 byte, and the
|
|
+ ``LC_NUMERIC`` locale is different than the ``LC_CTYPE`` locale. This
|
|
+ temporary change affects other threads.
|
|
+
|
|
+ .. versionchanged:: 3.6.5
|
|
+ When formatting a number with the ``n`` type, the function sets
|
|
+ temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC`` locale in some
|
|
+ cases.
|
|
+
|
|
|
|
.. method:: str.format_map(mapping)
|
|
|
|
diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
|
|
index 847b50140a6..f83508c9250 100644
|
|
--- a/Doc/whatsnew/3.6.rst
|
|
+++ b/Doc/whatsnew/3.6.rst
|
|
@@ -2346,3 +2346,11 @@ It has been replaced by the new ``make regen-all`` target.
|
|
(Contributed by Victor Stinner in :issue:`23404`.)
|
|
|
|
.. versionchanged:: 3.6.2
|
|
+
|
|
+
|
|
+Notable changes in Python 3.6.5
|
|
+===============================
|
|
+
|
|
+The :func:`locale.localeconv` function now sets temporarily the ``LC_CTYPE``
|
|
+locale to the ``LC_NUMERIC`` locale in some cases.
|
|
+(Contributed by Victor Stinner in :issue:`31900`.)
|
|
diff --git a/Include/fileutils.h b/Include/fileutils.h
|
|
index 900c70faad7..875715df97a 100644
|
|
--- a/Include/fileutils.h
|
|
+++ b/Include/fileutils.h
|
|
@@ -119,6 +119,11 @@ PyAPI_FUNC(int) _Py_get_blocking(int fd);
|
|
PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking);
|
|
#endif /* !MS_WINDOWS */
|
|
|
|
+PyAPI_FUNC(int) _Py_GetLocaleconvNumeric(
|
|
+ PyObject **decimal_point,
|
|
+ PyObject **thousands_sep,
|
|
+ const char **grouping);
|
|
+
|
|
#endif /* Py_LIMITED_API */
|
|
|
|
#ifdef __cplusplus
|
|
diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c
|
|
index 71c9146ccb8..95b370b1ad0 100644
|
|
--- a/Modules/_localemodule.c
|
|
+++ b/Modules/_localemodule.c
|
|
@@ -171,12 +171,6 @@ PyLocale_localeconv(PyObject* self)
|
|
RESULT(#i, x); \
|
|
} while (0)
|
|
|
|
- /* Numeric information */
|
|
- RESULT_STRING(decimal_point);
|
|
- RESULT_STRING(thousands_sep);
|
|
- x = copy_grouping(l->grouping);
|
|
- RESULT("grouping", x);
|
|
-
|
|
/* Monetary information */
|
|
RESULT_STRING(int_curr_symbol);
|
|
RESULT_STRING(currency_symbol);
|
|
@@ -195,6 +189,32 @@ PyLocale_localeconv(PyObject* self)
|
|
RESULT_INT(n_sep_by_space);
|
|
RESULT_INT(p_sign_posn);
|
|
RESULT_INT(n_sign_posn);
|
|
+
|
|
+ /* Numeric information */
|
|
+ PyObject *decimal_point, *thousands_sep;
|
|
+ const char *grouping;
|
|
+ if (_Py_GetLocaleconvNumeric(&decimal_point,
|
|
+ &thousands_sep,
|
|
+ &grouping) < 0) {
|
|
+ goto failed;
|
|
+ }
|
|
+
|
|
+ if (PyDict_SetItemString(result, "decimal_point", decimal_point) < 0) {
|
|
+ Py_DECREF(decimal_point);
|
|
+ Py_DECREF(thousands_sep);
|
|
+ goto failed;
|
|
+ }
|
|
+ Py_DECREF(decimal_point);
|
|
+
|
|
+ if (PyDict_SetItemString(result, "thousands_sep", thousands_sep) < 0) {
|
|
+ Py_DECREF(thousands_sep);
|
|
+ goto failed;
|
|
+ }
|
|
+ Py_DECREF(thousands_sep);
|
|
+
|
|
+ x = copy_grouping(grouping);
|
|
+ RESULT("grouping", x);
|
|
+
|
|
return result;
|
|
|
|
failed:
|
|
diff --git a/Python/fileutils.c b/Python/fileutils.c
|
|
index 97505e5bc6d..14dd81b03f0 100644
|
|
--- a/Python/fileutils.c
|
|
+++ b/Python/fileutils.c
|
|
@@ -1597,3 +1597,80 @@ _Py_set_blocking(int fd, int blocking)
|
|
return -1;
|
|
}
|
|
#endif
|
|
+
|
|
+
|
|
+int
|
|
+_Py_GetLocaleconvNumeric(PyObject **decimal_point, PyObject **thousands_sep,
|
|
+ const char **grouping)
|
|
+{
|
|
+ int res = -1;
|
|
+
|
|
+ struct lconv *lc = localeconv();
|
|
+
|
|
+ int change_locale = 0;
|
|
+ if (decimal_point != NULL &&
|
|
+ (strlen(lc->decimal_point) > 1 || ((unsigned char)lc->decimal_point[0]) > 127))
|
|
+ {
|
|
+ change_locale = 1;
|
|
+ }
|
|
+ if (thousands_sep != NULL &&
|
|
+ (strlen(lc->thousands_sep) > 1 || ((unsigned char)lc->thousands_sep[0]) > 127))
|
|
+ {
|
|
+ change_locale = 1;
|
|
+ }
|
|
+
|
|
+ /* Keep a copy of the LC_CTYPE locale */
|
|
+ char *oldloc = NULL, *loc = NULL;
|
|
+ if (change_locale) {
|
|
+ oldloc = setlocale(LC_CTYPE, NULL);
|
|
+ if (!oldloc) {
|
|
+ PyErr_SetString(PyExc_RuntimeWarning, "faild to get LC_CTYPE locale");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ oldloc = _PyMem_Strdup(oldloc);
|
|
+ if (!oldloc) {
|
|
+ PyErr_NoMemory();
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ loc = setlocale(LC_NUMERIC, NULL);
|
|
+ if (loc != NULL && strcmp(loc, oldloc) == 0) {
|
|
+ loc = NULL;
|
|
+ }
|
|
+
|
|
+ if (loc != NULL) {
|
|
+ /* Only set the locale temporarilty the LC_CTYPE locale
|
|
+ if LC_NUMERIC locale is different than LC_CTYPE locale and
|
|
+ decimal_point and/or thousands_sep are non-ASCII or longer than
|
|
+ 1 byte */
|
|
+ setlocale(LC_CTYPE, loc);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (decimal_point != NULL) {
|
|
+ *decimal_point = PyUnicode_DecodeLocale(lc->decimal_point, NULL);
|
|
+ if (*decimal_point == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+ if (thousands_sep != NULL) {
|
|
+ *thousands_sep = PyUnicode_DecodeLocale(lc->thousands_sep, NULL);
|
|
+ if (*thousands_sep == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (grouping != NULL) {
|
|
+ *grouping = lc->grouping;
|
|
+ }
|
|
+
|
|
+ res = 0;
|
|
+
|
|
+error:
|
|
+ if (loc != NULL) {
|
|
+ setlocale(LC_CTYPE, oldloc);
|
|
+ }
|
|
+ PyMem_Free(oldloc);
|
|
+ return res;
|
|
+}
|
|
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
|
|
index d2be76f1e1a..d3ef650e6ce 100644
|
|
--- a/Python/formatter_unicode.c
|
|
+++ b/Python/formatter_unicode.c
|
|
@@ -707,18 +707,11 @@ get_locale_info(enum LocaleType type, LocaleInfo *locale_info)
|
|
{
|
|
switch (type) {
|
|
case LT_CURRENT_LOCALE: {
|
|
- struct lconv *locale_data = localeconv();
|
|
- locale_info->decimal_point = PyUnicode_DecodeLocale(
|
|
- locale_data->decimal_point,
|
|
- NULL);
|
|
- if (locale_info->decimal_point == NULL)
|
|
+ if (_Py_GetLocaleconvNumeric(&locale_info->decimal_point,
|
|
+ &locale_info->thousands_sep,
|
|
+ &locale_info->grouping) < 0) {
|
|
return -1;
|
|
- locale_info->thousands_sep = PyUnicode_DecodeLocale(
|
|
- locale_data->thousands_sep,
|
|
- NULL);
|
|
- if (locale_info->thousands_sep == NULL)
|
|
- return -1;
|
|
- locale_info->grouping = locale_data->grouping;
|
|
+ }
|
|
break;
|
|
}
|
|
case LT_DEFAULT_LOCALE:
|