1

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)
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Tomáš Sláma
  • 122
  • 3
  • 8
  • I agree that you've found a legitimate bug here - but I fail to see any real-world impact from the bug. Your screen is certainly not displaying 32768 characters at the same time; you could assign a separate color pair to each character on the screen, so you aren't actually being limited in any way. – jasonharper Jul 13 '20 at 13:06
  • I am, since I would like to use all of the `256^2` of foreground-background color combinations. I realize that one could dynamically map currently unused pairs numbers, but that would be such a pain to program... – Tomáš Sláma Jul 13 '20 at 13:55

1 Answers1

2

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).

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • Oh, I see. Thanks for the answer! Do you think that there would be a way to do this from Python, or do I just have to wait for the bindings to get updated? – Tomáš Sláma Jul 14 '20 at 19:47
  • You might wait a while (opening a bug report might get some action). It involves adding/modifying code (see [this example](https://stackoverflow.com/questions/16647186/calling-c-functions-in-python)). – Thomas Dickey Jul 14 '20 at 19:55