Skip to content

Commit 0f2ff4c

Browse files
gh-151316: Address review on locale UTF-8 overrides
Use support.subTests for the hardcoded replacements, shorten the test docstring with an issue link, and extract apply_x11_locales_patch() so the X11 override of glibc UTF-8 defaults is explicit. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent a273b30 commit 0f2ff4c

2 files changed

Lines changed: 60 additions & 56 deletions

File tree

Lib/test/test_locale.py

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -642,56 +642,51 @@ def test_getlocale_with_modifier(self, localename, localetuple):
642642
self.assertEqual(locale.getlocale(locale.LC_CTYPE), localetuple)
643643

644644

645+
# Bare aliases that must stay on UTF-8 after X11 locale.alias regeneration
646+
# (gh-151316). Keep in sync with apply_x11_locales_patch() in
647+
# Tools/i18n/makelocalealias.py.
648+
_UTF8_X11_OVERRIDES = (
649+
('az_az', 'az_AZ.UTF-8'),
650+
('de_li', 'de_LI.UTF-8'),
651+
('en_il', 'en_IL.UTF-8'),
652+
('en_in', 'en_IN.UTF-8'),
653+
('eo', 'eo.UTF-8'),
654+
('es_cu', 'es_CU.UTF-8'),
655+
('hi_in', 'hi_IN.UTF-8'),
656+
('iu_ca', 'iu_CA.UTF-8'),
657+
('lo_la', 'lo_LA.UTF-8'),
658+
('nr_za', 'nr_ZA.UTF-8'),
659+
('nso_za', 'nso_ZA.UTF-8'),
660+
('rw_rw', 'rw_RW.UTF-8'),
661+
('ss_za', 'ss_ZA.UTF-8'),
662+
('ta_in', 'ta_IN.UTF-8'),
663+
('tn_za', 'tn_ZA.UTF-8'),
664+
('ts_za', 'ts_ZA.UTF-8'),
665+
('tt_ru', 'tt_RU.UTF-8'),
666+
('ur_pk', 'ur_PK.UTF-8'),
667+
('vi_vn', 'vi_VN.UTF-8'),
668+
)
669+
670+
645671
class TestHardcodedLocaleReplacements(unittest.TestCase):
646-
"""gh-151316: UTF-8 preferences that override X11 legacy codesets.
672+
"""UTF-8 preferences that override X11 legacy codesets.
647673
648-
These bare aliases are UTF-8-only in glibc SUPPORTED, but X11
649-
locale.alias still maps them to obsolete encodings. makelocalealias
650-
restores the glibc UTF-8 defaults after applying X11 (plus de_li,
651-
which has no bare SUPPORTED line).
674+
See https://github.com/python/cpython/issues/151316
652675
"""
653676

654-
REPLACEMENTS = {
655-
'az_az': 'az_AZ.UTF-8',
656-
'de_li': 'de_LI.UTF-8',
657-
'en_il': 'en_IL.UTF-8',
658-
'en_in': 'en_IN.UTF-8',
659-
'eo': 'eo.UTF-8',
660-
'es_cu': 'es_CU.UTF-8',
661-
'hi_in': 'hi_IN.UTF-8',
662-
'iu_ca': 'iu_CA.UTF-8',
663-
'lo_la': 'lo_LA.UTF-8',
664-
'nr_za': 'nr_ZA.UTF-8',
665-
'nso_za': 'nso_ZA.UTF-8',
666-
'rw_rw': 'rw_RW.UTF-8',
667-
'ss_za': 'ss_ZA.UTF-8',
668-
'ta_in': 'ta_IN.UTF-8',
669-
'tn_za': 'tn_ZA.UTF-8',
670-
'ts_za': 'ts_ZA.UTF-8',
671-
'tt_ru': 'tt_RU.UTF-8',
672-
'ur_pk': 'ur_PK.UTF-8',
673-
'vi_vn': 'vi_VN.UTF-8',
674-
}
677+
@support.subTests('key,expected', _UTF8_X11_OVERRIDES)
678+
def test_locale_alias_entries(self, key, expected):
679+
self.assertEqual(locale.locale_alias[key], expected)
680+
681+
@support.subTests('key,expected', _UTF8_X11_OVERRIDES)
682+
def test_normalize(self, key, expected):
683+
self.assertEqual(locale.normalize(key), expected)
684+
self.assertEqual(locale.normalize(key.upper()), expected)
675685

676-
def test_locale_alias_entries(self):
677-
for key, expected in self.REPLACEMENTS.items():
678-
with self.subTest(key=key):
679-
self.assertEqual(locale.locale_alias[key], expected)
680-
681-
def test_normalize(self):
682-
for key, expected in self.REPLACEMENTS.items():
683-
with self.subTest(key=key):
684-
self.assertEqual(locale.normalize(key), expected)
685-
self.assertEqual(locale.normalize(key.upper()), expected)
686-
687-
def test_parse_localename(self):
688-
for key, expected in self.REPLACEMENTS.items():
689-
with self.subTest(key=key):
690-
lang, encoding = expected.split('.')
691-
self.assertEqual(
692-
locale._parse_localename(key),
693-
(lang, encoding),
694-
)
686+
@support.subTests('key,expected', _UTF8_X11_OVERRIDES)
687+
def test_parse_localename(self, key, expected):
688+
lang, encoding = expected.split('.')
689+
self.assertEqual(locale._parse_localename(key), (lang, encoding))
695690

696691

697692
class TestMiscellaneous(unittest.TestCase):

Tools/i18n/makelocalealias.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,25 @@ def parse_glibc_supported(filename):
9898
data[locale] = alias
9999
return data
100100

101+
def apply_x11_locales_patch(data, glibc_data):
102+
"""Restore glibc UTF-8 defaults that X11 locale.alias overwrote.
103+
104+
Regeneration updates glibc SUPPORTED first, then X11 locale.alias.
105+
X11 still maps several locales that are UTF-8-only in modern glibc to
106+
obsolete encodings (for example en_IN -> en_IN.ISO8859-1). Prefer the
107+
glibc UTF-8 mapping for those bare keys (gh-151316).
108+
109+
de_LI is special: glibc only ships de_LI.UTF-8 (no bare SUPPORTED line),
110+
so the X11 de_LI.ISO8859-1 mapping would otherwise stick.
111+
"""
112+
for key, value in glibc_data.items():
113+
if data.get(key) == value:
114+
continue
115+
if value.split('@')[0].endswith('.UTF-8'):
116+
data[key] = value
117+
data['de_li'] = 'de_LI.UTF-8'
118+
return data
119+
101120
def pprint(data):
102121
items = sorted(data.items())
103122
for k, v in items:
@@ -155,17 +174,7 @@ def check(data):
155174
# Hardcode 'c.utf8' -> 'C.UTF-8' because 'en_US.UTF-8' does not exist
156175
# on all platforms.
157176
data['c.utf8'] = 'C.UTF-8'
158-
# Prefer glibc UTF-8 defaults over X11 legacy codesets (gh-151316).
159-
# X11 locale.alias still maps several UTF-8-only locales to obsolete
160-
# encodings and would otherwise override glibc during regeneration.
161-
for key, value in glibc_data.items():
162-
if data.get(key) == value:
163-
continue
164-
if value.split('@')[0].endswith('.UTF-8'):
165-
data[key] = value
166-
# de_LI is UTF-8-only in glibc as 'de_LI.UTF-8', with no bare SUPPORTED
167-
# line, so the X11 'de_LI.ISO8859-1' mapping would otherwise stick.
168-
data['de_li'] = 'de_LI.UTF-8'
177+
data = apply_x11_locales_patch(data, glibc_data)
169178
while True:
170179
# Repeat optimization while the size is decreased.
171180
n = len(data)

0 commit comments

Comments
 (0)