Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

curses.addch('a', curses.color_pair(1)) ignores the color information #81919

Closed
mgedmin mannequin opened this issue Aug 1, 2019 · 8 comments
Closed

curses.addch('a', curses.color_pair(1)) ignores the color information #81919

mgedmin mannequin opened this issue Aug 1, 2019 · 8 comments
Labels
3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes stdlib Python modules in the Lib dir

Comments

@mgedmin
Copy link
Mannequin

mgedmin mannequin commented Aug 1, 2019

BPO 37738
Nosy @mgedmin, @vstinner, @miss-islington
PRs
  • bpo-37738: Fix curses addch(str, color_pair) #15071
  • [3.8] bpo-37738: Fix curses addch(str, color_pair) (GH-15071) #15272
  • [3.7] bpo-37738: Fix curses addch(str, color_pair) (GH-15071) #15273
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-08-14.11:01:28.955>
    created_at = <Date 2019-08-01.13:45:15.175>
    labels = ['3.8', '3.7', 'library', '3.9']
    title = "curses.addch('a', curses.color_pair(1)) ignores the color information"
    updated_at = <Date 2019-08-14.11:01:28.954>
    user = 'https://github.com/mgedmin'

    bugs.python.org fields:

    activity = <Date 2019-08-14.11:01:28.954>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-08-14.11:01:28.955>
    closer = 'vstinner'
    components = ['Library (Lib)']
    creation = <Date 2019-08-01.13:45:15.175>
    creator = 'mgedmin'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 37738
    keywords = ['patch']
    message_count = 8.0
    messages = ['348855', '348862', '348863', '349672', '349673', '349674', '349676', '349677']
    nosy_count = 3.0
    nosy_names = ['mgedmin', 'vstinner', 'miss-islington']
    pr_nums = ['15071', '15272', '15273']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue37738'
    versions = ['Python 3.7', 'Python 3.8', 'Python 3.9']

    @mgedmin
    Copy link
    Mannequin Author

    mgedmin mannequin commented Aug 1, 2019

    curses.addch() ignores color information if I pass it a string of length one. Color works fine if I pass it a byte string or an int. Here's a reproducer:

    ### start of example ###
    import curses                                                                                                                               
                                                                                                                                                
                                                                                                                                                
    def main(stdscr):                                                                                                                           
        curses.start_color()                                                                                                                    
        curses.use_default_colors()                                                                                                             
        curses.init_pair(1, curses.COLOR_RED, -1)                                                                                               
        curses.init_pair(2, curses.COLOR_GREEN, -1)                                                                                             
        curses.curs_set(0)                                                                                                                      
                                                                                                                                                
        stdscr.addch("a", curses.color_pair(1))                                                                                                 
        stdscr.addch("b", curses.color_pair(2) | curses.A_BOLD)                                                                                 
        stdscr.addch(b"c", curses.color_pair(1))                                                                                                
        stdscr.addch(b"d", curses.color_pair(2) | curses.A_BOLD)                                                                                
        stdscr.addch(ord("e"), curses.color_pair(1))                                                                                            
        stdscr.addch(ord("f"), curses.color_pair(2) | curses.A_BOLD)                                                                            
        stdscr.refresh()                                                                                                                        
                                                                                                                                                
        stdscr.getch()                                                                                                                          
                                                                                                                                                
                                                                                                                                                
    curses.wrapper(main)                                                                                                                        
    ### end of example ###

    On Python 2.7 this prints 'abcdef' in alternating red and green. On Python 3.5 through 3.8 this prints 'ab' in white and the rest in red/green.

    Note that only color pair information is lost -- the bold attribute is correctly set on the 'b'.

    @mgedmin mgedmin mannequin added 3.7 (EOL) end of life 3.8 only security fixes stdlib Python modules in the Lib dir labels Aug 1, 2019
    @vstinner
    Copy link
    Member

    vstinner commented Aug 1, 2019

    stdscr.addch(str, color_pair) is implemented with:

    setcchar(&wcval, wstr, attr, 0, NULL);
    rtn = wadd_wch(self->win, &wcval);

    whereas stdscr.addch(bytes, color_pair) is implemented with:

       rtn = waddch(self->win, cch | (attr_t) attr);

    The 4th argument of setcchar() is "short color_pair": Python always pass 0. It seems to be your bug.

    Attached PR 15071 fix this bug.

    Note: Python 3.5 and 3.6 don't accept bugfixes anymore, only security fixes.

    @vstinner
    Copy link
    Member

    vstinner commented Aug 1, 2019

    I'm able to reproduce the issue on Fedora 30: Python 3.7.4 with ncurses-libs-6.1-10.20180923.fc30.x86_64.

    vstinner@apu$ cat /etc/fedora-release
    Fedora release 30 (Thirty)
    vstinner@apu$ python3 -VV
    Python 3.7.4 (default, Jul 9 2019, 16:32:37)
    [GCC 9.1.1 20190503 (Red Hat 9.1.1-1)]
    vstinner@apu$ python3 -c 'import _curses; print(curses.__file_)'
    /usr/lib64/python3.7/lib-dynload/curses.cpython-37m-x86_64-linux-gnu.so
    vstinner@apu$ ldd $(python3 -c 'import _curses; print(curses.__file
    )')
    linux-vdso.so.1 (0x00007ffe6f1b4000)
    libncursesw.so.6 => /lib64/libncursesw.so.6 (0x00007f1acf456000)
    libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007f1acf427000)
    libpython3.7m.so.1.0 => /lib64/libpython3.7m.so.1.0 (0x00007f1acf0de000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f1acef18000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f1acef12000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1aceef1000)
    libutil.so.1 => /lib64/libutil.so.1 (0x00007f1aceeea000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f1aceda4000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f1acf4dc000)
    vstinner@apu$ rpm -qf /lib64/libncursesw.so.6
    ncurses-libs-6.1-10.20180923.fc30.x86_64

    @vstinner vstinner added the 3.9 only security fixes label Aug 1, 2019
    @vstinner
    Copy link
    Member

    New changeset 077af8c by Victor Stinner in branch 'master':
    bpo-37738: Fix curses addch(str, color_pair) (GH-15071)
    077af8c

    @vstinner
    Copy link
    Member

    On my Fedora 30 with libncursesw, A_COLOR = 0xff00.

    After my change, _curses uses:

    static inline short
    attr_to_color_pair(int attr)
    {
        return (short)((attr & A_COLOR) >> 8);
    }
    
    ...
    setcchar(&wcval, wstr, attr, attr_to_color_pair(attr), NULL);
    ...
    

    If someone gets troubles with attr passed "directly" as the 3rd argument of setcchar(), we can try to pass (attr & ~A_COLOR) instead. On my Linux, it would mean: only pass the low 8 bits of attr.

    But since it "just" works on my Linux, I prefer to only make minimum changes to fix this issue on Linux.

    @miss-islington
    Copy link
    Contributor

    New changeset 9842269 by Miss Islington (bot) in branch '3.8':
    bpo-37738: Fix curses addch(str, color_pair) (GH-15071)
    9842269

    @vstinner
    Copy link
    Member

    New changeset 7eef81e by Victor Stinner in branch '3.7':
    bpo-37738: Fix curses addch(str, color_pair) (GH-15071) (GH-15273)
    7eef81e

    @vstinner
    Copy link
    Member

    I fixed the bug in 3.7, 3.8 and master (future 3.9) branches. Thanks Marius Gedminas for the bug report. In the meanwhile, you have to pass bytes strings to addch() :-(

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes stdlib Python modules in the Lib dir
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants