I've been experimenting with Curses colors and ran into a bit of an issue.
As the documentation of init_pair
states, the first argument (the number of the pair) shall be between 1
and curses.COLOR_PAIRS - 1
. Doing print(curses.COLOR, curses.COLOR_PAIR)
yields 256 65536
, so one would think that calling courses.init_pair(40000, 1, 53)
(random example) would work, but I get an error instead:
Traceback (most recent call last):
File "4-colors.py", line 38, in <module>
curses.wrapper(main)
File "/usr/lib/python3.8/curses/__init__.py", line 105, in wrapper
return func(stdscr, *args, **kwds)
File "4-colors.py", line 18, in main
curses.init_pair(40000, 1, 53)
OverflowError: signed short integer is greater than maximum
Sure enough, the implementation of init_color (I hope that I'm looking at the right file) checks whether the color pair number is within bounds of a signed short.
Why? Is there a way to bypass this and use all of the colors of my terminal, not just an arbitrary half?
Full source code of the MWE:
import curses
def main(window):
curses.start_color()
curses.use_default_colors()
curses.init_pair(40000, 1, 53)
curses.wrapper(main)
The problem is that Python's curses binding was not updated to account for the changes made in ncurses 6.1: before that point, capability values (numbers) passed to/from the curses library were limited to a signed 16-bit number. ncurses 6.1 extended that, although to make effective use of things like COLOR_PAIRS
, it is necessary to use one of the function extensions introduced in ncurses 6.1
In the given example, for instance, rather than calling init_pair
, whose C prototype is
int init_pair(short pair, short f, short b);
one would use init_extended_pair
:
int init_extended_pair(int pair, int f, int b);
Of course, it's always been the case that applications are responsible for validating the numbers that they deal with. The example shown illustrates a Python runtime exception (rather than for example limiting the number of color pairs seen by callers).