From 6bb92f26af6c197b05740766837cb96395995cd9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 18 Jun 2026 13:52:26 +0300 Subject: [PATCH] [3.13] gh-151623: Add missing curses docstrings and document intrflush() (GH-151632) (cherry picked from commit 12add3822f458a3e107dff4176b4c4b991764ea7) --- Doc/library/curses.rst | 7 + Modules/_cursesmodule.c | 217 +++++++++++++++++++++++++------ Modules/clinic/_cursesmodule.c.h | 22 +++- 3 files changed, 200 insertions(+), 46 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 8ed73b58996d6a6..d0a521b6415e7c2 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -314,6 +314,13 @@ The module :mod:`curses` defines the following functions: cause the interpreter to exit. +.. function:: intrflush(flag) + + If *flag* is ``True``, pressing an interrupt key (interrupt, break, or quit) + will flush all output in the terminal driver queue. If *flag* is ``False``, + no flushing is done. + + .. function:: is_term_resized(nlines, ncols) Return ``True`` if :func:`resize_term` would modify the window structure, diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 23a09656a261aad..e365fc6ee9d5c55 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2507,6 +2507,55 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P #include "clinic/_cursesmodule.c.h" +PyDoc_STRVAR(_curses_window_chgat__doc__, +"chgat([y, x,] [n=-1,] attr)\n" +"Set the attributes of characters.\n" +"\n" +" y\n" +" Y-coordinate.\n" +" x\n" +" X-coordinate.\n" +" n\n" +" Number of characters.\n" +" attr\n" +" Attributes for characters.\n" +"\n" +"Set the attributes of num characters at the current cursor position, or at\n" +"position (y, x) if supplied. If no value of num is given or num = -1, the\n" +"attribute will be set on all the characters to the end of the line. This\n" +"function does not move the cursor. The changed line will be touched using\n" +"the touchline() method so that the contents will be redisplayed by the next\n" +"window refresh."); + +PyDoc_STRVAR(_curses_window_getstr__doc__, +"getstr([[y, x,] n=2047])\n" +"Read a string from the user, with primitive line editing capacity.\n" +"\n" +" y\n" +" Y-coordinate.\n" +" x\n" +" X-coordinate.\n" +" n\n" +" Maximal number of characters."); + +PyDoc_STRVAR(_curses_window_instr__doc__, +"instr([y, x,] n=2047)\n" +"Return a string of characters, extracted from the window.\n" +"\n" +" y\n" +" Y-coordinate.\n" +" x\n" +" X-coordinate.\n" +" n\n" +" Maximal number of characters.\n" +"\n" +"Return a string of characters, extracted from the window starting\n" +"at the current cursor position, or at y, x if specified, and\n" +"stopping at the end of the line. Attributes and color\n" +"information are stripped from the characters. If n is specified,\n" +"instr() returns a string at most n characters long (exclusive of\n" +"the trailing NUL)."); + static PyMethodDef PyCursesWindow_Methods[] = { _CURSES_WINDOW_ADDCH_METHODDEF _CURSES_WINDOW_ADDNSTR_METHODDEF @@ -2516,79 +2565,149 @@ static PyMethodDef PyCursesWindow_Methods[] = { _CURSES_WINDOW_ATTRSET_METHODDEF _CURSES_WINDOW_BKGD_METHODDEF #ifdef HAVE_CURSES_WCHGAT - {"chgat", (PyCFunction)PyCursesWindow_ChgAt, METH_VARARGS}, + {"chgat", (PyCFunction)PyCursesWindow_ChgAt, METH_VARARGS, _curses_window_chgat__doc__}, #endif _CURSES_WINDOW_BKGDSET_METHODDEF _CURSES_WINDOW_BORDER_METHODDEF _CURSES_WINDOW_BOX_METHODDEF - {"clear", (PyCFunction)PyCursesWindow_wclear, METH_NOARGS}, - {"clearok", (PyCFunction)PyCursesWindow_clearok, METH_VARARGS}, - {"clrtobot", (PyCFunction)PyCursesWindow_wclrtobot, METH_NOARGS}, - {"clrtoeol", (PyCFunction)PyCursesWindow_wclrtoeol, METH_NOARGS}, - {"cursyncup", (PyCFunction)PyCursesWindow_wcursyncup, METH_NOARGS}, + {"clear", (PyCFunction)PyCursesWindow_wclear, METH_NOARGS, + "clear($self, /)\n--\n\n" + "Clear the window and repaint it completely on the next refresh()."}, + {"clearok", (PyCFunction)PyCursesWindow_clearok, METH_VARARGS, + "clearok($self, flag, /)\n--\n\n" + "Clear the window on the next refresh() if flag is true."}, + {"clrtobot", (PyCFunction)PyCursesWindow_wclrtobot, METH_NOARGS, + "clrtobot($self, /)\n--\n\n" + "Erase from the cursor to the end of the window."}, + {"clrtoeol", (PyCFunction)PyCursesWindow_wclrtoeol, METH_NOARGS, + "clrtoeol($self, /)\n--\n\n" + "Erase from the cursor to the end of the line."}, + {"cursyncup", (PyCFunction)PyCursesWindow_wcursyncup, METH_NOARGS, + "cursyncup($self, /)\n--\n\n" + "Update the cursor position of all ancestor windows to match."}, _CURSES_WINDOW_DELCH_METHODDEF - {"deleteln", (PyCFunction)PyCursesWindow_wdeleteln, METH_NOARGS}, + {"deleteln", (PyCFunction)PyCursesWindow_wdeleteln, METH_NOARGS, + "deleteln($self, /)\n--\n\n" + "Delete the line under the cursor; move following lines up by one."}, _CURSES_WINDOW_DERWIN_METHODDEF _CURSES_WINDOW_ECHOCHAR_METHODDEF _CURSES_WINDOW_ENCLOSE_METHODDEF - {"erase", (PyCFunction)PyCursesWindow_werase, METH_NOARGS}, - {"getbegyx", (PyCFunction)PyCursesWindow_getbegyx, METH_NOARGS}, + {"erase", (PyCFunction)PyCursesWindow_werase, METH_NOARGS, + "erase($self, /)\n--\n\n" + "Clear the window."}, + {"getbegyx", (PyCFunction)PyCursesWindow_getbegyx, METH_NOARGS, + "getbegyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the upper-left corner coordinates."}, _CURSES_WINDOW_GETBKGD_METHODDEF _CURSES_WINDOW_GETCH_METHODDEF _CURSES_WINDOW_GETKEY_METHODDEF _CURSES_WINDOW_GET_WCH_METHODDEF - {"getmaxyx", (PyCFunction)PyCursesWindow_getmaxyx, METH_NOARGS}, - {"getparyx", (PyCFunction)PyCursesWindow_getparyx, METH_NOARGS}, - {"getstr", (PyCFunction)PyCursesWindow_GetStr, METH_VARARGS}, - {"getyx", (PyCFunction)PyCursesWindow_getyx, METH_NOARGS}, + {"getmaxyx", (PyCFunction)PyCursesWindow_getmaxyx, METH_NOARGS, + "getmaxyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the window height and width."}, + {"getparyx", (PyCFunction)PyCursesWindow_getparyx, METH_NOARGS, + "getparyx($self, /)\n--\n\n" + "Return (y, x) relative to the parent window, or (-1, -1) if none."}, + {"getstr", (PyCFunction)PyCursesWindow_GetStr, METH_VARARGS, _curses_window_getstr__doc__}, + {"getyx", (PyCFunction)PyCursesWindow_getyx, METH_NOARGS, + "getyx($self, /)\n--\n\n" + "Return a tuple (y, x) of the current cursor position."}, _CURSES_WINDOW_HLINE_METHODDEF - {"idcok", (PyCFunction)PyCursesWindow_idcok, METH_VARARGS}, - {"idlok", (PyCFunction)PyCursesWindow_idlok, METH_VARARGS}, + {"idcok", (PyCFunction)PyCursesWindow_idcok, METH_VARARGS, + "idcok($self, flag, /)\n--\n\n" + "Enable or disable the hardware insert/delete character feature."}, + {"idlok", (PyCFunction)PyCursesWindow_idlok, METH_VARARGS, + "idlok($self, flag, /)\n--\n\n" + "Enable or disable the hardware insert/delete line feature."}, #ifdef HAVE_CURSES_IMMEDOK - {"immedok", (PyCFunction)PyCursesWindow_immedok, METH_VARARGS}, + {"immedok", (PyCFunction)PyCursesWindow_immedok, METH_VARARGS, + "immedok($self, flag, /)\n--\n\n" + "If flag is true, refresh the window on every change to it."}, #endif _CURSES_WINDOW_INCH_METHODDEF _CURSES_WINDOW_INSCH_METHODDEF - {"insdelln", (PyCFunction)PyCursesWindow_winsdelln, METH_VARARGS}, - {"insertln", (PyCFunction)PyCursesWindow_winsertln, METH_NOARGS}, + {"insdelln", (PyCFunction)PyCursesWindow_winsdelln, METH_VARARGS, + "insdelln($self, nlines, /)\n--\n\n" + "Insert (nlines > 0) or delete (nlines < 0) lines above the cursor."}, + {"insertln", (PyCFunction)PyCursesWindow_winsertln, METH_NOARGS, + "insertln($self, /)\n--\n\n" + "Insert a blank line under the cursor; move following lines down."}, _CURSES_WINDOW_INSNSTR_METHODDEF _CURSES_WINDOW_INSSTR_METHODDEF - {"instr", (PyCFunction)PyCursesWindow_InStr, METH_VARARGS}, + {"instr", (PyCFunction)PyCursesWindow_InStr, METH_VARARGS, _curses_window_instr__doc__}, _CURSES_WINDOW_IS_LINETOUCHED_METHODDEF - {"is_wintouched", (PyCFunction)PyCursesWindow_is_wintouched, METH_NOARGS}, - {"keypad", (PyCFunction)PyCursesWindow_keypad, METH_VARARGS}, - {"leaveok", (PyCFunction)PyCursesWindow_leaveok, METH_VARARGS}, - {"move", (PyCFunction)PyCursesWindow_wmove, METH_VARARGS}, - {"mvderwin", (PyCFunction)PyCursesWindow_mvderwin, METH_VARARGS}, - {"mvwin", (PyCFunction)PyCursesWindow_mvwin, METH_VARARGS}, - {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS}, - {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS}, + {"is_wintouched", (PyCFunction)PyCursesWindow_is_wintouched, METH_NOARGS, + "is_wintouched($self, /)\n--\n\n" + "Return True if the window changed since the last refresh()."}, + {"keypad", (PyCFunction)PyCursesWindow_keypad, METH_VARARGS, + "keypad($self, flag, /)\n--\n\n" + "Interpret escape sequences for special keys if flag is true."}, + {"leaveok", (PyCFunction)PyCursesWindow_leaveok, METH_VARARGS, + "leaveok($self, flag, /)\n--\n\n" + "If flag is true, leave the cursor where the update leaves it."}, + {"move", (PyCFunction)PyCursesWindow_wmove, METH_VARARGS, + "move($self, new_y, new_x, /)\n--\n\n" + "Move the cursor to (new_y, new_x)."}, + {"mvderwin", (PyCFunction)PyCursesWindow_mvderwin, METH_VARARGS, + "mvderwin($self, y, x, /)\n--\n\n" + "Move the window inside its parent window."}, + {"mvwin", (PyCFunction)PyCursesWindow_mvwin, METH_VARARGS, + "mvwin($self, new_y, new_x, /)\n--\n\n" + "Move the window so its upper-left corner is at (new_y, new_x)."}, + {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS, + "nodelay($self, flag, /)\n--\n\n" + "If flag is true, getch() becomes non-blocking."}, + {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS, + "notimeout($self, flag, /)\n--\n\n" + "If flag is true, do not time out escape sequences."}, _CURSES_WINDOW_NOUTREFRESH_METHODDEF _CURSES_WINDOW_OVERLAY_METHODDEF _CURSES_WINDOW_OVERWRITE_METHODDEF _CURSES_WINDOW_PUTWIN_METHODDEF _CURSES_WINDOW_REDRAWLN_METHODDEF - {"redrawwin", (PyCFunction)PyCursesWindow_redrawwin, METH_NOARGS}, + {"redrawwin", (PyCFunction)PyCursesWindow_redrawwin, METH_NOARGS, + "redrawwin($self, /)\n--\n\n" + "Mark the entire window for redraw on the next refresh()."}, _CURSES_WINDOW_REFRESH_METHODDEF #ifndef STRICT_SYSV_CURSES - {"resize", (PyCFunction)PyCursesWindow_wresize, METH_VARARGS}, + {"resize", (PyCFunction)PyCursesWindow_wresize, METH_VARARGS, + "resize($self, nlines, ncols, /)\n--\n\n" + "Resize the window to nlines rows and ncols columns."}, #endif _CURSES_WINDOW_SCROLL_METHODDEF - {"scrollok", (PyCFunction)PyCursesWindow_scrollok, METH_VARARGS}, + {"scrollok", (PyCFunction)PyCursesWindow_scrollok, METH_VARARGS, + "scrollok($self, flag, /)\n--\n\n" + "Control whether the window scrolls when the cursor moves off it."}, _CURSES_WINDOW_SETSCRREG_METHODDEF - {"standend", (PyCFunction)PyCursesWindow_wstandend, METH_NOARGS}, - {"standout", (PyCFunction)PyCursesWindow_wstandout, METH_NOARGS}, - {"subpad", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + {"standend", (PyCFunction)PyCursesWindow_wstandend, METH_NOARGS, + "standend($self, /)\n--\n\n" + "Turn off the standout attribute."}, + {"standout", (PyCFunction)PyCursesWindow_wstandout, METH_NOARGS, + "standout($self, /)\n--\n\n" + "Turn on the A_STANDOUT attribute."}, + {"subpad", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, _CURSES_WINDOW_SUBWIN_METHODDEF - {"syncdown", (PyCFunction)PyCursesWindow_wsyncdown, METH_NOARGS}, + {"syncdown", (PyCFunction)PyCursesWindow_wsyncdown, METH_NOARGS, + "syncdown($self, /)\n--\n\n" + "Touch each location changed in any ancestor of the window."}, #ifdef HAVE_CURSES_SYNCOK - {"syncok", (PyCFunction)PyCursesWindow_syncok, METH_VARARGS}, + {"syncok", (PyCFunction)PyCursesWindow_syncok, METH_VARARGS, + "syncok($self, flag, /)\n--\n\n" + "If flag is true, call syncup() on every change to the window."}, #endif - {"syncup", (PyCFunction)PyCursesWindow_wsyncup, METH_NOARGS}, - {"timeout", (PyCFunction)PyCursesWindow_wtimeout, METH_VARARGS}, + {"syncup", (PyCFunction)PyCursesWindow_wsyncup, METH_NOARGS, + "syncup($self, /)\n--\n\n" + "Touch locations in ancestors that changed in this window."}, + {"timeout", (PyCFunction)PyCursesWindow_wtimeout, METH_VARARGS, + "timeout($self, delay, /)\n--\n\n" + "Set blocking or non-blocking read behavior for the window."}, _CURSES_WINDOW_TOUCHLINE_METHODDEF - {"touchwin", (PyCFunction)PyCursesWindow_touchwin, METH_NOARGS}, - {"untouchwin", (PyCFunction)PyCursesWindow_untouchwin, METH_NOARGS}, + {"touchwin", (PyCFunction)PyCursesWindow_touchwin, METH_NOARGS, + "touchwin($self, /)\n--\n\n" + "Mark the whole window as changed."}, + {"untouchwin", (PyCFunction)PyCursesWindow_untouchwin, METH_NOARGS, + "untouchwin($self, /)\n--\n\n" + "Mark all lines in the window as unchanged since last refresh()."}, _CURSES_WINDOW_VLINE_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -2689,11 +2808,17 @@ PyTypeObject PyCursesWindow_Type = { /*[clinic input] _curses.filter +Restrict screen updates to the current line. + +Must be called before initscr(). Afterwards curses confines the cursor +and screen updates to a single line, which is useful for enabling +character-at-a-time line editing without touching the rest of the +screen. [clinic start generated code]*/ static PyObject * _curses_filter_impl(PyObject *module) -/*[clinic end generated code: output=fb5b8a3642eb70b5 input=668c75a6992d3624]*/ +/*[clinic end generated code: output=fb5b8a3642eb70b5 input=e3c64d6ab2106132]*/ { /* not checking for PyCursesInitialised here since filter() must be called before initscr() */ @@ -3575,11 +3700,16 @@ _curses.intrflush flag: bool / +Control flushing of the output buffer when an interrupt key is pressed. + +If flag is true, pressing an interrupt key (interrupt, break, or quit) +flushes all output in the terminal driver queue. If flag is false, no +flushing is done. [clinic start generated code]*/ static PyObject * _curses_intrflush_impl(PyObject *module, int flag) -/*[clinic end generated code: output=c1986df35e999a0f input=c65fe2ef973fe40a]*/ +/*[clinic end generated code: output=c1986df35e999a0f input=66588c2bccc7e8fa]*/ { PyCursesInitialised; @@ -4081,11 +4211,14 @@ update_lines_cols(void) /*[clinic input] _curses.update_lines_cols +Update the LINES and COLS module variables. + +This is useful for detecting manual screen resize. [clinic start generated code]*/ static PyObject * _curses_update_lines_cols_impl(PyObject *module) -/*[clinic end generated code: output=423f2b1e63ed0f75 input=5f065ab7a28a5d90]*/ +/*[clinic end generated code: output=423f2b1e63ed0f75 input=1d8ea7c356b61a8b]*/ { if (!update_lines_cols()) { return NULL; diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index b7a2551ff2028c1..6f7fe9c3708136f 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1846,7 +1846,13 @@ _curses_window_vline(PyCursesWindowObject *self, PyObject *args) PyDoc_STRVAR(_curses_filter__doc__, "filter($module, /)\n" "--\n" -"\n"); +"\n" +"Restrict screen updates to the current line.\n" +"\n" +"Must be called before initscr(). Afterwards curses confines the cursor\n" +"and screen updates to a single line, which is useful for enabling\n" +"character-at-a-time line editing without touching the rest of the\n" +"screen."); #define _CURSES_FILTER_METHODDEF \ {"filter", (PyCFunction)_curses_filter, METH_NOARGS, _curses_filter__doc__}, @@ -2901,7 +2907,12 @@ _curses_set_tabsize(PyObject *module, PyObject *arg) PyDoc_STRVAR(_curses_intrflush__doc__, "intrflush($module, flag, /)\n" "--\n" -"\n"); +"\n" +"Control flushing of the output buffer when an interrupt key is pressed.\n" +"\n" +"If flag is true, pressing an interrupt key (interrupt, break, or quit)\n" +"flushes all output in the terminal driver queue. If flag is false, no\n" +"flushing is done."); #define _CURSES_INTRFLUSH_METHODDEF \ {"intrflush", (PyCFunction)_curses_intrflush, METH_O, _curses_intrflush__doc__}, @@ -3577,7 +3588,10 @@ _curses_qiflush(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(_curses_update_lines_cols__doc__, "update_lines_cols($module, /)\n" "--\n" -"\n"); +"\n" +"Update the LINES and COLS module variables.\n" +"\n" +"This is useful for detecting manual screen resize."); #define _CURSES_UPDATE_LINES_COLS_METHODDEF \ {"update_lines_cols", (PyCFunction)_curses_update_lines_cols, METH_NOARGS, _curses_update_lines_cols__doc__}, @@ -4395,4 +4409,4 @@ _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=28bf3e5445c762b4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=80ed45ba69ca7654 input=a9049054013a1b77]*/