mirror of https://github.com/python/cpython
gh-124969: Fix locale.nl_langinfo(locale.ALT_DIGITS) (GH-124974)
Now it returns a tuple of up to 100 strings (an empty tuple on most locales). Previously it returned the first item of that tuple or an empty string.
This commit is contained in:
parent
92760bd85b
commit
21c04e1a97
|
@ -158,7 +158,8 @@ The :mod:`locale` module defines the following exception and functions:
|
|||
|
||||
.. function:: nl_langinfo(option)
|
||||
|
||||
Return some locale-specific information as a string. This function is not
|
||||
Return some locale-specific information as a string (or a tuple for
|
||||
``ALT_DIGITS``). This function is not
|
||||
available on all systems, and the set of possible options might also vary
|
||||
across platforms. The possible argument values are numbers, for which
|
||||
symbolic constants are available in the locale module.
|
||||
|
@ -311,8 +312,7 @@ The :mod:`locale` module defines the following exception and functions:
|
|||
|
||||
.. data:: ALT_DIGITS
|
||||
|
||||
Get a representation of up to 100 values used to represent the values
|
||||
0 to 99.
|
||||
Get a tuple of up to 100 strings used to represent the values 0 to 99.
|
||||
|
||||
The function temporarily sets the ``LC_CTYPE`` locale to the locale
|
||||
of the category that determines the requested value (``LC_TIME``,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, localeconv, Error)
|
||||
from _locale import (setlocale, LC_ALL, LC_CTYPE, LC_NUMERIC, LC_TIME, localeconv, Error)
|
||||
try:
|
||||
from _locale import (RADIXCHAR, THOUSEP, nl_langinfo)
|
||||
except ImportError:
|
||||
|
@ -74,6 +74,17 @@ known_numerics = {
|
|||
'ps_AF': ('\u066b', '\u066c'),
|
||||
}
|
||||
|
||||
known_alt_digits = {
|
||||
'C': (0, {}),
|
||||
'en_US': (0, {}),
|
||||
'fa_IR': (100, {0: '\u06f0\u06f0', 10: '\u06f1\u06f0', 99: '\u06f9\u06f9'}),
|
||||
'ja_JP': (100, {0: '\u3007', 10: '\u5341', 99: '\u4e5d\u5341\u4e5d'}),
|
||||
'lzh_TW': (32, {0: '\u3007', 10: '\u5341', 31: '\u5345\u4e00'}),
|
||||
'my_MM': (100, {0: '\u1040\u1040', 10: '\u1041\u1040', 99: '\u1049\u1049'}),
|
||||
'or_IN': (100, {0: '\u0b66', 10: '\u0b67\u0b66', 99: '\u0b6f\u0b6f'}),
|
||||
'shn_MM': (100, {0: '\u1090\u1090', 10: '\u1091\u1090', 99: '\u1099\u1099'}),
|
||||
}
|
||||
|
||||
if sys.platform == 'win32':
|
||||
# ps_AF doesn't work on Windows: see bpo-38324 (msg361830)
|
||||
del known_numerics['ps_AF']
|
||||
|
@ -179,6 +190,34 @@ class _LocaleTests(unittest.TestCase):
|
|||
if not tested:
|
||||
self.skipTest('no suitable locales')
|
||||
|
||||
@unittest.skipUnless(nl_langinfo, "nl_langinfo is not available")
|
||||
@unittest.skipUnless(hasattr(locale, 'ALT_DIGITS'), "requires locale.ALT_DIGITS")
|
||||
@unittest.skipIf(
|
||||
support.is_emscripten or support.is_wasi,
|
||||
"musl libc issue on Emscripten, bpo-46390"
|
||||
)
|
||||
def test_alt_digits_nl_langinfo(self):
|
||||
# Test nl_langinfo(ALT_DIGITS)
|
||||
tested = False
|
||||
for loc, (count, samples) in known_alt_digits.items():
|
||||
with self.subTest(locale=loc):
|
||||
try:
|
||||
setlocale(LC_TIME, loc)
|
||||
except Error:
|
||||
self.skipTest(f'no locale {loc!r}')
|
||||
continue
|
||||
with self.subTest(locale=loc):
|
||||
alt_digits = nl_langinfo(locale.ALT_DIGITS)
|
||||
self.assertIsInstance(alt_digits, tuple)
|
||||
if count and not alt_digits and sys.platform == 'darwin':
|
||||
self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on macOS')
|
||||
self.assertEqual(len(alt_digits), count)
|
||||
for i in samples:
|
||||
self.assertEqual(alt_digits[i], samples[i])
|
||||
tested = True
|
||||
if not tested:
|
||||
self.skipTest('no suitable locales')
|
||||
|
||||
def test_float_parsing(self):
|
||||
# Bug #1391872: Test whether float parsing is okay on European
|
||||
# locales.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix ``locale.nl_langinfo(locale.ALT_DIGITS)``. Now it returns a tuple of up
|
||||
to 100 strings (an empty tuple on most locales). Previously it returned the
|
||||
first item of that tuple or an empty string.
|
|
@ -666,9 +666,35 @@ _locale_nl_langinfo_impl(PyObject *module, int item)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
PyObject *pyresult;
|
||||
#ifdef ALT_DIGITS
|
||||
if (item == ALT_DIGITS) {
|
||||
/* The result is a sequence of up to 100 NUL-separated strings. */
|
||||
const char *s = result;
|
||||
int count = 0;
|
||||
for (; count < 100 && *s; count++) {
|
||||
s += strlen(s) + 1;
|
||||
}
|
||||
pyresult = PyTuple_New(count);
|
||||
if (pyresult != NULL) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
PyObject *unicode = PyUnicode_DecodeLocale(result, NULL);
|
||||
if (unicode == NULL) {
|
||||
Py_CLEAR(pyresult);
|
||||
break;
|
||||
}
|
||||
PyTuple_SET_ITEM(pyresult, i, unicode);
|
||||
result += strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pyresult = PyUnicode_DecodeLocale(result, NULL);
|
||||
}
|
||||
restore_locale(oldloc);
|
||||
return unicode;
|
||||
return pyresult;
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant");
|
||||
|
|
Loading…
Reference in New Issue