Bug report
On a wide (ncursesw) build, window.inch() and window.mvinch() return the low 8 bits of a character's code point instead of its locale-encoded byte, so they disagree with instr() for the same cell. It is invisible for ASCII/Latin-1 (where the byte equals the low byte of the code point) and only shows for other single-byte characters.
Under an ISO-8859-15 locale (€ U+20AC encodes to 0xA4):
import curses, locale locale.setlocale(locale.LC_ALL, '') # run under e.g. LANG=en_US.ISO-8859-15 def main(stdscr): stdscr.addstr(0, 0, '€') print(hex(stdscr.instr(0, 0, 1)[0])) # 0xa4 — correct print(hex(stdscr.inch(0, 0) & curses.A_CHARTEXT)) # 0xac — wrong curses.wrapper(main)
Cause: ncurses' winch() returns the raw cell character with no locale conversion, unlike instr() and getbkgd(). getbkgd() is not affected. Reported upstream (bug-ncurses), where the 8-bit behavior is considered documented, so this should be worked around on the CPython side by re-encoding the cell to its locale byte when the character has a single-byte form.
Linked PRs
- gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build #153863
- [3.15] gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build (GH-153863) #154116
- [3.14] gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build (GH-153863) #154151
- [3.13] gh-153862: Fix curses window.inch() for non-ASCII characters on a wide build (GH-153863) #154153
- gh-153862: Fix spurious color pair in curses window.inch() on a wide build #154703
- [3.15] gh-153862: Fix spurious color pair in curses window.inch() on a wide build (GH-154703) #154720
- [3.14] gh-153862: Fix spurious color pair in curses window.inch() on a wide build (GH-154703) #154732
- [3.13] gh-153862: Fix spurious color pair in curses window.inch() on a wide build (GH-154703) #154733