Skip to content

Commit f231203

Browse files
authored
bpo-38324: Fix test__locale.py Windows failures (GH-20529)
Use wide-char _W_* fields of lconv structure on Windows Remove "ps_AF" from test__locale.known_numerics on Windows
1 parent d5d0521 commit f231203

File tree

4 files changed

+40
-5
lines changed

4 files changed

+40
-5
lines changed

Lib/test/test__locale.py

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def accept(loc):
7272
'ps_AF': ('\u066b', '\u066c'),
7373
}
7474

75+
if sys.platform == 'win32':
76+
# ps_AF doesn't work on Windows: see bpo-38324 (msg361830)
77+
del known_numerics['ps_AF']
78+
7579
class _LocaleTests(unittest.TestCase):
7680

7781
def setUp(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Avoid Unicode errors when accessing certain locale data on Windows.

Modules/_localemodule.c

+22-3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ locale_is_ascii(const char *str)
155155
static int
156156
locale_decode_monetary(PyObject *dict, struct lconv *lc)
157157
{
158+
#ifndef MS_WINDOWS
158159
int change_locale;
159160
change_locale = (!locale_is_ascii(lc->int_curr_symbol)
160161
|| !locale_is_ascii(lc->currency_symbol)
@@ -190,12 +191,18 @@ locale_decode_monetary(PyObject *dict, struct lconv *lc)
190191
}
191192
}
192193

194+
#define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
195+
#else /* MS_WINDOWS */
196+
/* Use _W_* fields of Windows struct lconv */
197+
#define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
198+
#endif /* MS_WINDOWS */
199+
193200
int res = -1;
194201

195202
#define RESULT_STRING(ATTR) \
196203
do { \
197204
PyObject *obj; \
198-
obj = PyUnicode_DecodeLocale(lc->ATTR, NULL); \
205+
obj = GET_LOCALE_STRING(ATTR); \
199206
if (obj == NULL) { \
200207
goto done; \
201208
} \
@@ -211,14 +218,17 @@ locale_decode_monetary(PyObject *dict, struct lconv *lc)
211218
RESULT_STRING(mon_decimal_point);
212219
RESULT_STRING(mon_thousands_sep);
213220
#undef RESULT_STRING
221+
#undef GET_LOCALE_STRING
214222

215223
res = 0;
216224

217225
done:
226+
#ifndef MS_WINDOWS
218227
if (loc != NULL) {
219228
setlocale(LC_CTYPE, oldloc);
220229
}
221230
PyMem_Free(oldloc);
231+
#endif
222232
return res;
223233
}
224234

@@ -258,9 +268,15 @@ _locale_localeconv_impl(PyObject *module)
258268
Py_DECREF(obj); \
259269
} while (0)
260270

271+
#ifdef MS_WINDOWS
272+
/* Use _W_* fields of Windows struct lconv */
273+
#define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
274+
#else
275+
#define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
276+
#endif
261277
#define RESULT_STRING(s)\
262278
do { \
263-
x = PyUnicode_DecodeLocale(lc->s, NULL); \
279+
x = GET_LOCALE_STRING(s); \
264280
RESULT(#s, x); \
265281
} while (0)
266282

@@ -289,8 +305,10 @@ _locale_localeconv_impl(PyObject *module)
289305
RESULT_INT(n_sign_posn);
290306

291307
/* Numeric information: LC_NUMERIC encoding */
292-
PyObject *decimal_point, *thousands_sep;
308+
PyObject *decimal_point = NULL, *thousands_sep = NULL;
293309
if (_Py_GetLocaleconvNumeric(lc, &decimal_point, &thousands_sep) < 0) {
310+
Py_XDECREF(decimal_point);
311+
Py_XDECREF(thousands_sep);
294312
goto failed;
295313
}
296314

@@ -319,6 +337,7 @@ _locale_localeconv_impl(PyObject *module)
319337
#undef RESULT
320338
#undef RESULT_STRING
321339
#undef RESULT_INT
340+
#undef GET_LOCALE_STRING
322341
}
323342

324343
#if defined(HAVE_WCSCOLL)

Python/fileutils.c

+13-2
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,7 @@ _Py_GetLocaleconvNumeric(struct lconv *lc,
20472047
assert(decimal_point != NULL);
20482048
assert(thousands_sep != NULL);
20492049

2050+
#ifndef MS_WINDOWS
20502051
int change_locale = 0;
20512052
if ((strlen(lc->decimal_point) > 1 || ((unsigned char)lc->decimal_point[0]) > 127)) {
20522053
change_locale = 1;
@@ -2085,26 +2086,36 @@ _Py_GetLocaleconvNumeric(struct lconv *lc,
20852086
}
20862087
}
20872088

2089+
#define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
2090+
#else /* MS_WINDOWS */
2091+
/* Use _W_* fields of Windows strcut lconv */
2092+
#define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
2093+
#endif /* MS_WINDOWS */
2094+
20882095
int res = -1;
20892096

2090-
*decimal_point = PyUnicode_DecodeLocale(lc->decimal_point, NULL);
2097+
*decimal_point = GET_LOCALE_STRING(decimal_point);
20912098
if (*decimal_point == NULL) {
20922099
goto done;
20932100
}
20942101

2095-
*thousands_sep = PyUnicode_DecodeLocale(lc->thousands_sep, NULL);
2102+
*thousands_sep = GET_LOCALE_STRING(thousands_sep);
20962103
if (*thousands_sep == NULL) {
20972104
goto done;
20982105
}
20992106

21002107
res = 0;
21012108

21022109
done:
2110+
#ifndef MS_WINDOWS
21032111
if (loc != NULL) {
21042112
setlocale(LC_CTYPE, oldloc);
21052113
}
21062114
PyMem_Free(oldloc);
2115+
#endif
21072116
return res;
2117+
2118+
#undef GET_LOCALE_STRING
21082119
}
21092120

21102121
/* Our selection logic for which function to use is as follows:

0 commit comments

Comments
 (0)