I am running Python 3.10 and I am having an issue with curses, specifically when trying to utilize the full range of color pairs
curses.COLORS
returns 256
curses.COLOR_PAIRS
returns 65536
curses.has_extended_color_support()
returns True
But when I initialize a color pair of 256, 512, 768, 1024, etc... the color pair seems to reset the colors that were initialized
Additionally, if I am trying to display any color pair > 255 (curses.COLORS - 1
) it uses one of the pairs < 255 instead of the color pair ID I set. Curses allows me to run init_pair with these numbers, but it ignores them completely, and instead uses the color pair < 255
Here is an example code snippet
#!/usr/bin/env python3.10
"""
Python3.10 added extended color support to curses
curses.COLOR_PAIRS (xterm-256color) returns 65,536
curses.COLORS (xterm-256color) returns 256
"""
import curses
def cycler(start_color, end_color):
# cycle through all possible color IDs or pair IDs curses can display, loops indefinitely
while True:
for i in range(start_color, end_color):
yield i
def main(stdscr):
curses.start_color()
height, width = stdscr.getmaxyx()
RED = 1 # Reserve the red color at color ID 1
curses.init_color(RED, 1000, 0, 0)
color_cycler = cycler(2, curses.COLORS - 1) # RED is reserved at 1, start at 2
pair_cycler = cycler(1, curses.COLOR_PAIRS - 1)
has_extended_support = curses.has_extended_color_support()
stdscr.addstr(0, 0, f"COLORS:{curses.COLORS} "
f"COLOR_PAIRS:{curses.COLOR_PAIRS} "
f"ExtendedSupport:{has_extended_support}", curses.color_pair(1))
for y in range(1, height - 1):
for x in range(0, width, 5):
color_id = next(color_cycler)
pair_id = next(pair_cycler)
intensity = int((color_id / (curses.COLORS - 1)) * 1000)
curses.init_color(color_id, intensity, intensity, intensity)
# create a new color pair, (RED) foreground, (color) background
curses.init_pair(pair_id, RED, color_id)
string = str(pair_id).rjust(5, ' ')
stdscr.addstr(y, x, string, curses.color_pair(pair_id))
stdscr.noutrefresh()
curses.doupdate()
stdscr.getch()
if __name__ == "__main__":
curses.wrapper(main)
And here is a screenshot of what it generates for me (notice the numbers 256, 512, 768, 1024) the numbers represent the color pair ID
Terminal apps I've tried:
All with the same issue
You would have to use the extended interface, as noted in the release announcement for ncurses 6.1:
The motivation for making this extension came from noticing that termcap applications could (though not realistically) use larger numbers than would fit in 16-bits, and the fact that the number of color pairs for a 256-color xterm could not be expressed in terminfo (i.e., 32767 versus 65536). Also, a few terminals support direct-colors, which could use the extension.
Python probably doesn't do that (its binding only covers part of ncurses), so color-values and color-pairs are a signed 16-bit number:
0..32767
Now... python 3.10 was released in October 2021. The most recent ncurses fix related to color-pairs was in August 2021. If you're using an older version of ncurses (e.g., by compiling python on something very old, such as RHEL8), then it's just a known bug to which the answer would be "upgrade".