https://github.com/python/cpython/commit/7363e8d24d14abf651633865ea959702ebac73d3
commit: 7363e8d24d14abf651633865ea959702ebac73d3
branch: main
author: Serhiy Storchaka <storch...@gmail.com>
committer: serhiy-storchaka <storch...@gmail.com>
date: 2025-05-03T23:33:22+03:00
summary:

gh-133139: Add curses.assume_default_colors() (GH-133145)

This is a refinement of the curses.use_default_colors() function which
allows to change the color pair 0.

files:
A Misc/NEWS.d/next/Library/2025-04-29-13-40-05.gh-issue-133139.9yCcC2.rst
M Doc/library/curses.rst
M Doc/whatsnew/3.14.rst
M Lib/test/test_curses.py
M Modules/_cursesmodule.c
M Modules/clinic/_cursesmodule.c.h

diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 6c7fc721a3e0fb..4bccfdde664070 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -68,6 +68,21 @@ The module :mod:`curses` defines the following exception:
 The module :mod:`curses` defines the following functions:
 
 
+.. function:: assume_default_colors(fg, bg)
+
+   Allow use of default values for colors on terminals supporting this feature.
+   Use this to support transparency in your application.
+
+   * Assign terminal default foreground/background colors to color number 
``-1``.
+     So ``init_pair(x, COLOR_RED, -1)`` will initialize pair *x* as red
+     on default background and ``init_pair(x, -1, COLOR_BLUE)`` will
+     initialize pair *x* as default foreground on blue.
+
+   * Change the definition of the color-pair ``0`` to ``(fg, bg)``.
+
+   .. versionadded:: next
+
+
 .. function:: baudrate()
 
    Return the output speed of the terminal in bits per second.  On software
@@ -290,9 +305,11 @@ The module :mod:`curses` defines the following functions:
    Change the definition of a color-pair.  It takes three arguments: the 
number of
    the color-pair to be changed, the foreground color number, and the 
background
    color number.  The value of *pair_number* must be between ``1`` and
-   ``COLOR_PAIRS - 1`` (the ``0`` color pair is wired to white on black and 
cannot
-   be changed).  The value of *fg* and *bg* arguments must be between ``0`` and
-   ``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``.
+   ``COLOR_PAIRS - 1`` (the ``0`` color pair can only be changed by
+   :func:`use_default_colors` and :func:`assume_default_colors`).
+   The value of *fg* and *bg* arguments must be between ``0`` and
+   ``COLORS - 1``, or, after calling :func:`!use_default_colors` or
+   :func:`!assume_default_colors`, ``-1``.
    If the color-pair was previously initialized, the screen is
    refreshed and all occurrences of that color-pair are changed to the new
    definition.
@@ -678,11 +695,7 @@ The module :mod:`curses` defines the following functions:
 
 .. function:: use_default_colors()
 
-   Allow use of default values for colors on terminals supporting this 
feature. Use
-   this to support transparency in your application.  The default color is 
assigned
-   to the color number ``-1``. After calling this function,  ``init_pair(x,
-   curses.COLOR_RED, -1)`` initializes, for instance, color pair *x* to a red
-   foreground color on the default background.
+   Equivalent to ``assume_default_colors(-1, -1)``.
 
 
 .. function:: wrapper(func, /, *args, **kwargs)
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 1ebf6efffd0177..87c31d32e2264d 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -891,6 +891,14 @@ ctypes
   making it a :term:`generic type`.
   (Contributed by Brian Schubert in :gh:`132168`.)
 
+curses
+------
+
+* Add the :func:`~curses.assume_default_colors` function,
+  a refinement of the :func:`~curses.use_default_colors` function which
+  allows to change the color pair ``0``.
+  (Contributed by Serhiy Storchaka in :gh:`133139`.)
+
 datetime
 --------
 
diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py
index 6fe0e7fd4b7fe9..3f95a2b322fbb1 100644
--- a/Lib/test/test_curses.py
+++ b/Lib/test/test_curses.py
@@ -51,12 +51,6 @@ def wrapped(self, *args, **kwargs):
 
 term = os.environ.get('TERM')
 SHORT_MAX = 0x7fff
-DEFAULT_PAIR_CONTENTS = [
-    (curses.COLOR_WHITE, curses.COLOR_BLACK),
-    (0, 0),
-    (-1, -1),
-    (15, 0),  # for xterm-256color (15 is for BRIGHT WHITE)
-]
 
 # If newterm was supported we could use it instead of initscr and not exit
 @unittest.skipIf(not term or term == 'unknown',
@@ -948,8 +942,6 @@ def get_pair_limit(self):
 
     @requires_colors
     def test_pair_content(self):
-        if not hasattr(curses, 'use_default_colors'):
-            self.assertIn(curses.pair_content(0), DEFAULT_PAIR_CONTENTS)
         curses.pair_content(0)
         maxpair = self.get_pair_limit() - 1
         if maxpair > 0:
@@ -994,13 +986,27 @@ def test_color_attrs(self):
     @requires_curses_func('use_default_colors')
     @requires_colors
     def test_use_default_colors(self):
-        old = curses.pair_content(0)
         try:
             curses.use_default_colors()
         except curses.error:
             self.skipTest('cannot change color (use_default_colors() failed)')
         self.assertEqual(curses.pair_content(0), (-1, -1))
-        self.assertIn(old, DEFAULT_PAIR_CONTENTS)
+
+    @requires_curses_func('assume_default_colors')
+    @requires_colors
+    def test_assume_default_colors(self):
+        try:
+            curses.assume_default_colors(-1, -1)
+        except curses.error:
+            self.skipTest('cannot change color (assume_default_colors() 
failed)')
+        self.assertEqual(curses.pair_content(0), (-1, -1))
+        curses.assume_default_colors(curses.COLOR_YELLOW, curses.COLOR_BLUE)
+        self.assertEqual(curses.pair_content(0), (curses.COLOR_YELLOW, 
curses.COLOR_BLUE))
+        curses.assume_default_colors(curses.COLOR_RED, -1)
+        self.assertEqual(curses.pair_content(0), (curses.COLOR_RED, -1))
+        curses.assume_default_colors(-1, curses.COLOR_GREEN)
+        self.assertEqual(curses.pair_content(0), (-1, curses.COLOR_GREEN))
+        curses.assume_default_colors(-1, -1)
 
     def test_keyname(self):
         # TODO: key_name()
diff --git 
a/Misc/NEWS.d/next/Library/2025-04-29-13-40-05.gh-issue-133139.9yCcC2.rst 
b/Misc/NEWS.d/next/Library/2025-04-29-13-40-05.gh-issue-133139.9yCcC2.rst
new file mode 100644
index 00000000000000..526187d924b1ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-29-13-40-05.gh-issue-133139.9yCcC2.rst
@@ -0,0 +1,3 @@
+Add the :func:`curses.assume_default_colors` function, a refinement of the
+:func:`curses.use_default_colors` function which allows to change the color
+pair ``0``.
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index bf18cb51605075..f2ddd55dbf3900 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -4720,15 +4720,12 @@ _curses_use_env_impl(PyObject *module, int flag)
 /*[clinic input]
 _curses.use_default_colors
 
-Allow use of default values for colors on terminals supporting this feature.
-
-Use this to support transparency in your application.  The default color
-is assigned to the color number -1.
+Equivalent to assume_default_colors(-1, -1).
 [clinic start generated code]*/
 
 static PyObject *
 _curses_use_default_colors_impl(PyObject *module)
-/*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/
+/*[clinic end generated code: output=a3b81ff71dd901be input=99ff0b7c69834d1f]*/
 {
     int code;
 
@@ -4744,6 +4741,39 @@ _curses_use_default_colors_impl(PyObject *module)
         return NULL;
     }
 }
+
+/*[clinic input]
+_curses.assume_default_colors
+    fg: int
+    bg: int
+    /
+
+Allow use of default values for colors on terminals supporting this feature.
+
+Assign terminal default foreground/background colors to color number -1.
+Change the definition of the color-pair 0 to (fg, bg).
+
+Use this to support transparency in your application.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_assume_default_colors_impl(PyObject *module, int fg, int bg)
+/*[clinic end generated code: output=54985397a7d2b3a5 input=7fe301712ef3e9fb]*/
+{
+    int code;
+
+    PyCursesStatefulInitialised(module);
+    PyCursesStatefulInitialisedColor(module);
+
+    code = assume_default_colors(fg, bg);
+    if (code != ERR) {
+        Py_RETURN_NONE;
+    } else {
+        cursesmodule_state *state = get_cursesmodule_state(module);
+        PyErr_SetString(state->error, "assume_default_colors() returned ERR");
+        return NULL;
+    }
+}
 #endif /* STRICT_SYSV_CURSES */
 
 
@@ -4902,6 +4932,7 @@ static PyMethodDef cursesmodule_methods[] = {
     _CURSES_UNGET_WCH_METHODDEF
     _CURSES_USE_ENV_METHODDEF
     _CURSES_USE_DEFAULT_COLORS_METHODDEF
+    _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
     {NULL,                  NULL}         /* sentinel */
 };
 
diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h
index 3a1c1698b1b8c6..552360eb80a545 100644
--- a/Modules/clinic/_cursesmodule.c.h
+++ b/Modules/clinic/_cursesmodule.c.h
@@ -4263,10 +4263,7 @@ PyDoc_STRVAR(_curses_use_default_colors__doc__,
 "use_default_colors($module, /)\n"
 "--\n"
 "\n"
-"Allow use of default values for colors on terminals supporting this 
feature.\n"
-"\n"
-"Use this to support transparency in your application.  The default color\n"
-"is assigned to the color number -1.");
+"Equivalent to assume_default_colors(-1, -1).");
 
 #define _CURSES_USE_DEFAULT_COLORS_METHODDEF    \
     {"use_default_colors", (PyCFunction)_curses_use_default_colors, 
METH_NOARGS, _curses_use_default_colors__doc__},
@@ -4282,6 +4279,51 @@ _curses_use_default_colors(PyObject *module, PyObject 
*Py_UNUSED(ignored))
 
 #endif /* !defined(STRICT_SYSV_CURSES) */
 
+#if !defined(STRICT_SYSV_CURSES)
+
+PyDoc_STRVAR(_curses_assume_default_colors__doc__,
+"assume_default_colors($module, fg, bg, /)\n"
+"--\n"
+"\n"
+"Allow use of default values for colors on terminals supporting this 
feature.\n"
+"\n"
+"Assign terminal default foreground/background colors to color number -1.\n"
+"Change the definition of the color-pair 0 to (fg, bg).\n"
+"\n"
+"Use this to support transparency in your application.");
+
+#define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF    \
+    {"assume_default_colors", 
_PyCFunction_CAST(_curses_assume_default_colors), METH_FASTCALL, 
_curses_assume_default_colors__doc__},
+
+static PyObject *
+_curses_assume_default_colors_impl(PyObject *module, int fg, int bg);
+
+static PyObject *
+_curses_assume_default_colors(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    int fg;
+    int bg;
+
+    if (!_PyArg_CheckPositional("assume_default_colors", nargs, 2, 2)) {
+        goto exit;
+    }
+    fg = PyLong_AsInt(args[0]);
+    if (fg == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+    bg = PyLong_AsInt(args[1]);
+    if (bg == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+    return_value = _curses_assume_default_colors_impl(module, fg, bg);
+
+exit:
+    return return_value;
+}
+
+#endif /* !defined(STRICT_SYSV_CURSES) */
+
 PyDoc_STRVAR(_curses_has_extended_color_support__doc__,
 "has_extended_color_support($module, /)\n"
 "--\n"
@@ -4394,4 +4436,8 @@ _curses_has_extended_color_support(PyObject *module, 
PyObject *Py_UNUSED(ignored
 #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF
     #define _CURSES_USE_DEFAULT_COLORS_METHODDEF
 #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */
-/*[clinic end generated code: output=dbbbe86a4171799a input=a9049054013a1b77]*/
+
+#ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
+    #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
+#endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */
+/*[clinic end generated code: output=42b2923d88c8d0f6 input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to