.. 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.
.. 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.
.. function:: getdefaultlocale([envvars])
-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:
'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']
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)
+ setlocale(LC_CTYPE, 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 support.is_apple:
+ self.skipTest(f'ALT_DIGITS is not set for locale {loc!r} on Apple platforms')
+ 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.
instead of an empty string for nl_langinfo(ERA). */
const char *result = nl_langinfo(item);
result = result != NULL ? result : "";
- return PyUnicode_DecodeLocale(result, 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);
+ }
+ return pyresult;
}
PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant");
return NULL;