This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: curses.addch('a', curses.color_pair(1)) ignores the color information
Type: Stage: resolved
Components: Library (Lib) Versions: Python 3.9, Python 3.8, Python 3.7
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: mgedmin, miss-islington, vstinner
Priority: normal Keywords: patch

Created on 2019-08-01 13:45 by mgedmin, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 15071 merged vstinner, 2019-08-01 15:12
PR 15272 merged miss-islington, 2019-08-14 10:31
PR 15273 merged vstinner, 2019-08-14 10:41
Messages (8)
msg348855 - (view) Author: Marius Gedminas (mgedmin) * Date: 2019-08-01 13:45
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.init_pair(1, curses.COLOR_RED, -1)                                                                                               
    curses.init_pair(2, curses.COLOR_GREEN, -1)                                                                                             
    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)                                                                            
### 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'.
msg348862 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-01 15:13
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.
msg348863 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-01 15:18
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__)'
vstinner@apu$ ldd $(python3 -c 'import _curses; print(_curses.__file__)') (0x00007ffe6f1b4000) => /lib64/ (0x00007f1acf456000) => /lib64/ (0x00007f1acf427000) => /lib64/ (0x00007f1acf0de000) => /lib64/ (0x00007f1acef18000) => /lib64/ (0x00007f1acef12000) => /lib64/ (0x00007f1aceef1000) => /lib64/ (0x00007f1aceeea000) => /lib64/ (0x00007f1aceda4000)
	/lib64/ (0x00007f1acf4dc000)
vstinner@apu$ rpm -qf /lib64/
msg349672 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-14 10:31
New changeset 077af8c2c93dd71086e2c5e5ff1e634b6da8f214 by Victor Stinner in branch 'master':
bpo-37738: Fix curses addch(str, color_pair) (GH-15071)
msg349673 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-14 10:40
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.
msg349674 - (view) Author: miss-islington (miss-islington) Date: 2019-08-14 10:49
New changeset 984226962bc35254551d92771b5c8fb074507903 by Miss Islington (bot) in branch '3.8':
bpo-37738: Fix curses addch(str, color_pair) (GH-15071)
msg349676 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-14 11:00
New changeset 7eef81ee766c8df23e522b4e46a930cc1d360ad7 by Victor Stinner in branch '3.7':
bpo-37738: Fix curses addch(str, color_pair) (GH-15071) (GH-15273)
msg349677 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-08-14 11:01
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() :-(
Date User Action Args
2022-04-11 14:59:18adminsetgithub: 81919
2019-08-14 11:01:28vstinnersetstatus: open -> closed
resolution: fixed
messages: + msg349677

stage: patch review -> resolved
2019-08-14 11:00:30vstinnersetmessages: + msg349676
2019-08-14 10:49:16miss-islingtonsetnosy: + miss-islington
messages: + msg349674
2019-08-14 10:41:55vstinnersetpull_requests: + pull_request14995
2019-08-14 10:40:24vstinnersetmessages: + msg349673
2019-08-14 10:31:57vstinnersetmessages: + msg349672
2019-08-14 10:31:54miss-islingtonsetpull_requests: + pull_request14994
2019-08-01 16:03:23vstinnersetversions: + Python 3.9, - Python 3.5, Python 3.6
2019-08-01 15:18:31vstinnersetmessages: + msg348863
2019-08-01 15:13:21vstinnersetnosy: + vstinner
messages: + msg348862
2019-08-01 15:12:29vstinnersetkeywords: + patch
stage: patch review
pull_requests: + pull_request14818
2019-08-01 13:45:15mgedmincreate