Skip to main content

Modules/_cursesmodule.c

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c

_cursesmodule.c is the C extension backing Python's curses standard library module. It wraps the system ncurses (or curses) library and exposes screen, window, and color management to Python programs that need direct terminal control. The file is large, roughly 4500 lines, because it provides a nearly complete mapping of the ncurses API surface rather than a thin façade.

The module is structured in two tiers. The top-level functions, exposed on the _curses module object itself, handle global terminal state: initscr initializes the terminal, endwin restores it, newwin allocates sub-windows, and color helpers like start_color and init_pair configure the 256-color or 8-color palette. The second tier lives on PyCursesWindowObject, a heap-allocated Python type that wraps a single WINDOW * pointer and provides per-window methods such as addstr, refresh, getch, move, getyx, and border.

Error handling throughout the file follows a consistent pattern: ncurses functions return ERR on failure, and the module translates that into a _curses.error exception raised through the PyCursesSetupTermCalled guard and PyCursesCheckErr helper. The Clinic-generated argument clinic stubs (.clinic/_cursesmodule.c.h) handle most argument parsing, keeping the method bodies short and focused on the ncurses call and its return value.

Map

LinesSymbolRolegopy
1-120module setup, PyCursesErrorException type and init guards
121-600PyCursesWindowObject type + core methodsaddstr, move, refresh, getch, getyx
601-1200Window drawing methodsborder, box, hline, vline, addch, insch
1201-2000Window attribute + color methodsattrset, bkgd, chgat, color_set
2001-2800Window query methodsgetstr, instr, inch, getbegyx, getmaxyx
2801-3600Top-level module functionsinitscr, endwin, newwin, wrapper
3601-4200Color and key managementstart_color, init_pair, color_pair, has_colors
4201-4500Module init, constants tablePyInit__curses, key/attr constant registration

Reading

Exception setup and init guards (lines 1 to 120)

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c#L1-120

The file opens by defining PyCursesError, the module-level exception subclassing Exception. Two macros gate every public function: PyCursesSetupTermCalled raises error if initscr has not yet been called, and PyCursesInitialised does the same for the top-level module functions. This ensures ncurses is never called before the terminal is initialized, matching the contract ncurses itself requires.

static PyObject *PyCursesError;

#define PyCursesSetupTermCalled(X) \
if (!initialised_setupterm) { \
PyErr_SetString(PyCursesError, \
"must call (at least) setupterm() first"); \
return X; }

PyCursesWindowObject and core window methods (lines 121 to 600)

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c#L121-600

PyCursesWindowObject holds a single WINDOW *win field and an encoding string copied from the locale at window creation. The core methods, addstr, move, refresh, and getch, are defined here. Each method follows the same shape: parse Python arguments with Argument Clinic, call the ncurses function, and return None on success or raise _curses.error on ERR. getch is the only one that returns a meaningful integer value, the character code or a special-key constant.

static PyObject *
PyCurses_window_addstr(PyCursesWindowObject *self, PyObject *args)
{
int rtn;
/* ... argument parsing ... */
rtn = waddnstr(self->win, str, n);
return PyCursesCheckErr(rtn, "addstr");
}

Window drawing and border methods (lines 601 to 1200)

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c#L601-1200

Box-drawing functions border, box, hline, and vline wrap the corresponding ncurses primitives. border accepts up to eight character arguments for the left, right, top, bottom, and four corner cells. When no arguments are given the ncurses default box-drawing characters are used. The attribute helpers addch and insch handle the interaction between Python integer character codes and ncurses chtype, which packs a character and its display attributes into a single wide integer.

static PyObject *
PyCurses_window_border(PyCursesWindowObject *self, PyObject *args)
{
chtype ls=0, rs=0, ts=0, bs=0,
tl=0, tr=0, bl=0, br=0;
if (!PyArg_ParseTuple(args, "|kkkkkkkk;ls,rs,ts,bs,tl,tr,bl,br",
&ls, &rs, &ts, &bs, &tl, &tr, &bl, &br))
return NULL;
return PyCursesCheckErr(wborder(self->win, ls,rs,ts,bs,tl,tr,bl,br),
"border");
}

Top-level module functions (lines 2801 to 3600)

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c#L2801-3600

initscr calls the ncurses initscr() C function, sets the module-level initialised flag, wraps the returned stdscr in a PyCursesWindowObject, and stores it as _curses.initscr_called. endwin is a thin wrapper that clears the initialised flag and calls endwin(). newwin allocates a new WINDOW * via newwin() and returns a fresh Python window object. The Python-level wrapper convenience function is implemented in pure Python in curses/__init__.py, not here.

static PyObject *
PyCurses_InitScr(PyObject *module, PyObject *noargs)
{
WINDOW *win = initscr();
if (win == NULL) {
PyErr_SetString(PyCursesError, catchall_NULL);
return NULL;
}
initialised = TRUE;
return (PyObject *)PyCursesWindow_New(win, NULL);
}

Color management (lines 3601 to 4200)

cpython 3.14 @ ab2d84fe1023/Modules/_cursesmodule.c#L3601-4200

start_color enables terminal color support and must be called after initscr. init_pair(pair, fg, bg) assigns foreground and background color numbers to a color-pair index. color_pair(n) returns the chtype attribute value for pair n, suitable for OR-ing into addstr attribute arguments. has_colors and can_change_color query terminal capabilities. All six functions validate that start_color has been called and that color-pair indices are within the range [0, COLOR_PAIRS-1].

static PyObject *
PyCurses_InitPair(PyObject *module, PyObject *args)
{
short pair, f, b;
if (!PyArg_ParseTuple(args, "hhh;pair, fg, bg", &pair, &f, &b))
return NULL;
if (init_pair(pair, f, b) == ERR)
return PyCursesCheckErr(ERR, "init_pair");
Py_RETURN_NONE;
}

gopy mirror

Not yet ported.