FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

curses.window.inch() returns the wrong byte for a non-ASCII character on a wide build · Issue #153862 · python/cpython · GitHub

Repository navigation

curses.window.inch() returns the wrong byte for a non-ASCII character on a wide build #153862

Closed

Description

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

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    3.13only security fixes
    3.14bugs and security fixes
    3.15bugs and security fixes
    3.16new features, bugs and security fixes
    on Jul 17, 2026
  2. added 4 commits that reference this issue on Jul 19, 2026
  3. added a commit that references this issue on Jul 26, 2026
  4. serhiy-storchaka commented on Jul 26, 2026

    MemberAuthor

    It turned out to be worse than I anticipated.

    The previous fix was based on the ncurses documentation, which explicitly says that inch() returns only the low-order eight bits of the character code from the cell. In fact it returns the whole code point, ORed with the color pair and attributes. It could "work", even for non-encodable characters and even in a UTF-8 locale, but only when there are no attributes and the color pair is 0. Otherwise they pollute each other, and you can reconstruct neither the character nor its color and attributes. The previous fix kept the polluted high bits. The new fix rebuilds the result entirely from win_wch(). It returns 0 as the character for non-encodable characters.

    This can break code that interpreted the result of inch() as the code point. But it is the lesser evil — better than keeping the old, broken behavior — because there is another way to read characters (instr()), while there is no other way to read the color and attributes in older Python versions.

    In 3.16, the new in_wch() method returns the whole character together with its attributes and color pair, so it gives a lossless way to read a cell there. On older versions there is no in_wch(), and inch() is the only reader of a cell's attributes and color — which is exactly why fixing it correctly matters.

  5. added 3 commits that reference this issue on Jul 26, 2026
  6. added a commit that references this issue on Jul 26, 2026
  7. added a commit that references this issue on Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixes3.14bugs and security fixes3.15bugs and security fixes3.16new features, bugs and security fixestype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL