Skip to content

Commit d7f4d16

Browse files
gh-151757: Fix curses wide-character tests in non-UTF-8 locales
wcwidth() only classifies combining characters in a locale that can encode them, so guard the wide-character test operations on encodability. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a5677bf commit d7f4d16

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

Lib/test/test_curses.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,23 @@ def test_refresh_control(self):
253253
self.assertIs(win.is_wintouched(), syncok)
254254
self.assertIs(stdscr.is_wintouched(), syncok)
255255

256+
def _encodable(self, s):
257+
# Wide characters are only supported in a locale that can encode them.
258+
try:
259+
s.encode(self.stdscr.encoding)
260+
except UnicodeEncodeError:
261+
return False
262+
return True
263+
256264
@requires_curses_window_meth('get_wch')
257265
def test_addch_combining(self):
258-
# A character cell may hold a spacing char plus combining marks.
259266
stdscr = self.stdscr
260267
stdscr.move(0, 0)
261-
stdscr.addch('e\u0301') # 'e' + COMBINING ACUTE ACCENT
262-
stdscr.addch(1, 0, 'a\u0323\u0300') # base plus two combining marks
268+
# A character cell may hold a spacing char plus combining marks.
269+
if self._encodable('e\u0301'):
270+
stdscr.addch('e\u0301') # 'e' + COMBINING ACUTE ACCENT
271+
if self._encodable('a\u0323\u0300'):
272+
stdscr.addch(1, 0, 'a\u0323\u0300') # base plus two combining marks
263273
# Too many code points to fit in a single character cell.
264274
self.assertRaises(TypeError, stdscr.addch, 'e' + '\u0301' * 10)
265275
# Only the first code point may be a spacing character.
@@ -278,8 +288,10 @@ def test_addch_emoji(self):
278288
# character plus zero-width combining characters. A lone emoji fits,
279289
# as does an emoji with a zero-width variation selector.
280290
stdscr = self.stdscr
281-
stdscr.addch(0, 0, '\U0001f600') # single emoji
282-
stdscr.addch(1, 0, '\u263a\ufe0f') # WHITE SMILING FACE + VS-16
291+
if self._encodable('\U0001f600'):
292+
stdscr.addch(0, 0, '\U0001f600') # single emoji
293+
if self._encodable('\u263a\ufe0f'):
294+
stdscr.addch(1, 0, '\u263a\ufe0f') # WHITE SMILING FACE + VS-16
283295
# An emoji ZWJ sequence or an emoji with a modifier is more than one
284296
# spacing character and cannot share a single cell.
285297
self.assertRaises(ValueError, stdscr.addch,
@@ -294,14 +306,18 @@ def test_wide_characters(self):
294306
combining = 'e\u0301' # 'e' + COMBINING ACUTE ACCENT
295307
vline, hline = '\u2502', '\u2500' # box-drawing vertical/horizontal
296308
stdscr.move(0, 0)
297-
stdscr.echochar(combining)
298-
stdscr.insch(1, 0, combining)
299-
stdscr.hline(2, 0, hline, 5)
300-
stdscr.vline(3, 0, vline, 3)
301-
stdscr.bkgdset(combining)
302-
stdscr.bkgd(combining)
303-
stdscr.border(vline, vline, hline, hline)
304-
stdscr.box(vline, hline)
309+
if self._encodable(combining):
310+
stdscr.echochar(combining)
311+
stdscr.insch(1, 0, combining)
312+
stdscr.bkgdset(combining)
313+
stdscr.bkgd(combining)
314+
if self._encodable(hline):
315+
stdscr.hline(2, 0, hline, 5)
316+
if self._encodable(vline):
317+
stdscr.vline(3, 0, vline, 3)
318+
if self._encodable(vline + hline):
319+
stdscr.border(vline, vline, hline, hline)
320+
stdscr.box(vline, hline)
305321
# border() and box() cannot mix integer and wide-string characters.
306322
self.assertRaises(TypeError, stdscr.box, vline, ord('-'))
307323

0 commit comments

Comments
 (0)