From 03fc9c5b44f95aabd74978a14684de4c6538afd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:18:02 +0200 Subject: [PATCH 01/25] improve `curses.error` object --- Lib/test/test_curses.py | 35 ++++ Modules/_cursesmodule.c | 275 +++++++++++++++++++++++++++---- Modules/clinic/_cursesmodule.c.h | 48 +++++- 3 files changed, 322 insertions(+), 36 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index cc3aa561cd4c42..f767335c7b13ca 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -129,6 +129,41 @@ def test_use_env(self): curses.use_env(False) curses.use_env(True) + def test_error(self): + self.assertTrue(issubclass(curses.error, Exception)) + + def raise_curses_error(*args): + raise curses.error(*args) + + with self.assertRaisesRegex(curses.error, "test") as cm: + raise_curses_error('test') + self.assertSequenceEqual(cm.exception.args, ('test',)) + + with self.assertRaisesRegex(curses.error, "test") as cm: + raise_curses_error('test', '1', '2') + self.assertSequenceEqual(cm.exception.args, ('test', '1', '2')) + + def test_error_attributes(self): + error = curses.error() + self.assertSequenceEqual(error.args, ()) + self.assertIsNone(error.funcname) + + error = curses.error('test') + self.assertSequenceEqual(error.args, ('test',)) + self.assertIsNone(error.funcname) + + error = curses.error('test with curses function') + error.funcname = 'curses function' + self.assertSequenceEqual(error.args, ('test with curses function',)) + self.assertEqual(error.funcname, 'curses function') + + error = curses.error('unset attributes') + error.funcname = 'a' + error.funcname = None + self.assertIsNone(error.funcname) + + self.assertRaises(TypeError, setattr, error, 'funcname', 1) + def test_create_windows(self): win = curses.newwin(5, 10) self.assertEqual(win.getbegyx(), (0, 0)) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 27d5df08de933e..b2ec1a00b1f6ac 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -190,8 +190,9 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *win) /*[clinic input] module _curses class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" +class _curses.error "PyCursesErrorObject *" "clinic_state()->error" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a6b4ac3824e7c5c3]*/ /* Indicate whether the module has already been loaded or not. */ static int curses_module_loaded = 0; @@ -207,6 +208,174 @@ static int curses_start_color_called = FALSE; static const char *curses_screen_encoding = NULL; +/* Error type */ + +#define CURSES_ERROR_FORMAT "%s() returned ERR" +#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" + +typedef struct { + PyException_HEAD + PyObject *funcname; // the curses function responsible for the error +} PyCursesErrorObject; + +#define _PyCursesErrorObject_CAST(PTR) ((PyCursesErrorObject *)(PTR)) + +static int +PyCursesError_clear(PyObject *self) +{ + PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self); + Py_CLEAR(exc->funcname); + return _PyType_CAST(PyExc_Exception)->tp_clear(self); +} + +static void +PyCursesError_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)PyCursesError_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static int +PyCursesError_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self); + Py_VISIT(exc->funcname); + return _PyType_CAST(PyExc_Exception)->tp_traverse(self, visit, arg); +} + +/*[clinic input] +@getter +_curses.error.funcname +[clinic start generated code]*/ + +static PyObject * +_curses_error_funcname_get_impl(PyCursesErrorObject *self) +/*[clinic end generated code: output=bddac78d045d9e92 input=a0ed7b814bba25e9]*/ +{ + PyObject *res = self->funcname; + return res == NULL ? Py_None : Py_NewRef(res); +} + +/*[clinic input] +@setter +_curses.error.funcname +[clinic start generated code]*/ + +static int +_curses_error_funcname_set_impl(PyCursesErrorObject *self, PyObject *value) +/*[clinic end generated code: output=1320e03bf8c27ca8 input=e7ad8f11456a402e]*/ +{ + if (PyUnicode_Check(value) || Py_IsNone(value)) { + Py_XSETREF(self->funcname, Py_NewRef(value)); + return 0; + } + PyErr_Format(PyExc_TypeError, "expecting a str or None, got %T", value); + return -1; +} + +/* Utility Error Procedures */ + +static inline void +PyCursesError_SetImplementation( +#ifndef NDEBUG + cursesmodule_state *state, +#else + cursesmodule_state *Py_UNUSED(state), +#endif + const char *funcname) +{ + assert(funcname != NULL); + PyObject *exc = PyErr_GetRaisedException(); + assert(PyErr_GivenExceptionMatches(exc, state->error)); + PyObject *p_funcname = PyUnicode_FromString(funcname); + if (p_funcname == NULL) { + goto error; + } + int rc = PyObject_SetAttrString(exc, "funcname", p_funcname); + Py_DECREF(p_funcname); + if (rc < 0) { + goto error; + } + +restore: + PyErr_SetRaisedException(exc); + return; + +error: + // The curses exception is likely more important than the + // exceptions that we get if we fail to set the attribute. + PyErr_Clear(); + goto restore; +} + +/* + * Format a curses error. + * + * The function name in the error message is 'simple_funcname'. + * If 'simple_funcname' is NULL, it falls back 'curses_funcname'. + */ +static void +_PyCursesSetError(cursesmodule_state *state, + const char *simple_funcname, + const char *curses_funcname) +{ + assert(!PyErr_Occurred()); + if (simple_funcname == NULL && curses_funcname == NULL) { + PyErr_SetString(state->error, catchall_ERR); + return; + } + if (simple_funcname == NULL) { + simple_funcname = curses_funcname; + } + PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); + PyCursesError_SetImplementation(state, curses_funcname); +} + +static void +PyCursesSetError_From(PyObject *, const char *, const char *); + +/* + * Format a curses error using 'funcname' as the displayed + * function name and underlying curses function name. + */ +static inline void +PyCursesSetError(PyObject *module, const char *funcname) +{ + PyCursesSetError_From(module, funcname, funcname); +} + +static void +PyCursesSetError_From(PyObject *module, + const char *simple_funcname, + const char *curses_funcname) +{ + cursesmodule_state *state = get_cursesmodule_state(module); + _PyCursesSetError(state, simple_funcname, curses_funcname); +} + +static void +PyCursesSetError_ForWin_From(PyCursesWindowObject *, + const char *, const char *); + +static inline void +PyCursesSetError_ForWin(PyCursesWindowObject *win, const char *funcname) +{ + PyCursesSetError_ForWin_From(win, funcname, funcname); +} + +static void +PyCursesSetError_ForWin_From(PyCursesWindowObject *win, + const char *simple_funcname, + const char *curses_funcname) +{ + cursesmodule_state *state = get_cursesmodule_state_by_win(win); + _PyCursesSetError(state, simple_funcname, curses_funcname); +} + /* Utility Checking Procedures */ /* @@ -283,44 +452,52 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam /* Utility Functions */ -static inline void -_PyCursesSetError(cursesmodule_state *state, const char *funcname) -{ - if (funcname == NULL) { - PyErr_SetString(state->error, catchall_ERR); - } - else { - PyErr_Format(state->error, "%s() returned ERR", funcname); - } -} - /* - * Check the return code from a curses function and return None - * or raise an exception as appropriate. + * Check the return code from a curses function, returning None + * on success and setting an exception on error. */ +static PyObject *PyCursesCheckERR_From(PyObject *, int, + const char *, const char *); + +static inline PyObject * +PyCursesCheckERR(PyObject *module, int code, const char *funcname) +{ + return PyCursesCheckERR_From(module, code, funcname, funcname); +} + static PyObject * -PyCursesCheckERR(PyObject *module, int code, const char *fname) +PyCursesCheckERR_From(PyObject *module, int code, + const char *simple_funcname, + const char *curses_funcname) { if (code != ERR) { Py_RETURN_NONE; - } else { - cursesmodule_state *state = get_cursesmodule_state(module); - _PyCursesSetError(state, fname); - return NULL; } + PyCursesSetError_From(module, simple_funcname, curses_funcname); + return NULL; +} + +static PyObject *PyCursesCheckERR_ForWin_From(PyCursesWindowObject *, int, + const char *, const char *); + +static inline PyObject * +PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, + const char *funcname) +{ + return PyCursesCheckERR_ForWin_From(win, code, funcname, funcname); } static PyObject * -PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, const char *fname) +PyCursesCheckERR_ForWin_From(PyCursesWindowObject *win, int code, + const char *simple_funcname, + const char *curses_funcname) { if (code != ERR) { Py_RETURN_NONE; - } else { - cursesmodule_state *state = get_cursesmodule_state_by_win(win); - _PyCursesSetError(state, fname); - return NULL; } + PyCursesSetError_ForWin_From(win, simple_funcname, curses_funcname); + return NULL; } /* Convert an object to a byte (an integer of type chtype): @@ -2598,6 +2775,29 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P #include "clinic/_cursesmodule.c.h" #undef clinic_state +static PyGetSetDef PyCursesError_Type_getsets[] = { + _CURSES_ERROR_FUNCNAME_GETSETDEF + {NULL} +}; + +static PyType_Slot PyCursesError_Type_slots[] = { + {Py_tp_getset, PyCursesError_Type_getsets}, + {Py_tp_dealloc, PyCursesError_dealloc}, + {Py_tp_traverse, PyCursesError_traverse}, + {Py_tp_clear, PyCursesError_clear}, + {0, NULL}, +}; + +static PyType_Spec PyCursesError_Type_spec = { + .name = "_curses.error", + .basicsize = sizeof(PyCursesErrorObject), + .flags = Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HAVE_GC, + .slots = PyCursesError_Type_slots, +}; + static PyMethodDef PyCursesWindow_methods[] = { _CURSES_WINDOW_ADDCH_METHODDEF _CURSES_WINDOW_ADDNSTR_METHODDEF @@ -4990,7 +5190,22 @@ cursesmodule_exec(PyObject *module) curses_module_loaded = 1; cursesmodule_state *state = get_cursesmodule_state(module); - /* Initialize object type */ + /* Initialize error type */ + PyObject *bases = PyTuple_Pack(1, PyExc_Exception); + if (bases == NULL) { + return -1; + } + state->error = PyType_FromModuleAndSpec(module, &PyCursesError_Type_spec, + bases); + Py_DECREF(bases); + if (state->error == NULL) { + return -1; + } + if (PyModule_AddType(module, _PyType_CAST(state->error)) < 0) { + return -1; + } + + /* Initialize window type */ state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( module, &PyCursesWindow_Type_spec, NULL); if (state->window_type == NULL) { @@ -5023,16 +5238,6 @@ cursesmodule_exec(PyObject *module) return -1; } - /* For exception curses.error */ - state->error = PyErr_NewException("_curses.error", NULL, NULL); - if (state->error == NULL) { - return -1; - } - rc = PyDict_SetItemString(module_dict, "error", state->error); - if (rc < 0) { - return -1; - } - /* Make the version available */ PyObject *curses_version = PyBytes_FromString(PyCursesVersion); if (curses_version == NULL) { diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 8399c5620f125b..bdce1d6475ca61 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -8,6 +8,52 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_CheckPositional() +#if defined(_curses_error_funcname_HAS_DOCSTR) +# define _curses_error_funcname_DOCSTR _curses_error_funcname__doc__ +#else +# define _curses_error_funcname_DOCSTR NULL +#endif +#if defined(_CURSES_ERROR_FUNCNAME_GETSETDEF) +# undef _CURSES_ERROR_FUNCNAME_GETSETDEF +# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, (setter)_curses_error_funcname_set, _curses_error_funcname_DOCSTR}, +#else +# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, NULL, _curses_error_funcname_DOCSTR}, +#endif + +static PyObject * +_curses_error_funcname_get_impl(PyCursesErrorObject *self); + +static PyObject * +_curses_error_funcname_get(PyCursesErrorObject *self, void *Py_UNUSED(context)) +{ + return _curses_error_funcname_get_impl(self); +} + +#if defined(_CURSES_ERROR_FUNCNAME_HAS_DOCSTR) +# define _curses_error_funcname_DOCSTR _curses_error_funcname__doc__ +#else +# define _curses_error_funcname_DOCSTR NULL +#endif +#if defined(_CURSES_ERROR_FUNCNAME_GETSETDEF) +# undef _CURSES_ERROR_FUNCNAME_GETSETDEF +# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, (setter)_curses_error_funcname_set, _curses_error_funcname_DOCSTR}, +#else +# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", NULL, (setter)_curses_error_funcname_set, NULL}, +#endif + +static int +_curses_error_funcname_set_impl(PyCursesErrorObject *self, PyObject *value); + +static int +_curses_error_funcname_set(PyCursesErrorObject *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + return_value = _curses_error_funcname_set_impl(self, value); + + return return_value; +} + PyDoc_STRVAR(_curses_window_addch__doc__, "addch([y, x,] ch, [attr=_curses.A_NORMAL])\n" "Paint the character.\n" @@ -4378,4 +4424,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=cd1273354b08948f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9e369cce0678b4a3 input=a9049054013a1b77]*/ From 3436f9b467ed6ee86e4f8bc99cd0760cec3e1163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:58:39 +0200 Subject: [PATCH 02/25] update error messages --- Modules/_cursesmodule.c | 436 +++++++++++++++++++++++++--------------- 1 file changed, 272 insertions(+), 164 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index b2ec1a00b1f6ac..88bf969b98c44f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -210,12 +210,14 @@ static const char *curses_screen_encoding = NULL; /* Error type */ -#define CURSES_ERROR_FORMAT "%s() returned ERR" -#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" +#define CURSES_ERROR_FORMAT "%s() returned ERR" +#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" +#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first" typedef struct { PyException_HEAD - PyObject *funcname; // the curses function responsible for the error + /* The name of the curses function that triggered the error. */ + PyObject *funcname; } PyCursesErrorObject; #define _PyCursesErrorObject_CAST(PTR) ((PyCursesErrorObject *)(PTR)) @@ -395,7 +397,7 @@ _PyCursesCheckFunction(int called, const char *funcname) } PyObject *exc = _PyImport_GetModuleAttrString("_curses", "error"); if (exc != NULL) { - PyErr_Format(exc, "must call %s() first", funcname); + PyErr_Format(exc, CURSES_ERROR_MUST_CALL_FORMAT, funcname); Py_DECREF(exc); } assert(PyErr_Occurred()); @@ -416,7 +418,7 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam return 1; } cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, "must call %s() first", funcname); + PyErr_Format(state->error, CURSES_ERROR_MUST_CALL_FORMAT, funcname); return 0; } @@ -1038,18 +1040,21 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, wchar_t wstr[2]; cchar_t wcval; #endif - const char *funcname; + const char *simple_funcname, *curses_funcname; #ifdef HAVE_NCURSESW type = PyCurses_ConvertToCchar_t(self, ch, &cch, wstr); if (type == 2) { - funcname = "add_wch"; + simple_funcname = "add_wch"; wstr[1] = L'\0'; setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL); - if (coordinates_group) - rtn = mvwadd_wch(self->win,y,x, &wcval); + if (coordinates_group) { + rtn = mvwadd_wch(self->win, y, x, &wcval); + curses_funcname = "mvwadd_wch"; + } else { rtn = wadd_wch(self->win, &wcval); + curses_funcname = "wadd_wch"; } } else @@ -1057,17 +1062,22 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, type = PyCurses_ConvertToCchar_t(self, ch, &cch); #endif if (type == 1) { - funcname = "addch"; - if (coordinates_group) - rtn = mvwaddch(self->win,y,x, cch | (attr_t) attr); + simple_funcname = "addch"; + if (coordinates_group) { + rtn = mvwaddch(self->win, y, x, cch | (attr_t) attr); + curses_funcname = "mvwaddch"; + } else { rtn = waddch(self->win, cch | (attr_t) attr); + curses_funcname = "waddch"; } } else { return NULL; } - return PyCursesCheckERR_ForWin(self, rtn, funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, + simple_funcname, + curses_funcname); } /*[clinic input] @@ -1111,7 +1121,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *funcname; + const char *simple_funcname, *curses_funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); @@ -1121,33 +1131,45 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 0) { return NULL; } + if (use_attr) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); } #ifdef HAVE_NCURSESW if (strtype == 2) { - funcname = "addwstr"; - if (use_xy) - rtn = mvwaddwstr(self->win,y,x,wstr); - else - rtn = waddwstr(self->win,wstr); + simple_funcname = "addwstr"; + if (use_xy) { + rtn = mvwaddwstr(self->win, y, x, wstr); + curses_funcname = "mvwaddwstr"; + } + else { + rtn = waddwstr(self->win, wstr); + curses_funcname = "waddwstr"; + } PyMem_Free(wstr); } else #endif { - const char *str = PyBytes_AS_STRING(bytesobj); - funcname = "addstr"; - if (use_xy) - rtn = mvwaddstr(self->win,y,x,str); - else - rtn = waddstr(self->win,str); + const char *text = PyBytes_AS_STRING(bytesobj); + simple_funcname = "addstr"; + if (use_xy) { + rtn = mvwaddstr(self->win, y, x, text); + curses_funcname = "mvwaddstr"; + } + else { + rtn = waddstr(self->win, text); + curses_funcname = "waddstr"; + } Py_DECREF(bytesobj); } - if (use_attr) - (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin(self, rtn, funcname); + if (use_attr) { + (void)wattrset(self->win, attr_old); + } + return PyCursesCheckERR_ForWin_From(self, rtn, + simple_funcname, + curses_funcname); } /*[clinic input] @@ -1194,15 +1216,16 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *funcname; + const char *simple_funcname, *curses_funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) + if (strtype == 0) { return NULL; + } if (use_attr) { attr_old = getattrs(self->win); @@ -1210,27 +1233,38 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - funcname = "addnwstr"; - if (use_xy) - rtn = mvwaddnwstr(self->win,y,x,wstr,n); - else - rtn = waddnwstr(self->win,wstr,n); + simple_funcname = "addnwstr"; + if (use_xy) { + rtn = mvwaddnwstr(self->win, y, x, wstr, n); + curses_funcname = "mvwaddnwstr"; + } + else { + rtn = waddnwstr(self->win, wstr, n); + curses_funcname = "waddnwstr"; + } PyMem_Free(wstr); } else #endif { const char *str = PyBytes_AS_STRING(bytesobj); - funcname = "addnstr"; - if (use_xy) - rtn = mvwaddnstr(self->win,y,x,str,n); - else - rtn = waddnstr(self->win,str,n); + simple_funcname = "addnstr"; + if (use_xy) { + rtn = mvwaddnstr(self->win, y, x, str, n); + curses_funcname = "mvwaddnstr"; + } + else { + rtn = waddnstr(self->win, str, n); + curses_funcname = "waddnstr"; + } Py_DECREF(bytesobj); } - if (use_attr) + if (use_attr) { (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin(self, rtn, funcname); + } + return PyCursesCheckERR_ForWin_From(self, rtn, + simple_funcname, + curses_funcname); } /*[clinic input] @@ -1251,10 +1285,12 @@ _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr) { chtype bkgd; - if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) + if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) { return NULL; + } - return PyCursesCheckERR_ForWin(self, wbkgd(self->win, bkgd | attr), "bkgd"); + int rtn = wbkgd(self->win, bkgd | attr); + return PyCursesCheckERR_ForWin_From(self, rtn, "bkgd", "wbkgd"); } /*[clinic input] @@ -1270,7 +1306,8 @@ static PyObject * _curses_window_attroff_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=8a2fcd4df682fc64 input=786beedf06a7befe]*/ { - return PyCursesCheckERR_ForWin(self, wattroff(self->win, (attr_t)attr), "attroff"); + int rtn = wattroff(self->win, (attr_t)attr); + return PyCursesCheckERR_ForWin_From(self, rtn, "attroff", "wattroff"); } /*[clinic input] @@ -1286,7 +1323,8 @@ static PyObject * _curses_window_attron_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=7afea43b237fa870 input=5a88fba7b1524f32]*/ { - return PyCursesCheckERR_ForWin(self, wattron(self->win, (attr_t)attr), "attron"); + int rtn = wattron(self->win, (attr_t)attr); + return PyCursesCheckERR_ForWin_From(self, rtn, "attron", "wattron"); } /*[clinic input] @@ -1302,7 +1340,8 @@ static PyObject * _curses_window_attrset_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=84e379bff20c0433 input=42e400c0d0154ab5]*/ { - return PyCursesCheckERR_ForWin(self, wattrset(self->win, (attr_t)attr), "attrset"); + int rtn = wattrset(self->win, (attr_t)attr); + return PyCursesCheckERR_ForWin_From(self, rtn, "attrset", "wattrset"); } /*[clinic input] @@ -1324,11 +1363,12 @@ _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, { chtype bkgd; - if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) + if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) { return NULL; + } wbkgdset(self->win, bkgd | attr); - return PyCursesCheckERR_ForWin(self, 0, "bkgdset"); + Py_RETURN_NONE; } /*[clinic input] @@ -1426,7 +1466,7 @@ _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, return NULL; } } - box(self->win,ch1,ch2); + (void)box(self->win, ch1, ch2); Py_RETURN_NONE; } @@ -1482,6 +1522,7 @@ static PyObject * PyCursesWindow_ChgAt(PyCursesWindowObject *self, PyObject *args) { int rtn; + const char *curses_funcname; int x, y; int num = -1; short color; @@ -1521,14 +1562,17 @@ PyCursesWindow_ChgAt(PyCursesWindowObject *self, PyObject *args) attr = attr & A_ATTRIBUTES; if (use_xy) { - rtn = mvwchgat(self->win,y,x,num,attr,color,NULL); - touchline(self->win,y,1); - } else { - getyx(self->win,y,x); - rtn = wchgat(self->win,num,attr,color,NULL); - touchline(self->win,y,1); + rtn = mvwchgat(self->win, y, x, num, attr, color, NULL); + curses_funcname = "mvwchgat"; + (void)touchline(self->win, y, 1); + } + else { + getyx(self->win, y, x); + rtn = wchgat(self->win, num, attr, color, NULL); + curses_funcname = "wchgat"; + (void)touchline(self->win, y, 1); } - return PyCursesCheckERR_ForWin(self, rtn, "chgat"); + return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", curses_funcname); } #endif @@ -1551,12 +1595,17 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) /*[clinic end generated code: output=22e77bb9fa11b461 input=d2f79e630a4fc6d0]*/ { + int rtn; + const char *curses_funcname; if (!group_right_1) { - return PyCursesCheckERR_ForWin(self, wdelch(self->win), "wdelch"); + rtn = wdelch(self->win); + curses_funcname = "wdelch"; } else { - return PyCursesCheckERR_ForWin(self, py_mvwdelch(self->win, y, x), "mvwdelch"); + rtn = py_mvwdelch(self->win, y, x); + curses_funcname = "mvwdelch"; } + return PyCursesCheckERR_ForWin_From(self, rtn, "wdelch", curses_funcname); } /*[clinic input] @@ -1592,7 +1641,8 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_SetString(state->error, catchall_NULL); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "derwin"); + PyCursesError_SetImplementation(state, "derwin"); return NULL; } @@ -1620,20 +1670,24 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { return NULL; + } + int rtn; + const char *curses_funcname; #ifdef py_is_pad if (py_is_pad(self->win)) { - return PyCursesCheckERR_ForWin(self, - pechochar(self->win, ch_ | (attr_t)attr), - "echochar"); + rtn = pechochar(self->win, ch_ | (attr_t)attr); + curses_funcname = "pechochar"; } else #endif - return PyCursesCheckERR_ForWin(self, - wechochar(self->win, ch_ | (attr_t)attr), - "echochar"); + { + rtn = wechochar(self->win, ch_ | (attr_t)attr); + curses_funcname = "wechochar"; + } + return PyCursesCheckERR_ForWin_From(self, rtn, "echochar", curses_funcname); } #ifdef NCURSES_MOUSE_VERSION @@ -1747,6 +1801,8 @@ _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, if (!PyErr_Occurred()) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); + const char *funcname = group_right_1 ? "mvwgetch" : "wgetch"; + PyCursesError_SetImplementation(state, funcname); } return NULL; } else if (rtn <= 255) { @@ -1788,31 +1844,35 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) /*[clinic end generated code: output=9f4f86e91fe50ef3 input=dd7e5367fb49dc48]*/ { - int ct; - wint_t rtn; + int rtn; + wint_t wch; Py_BEGIN_ALLOW_THREADS if (!group_right_1) { - ct = wget_wch(self->win ,&rtn); + rtn = wget_wch(self->win, &wch); } else { - ct = mvwget_wch(self->win, y, x, &rtn); + rtn = mvwget_wch(self->win, y, x, &wch); } Py_END_ALLOW_THREADS - if (ct == ERR) { - if (PyErr_CheckSignals()) + if (rtn == ERR) { + if (PyErr_CheckSignals()) { return NULL; - + } /* get_wch() returns ERR in nodelay mode */ cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); + const char *funcname = group_right_1 ? "mvwget_wch" : "wget_wch"; + PyCursesError_SetImplementation(state, funcname); return NULL; } - if (ct == KEY_CODE_YES) - return PyLong_FromLong(rtn); - else - return PyUnicode_FromOrdinal(rtn); + else if (rtn == KEY_CODE_YES) { + return PyLong_FromLong(wch); + } + else { + return PyUnicode_FromOrdinal(wch); + } } #endif @@ -1926,14 +1986,18 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { return NULL; + } + if (group_left_1) { if (wmove(self->win, y, x) == ERR) { - return PyCursesCheckERR_ForWin(self, ERR, "wmove"); + PyCursesSetError_ForWin(self, "wmove"); + return NULL; } } - return PyCursesCheckERR_ForWin(self, whline(self->win, ch_ | (attr_t)attr, n), "hline"); + int rtn = whline(self->win, ch_ | (attr_t)attr, n); + return PyCursesCheckERR_ForWin_From(self, rtn, "hline", "whline"); } /*[clinic input] @@ -1970,17 +2034,21 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, int rtn; chtype ch_ = 0; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { return NULL; + } + const char *curses_funcname; if (!group_left_1) { rtn = winsch(self->win, ch_ | (attr_t)attr); + curses_funcname = "winsch"; } else { rtn = mvwinsch(self->win, y, x, ch_ | (attr_t)attr); + curses_funcname = "mvwwinsch"; } - return PyCursesCheckERR_ForWin(self, rtn, "insch"); + return PyCursesCheckERR_ForWin_From(self, rtn, "insch", curses_funcname); } /*[clinic input] @@ -2121,15 +2189,16 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *funcname; + const char *simple_funcname, *curses_funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) + if (strtype == 0) { return NULL; + } if (use_attr) { attr_old = getattrs(self->win); @@ -2137,27 +2206,38 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - funcname = "inswstr"; - if (use_xy) - rtn = mvwins_wstr(self->win,y,x,wstr); - else - rtn = wins_wstr(self->win,wstr); + simple_funcname = "inswstr"; + if (use_xy) { + rtn = mvwins_wstr(self->win, y, x, wstr); + curses_funcname = "mvwins_wstr"; + } + else { + rtn = wins_wstr(self->win, wstr); + curses_funcname = "wins_wstr"; + } PyMem_Free(wstr); } else #endif { - const char *str = PyBytes_AS_STRING(bytesobj); - funcname = "insstr"; - if (use_xy) - rtn = mvwinsstr(self->win,y,x,str); - else - rtn = winsstr(self->win,str); + const char *text = PyBytes_AS_STRING(bytesobj); + simple_funcname = "insstr"; + if (use_xy) { + rtn = mvwinsstr(self->win, y, x, text); + curses_funcname = "mvwinsstr"; + } + else { + rtn = winsstr(self->win, text); + curses_funcname = "winsstr"; + } Py_DECREF(bytesobj); } - if (use_attr) - (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin(self, rtn, funcname); + if (use_attr) { + (void)wattrset(self->win, attr_old); + } + return PyCursesCheckERR_ForWin_From(self, rtn, + simple_funcname, + curses_funcname); } /*[clinic input] @@ -2206,15 +2286,16 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *funcname; + const char *simple_funcname, *curses_funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) + if (strtype == 0) { return NULL; + } if (use_attr) { attr_old = getattrs(self->win); @@ -2222,27 +2303,38 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - funcname = "insn_wstr"; - if (use_xy) - rtn = mvwins_nwstr(self->win,y,x,wstr,n); - else - rtn = wins_nwstr(self->win,wstr,n); + simple_funcname = "insn_wstr"; + if (use_xy) { + rtn = mvwins_nwstr(self->win, y, x, wstr, n); + curses_funcname = "mvwins_nwstr"; + } + else { + rtn = wins_nwstr(self->win, wstr, n); + curses_funcname = "wins_nwstr"; + } PyMem_Free(wstr); } else #endif { - const char *str = PyBytes_AS_STRING(bytesobj); - funcname = "insnstr"; - if (use_xy) - rtn = mvwinsnstr(self->win,y,x,str,n); - else - rtn = winsnstr(self->win,str,n); + const char *text = PyBytes_AS_STRING(bytesobj); + simple_funcname = "insnstr"; + if (use_xy) { + rtn = mvwinsnstr(self->win, y, x, text, n); + curses_funcname = "mvwinsnstr"; + } + else { + rtn = winsnstr(self->win, text, n); + curses_funcname = "winsnstr"; + } Py_DECREF(bytesobj); } - if (use_attr) - (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin(self, rtn, funcname); + if (use_attr) { + (void)wattrset(self->win, attr_old); + } + return PyCursesCheckERR_ForWin_From(self, rtn, + simple_funcname, + curses_funcname); } /*[clinic input] @@ -2502,7 +2594,8 @@ static PyObject * _curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num) /*[clinic end generated code: output=ea216e334f9ce1b4 input=152155e258a77a7a]*/ { - return PyCursesCheckERR_ForWin(self, wredrawln(self->win,beg,num), "redrawln"); + int rtn = wredrawln(self->win,beg, num); + return PyCursesCheckERR_ForWin_From(self, rtn, "redrawln", "wredrawln"); } /*[clinic input] @@ -2564,7 +2657,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, Py_BEGIN_ALLOW_THREADS rtn = wrefresh(self->win); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin(self, rtn, "prefresh"); + return PyCursesCheckERR_ForWin_From(self, rtn, "prefresh", "wrefresh"); } /*[clinic input] @@ -2586,7 +2679,8 @@ _curses_window_setscrreg_impl(PyCursesWindowObject *self, int top, int bottom) /*[clinic end generated code: output=486ab5db218d2b1a input=1b517b986838bf0e]*/ { - return PyCursesCheckERR_ForWin(self, wsetscrreg(self->win, top, bottom), "wsetscrreg"); + int rtn = wsetscrreg(self->win, top, bottom); + return PyCursesCheckERR_ForWin(self, rtn, "wsetscrreg"); } /*[clinic input] @@ -2616,19 +2710,25 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, /*[clinic end generated code: output=93e898afc348f59a input=2129fa47fd57721c]*/ { WINDOW *win; + const char *curses_funcname; /* printf("Subwin: %i %i %i %i \n", nlines, ncols, begin_y, begin_x); */ #ifdef py_is_pad if (py_is_pad(self->win)) { win = subpad(self->win, nlines, ncols, begin_y, begin_x); + curses_funcname = "subpad"; } else #endif + { win = subwin(self->win, nlines, ncols, begin_y, begin_x); + curses_funcname = "subwin"; + } if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, catchall_NULL); + PyCursesError_SetImplementation(state, curses_funcname); return NULL; } @@ -2655,12 +2755,17 @@ _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, int lines) /*[clinic end generated code: output=4541a8a11852d360 input=c969ca0cfabbdbec]*/ { + int rtn; + const char *curses_funcname; if (!group_right_1) { - return PyCursesCheckERR_ForWin(self, scroll(self->win), "scroll"); + rtn = scroll(self->win); + curses_funcname = "scroll"; } else { - return PyCursesCheckERR_ForWin(self, wscrl(self->win, lines), "scroll"); + rtn = wscrl(self->win, lines); + curses_funcname = "wscrl"; } + return PyCursesCheckERR_ForWin_From(self, rtn, "scroll", curses_funcname); } /*[clinic input] @@ -2684,12 +2789,17 @@ _curses_window_touchline_impl(PyCursesWindowObject *self, int start, int count, int group_right_1, int changed) /*[clinic end generated code: output=65d05b3f7438c61d input=a98aa4f79b6be845]*/ { + int rtn; + const char *curses_funcname; if (!group_right_1) { - return PyCursesCheckERR_ForWin(self, touchline(self->win, start, count), "touchline"); + rtn = touchline(self->win, start, count); + curses_funcname = "touchline"; } else { - return PyCursesCheckERR_ForWin(self, wtouchln(self->win, start, count, changed), "touchline"); + rtn = wtouchln(self->win, start, count, changed); + curses_funcname = "wtouchln"; } + return PyCursesCheckERR_ForWin_From(self, rtn, "touchline", curses_funcname); } /*[clinic input] @@ -2724,13 +2834,17 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { return NULL; + } if (group_left_1) { - if (wmove(self->win, y, x) == ERR) - return PyCursesCheckERR_ForWin(self, ERR, "wmove"); + if (wmove(self->win, y, x) == ERR) { + PyCursesSetError_ForWin(self, "wmove"); + return NULL; + } } - return PyCursesCheckERR_ForWin(self, wvline(self->win, ch_ | (attr_t)attr, n), "vline"); + int rtn = wvline(self->win, ch_ | (attr_t)attr, n); + return PyCursesCheckERR_ForWin_From(self, rtn, "vline", "wvline"); } static PyObject * @@ -3055,9 +3169,7 @@ _curses_color_content_impl(PyObject *module, int color_number) PyCursesStatefulInitialisedColor(module); if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, "%s() returned ERR", - Py_STRINGIFY(_COLOR_CONTENT_FUNC)); + PyCursesSetError(module, Py_STRINGIFY(_COLOR_CONTENT_FUNC)); return NULL; } @@ -3084,7 +3196,7 @@ _curses_color_pair_impl(PyObject *module, int pair_number) PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); - return PyLong_FromLong(COLOR_PAIR(pair_number)); + return PyLong_FromLong(COLOR_PAIR(pair_number)); } /*[clinic input] @@ -3111,7 +3223,10 @@ _curses_curs_set_impl(PyObject *module, int visibility) PyCursesStatefulInitialised(module); erg = curs_set(visibility); - if (erg == ERR) return PyCursesCheckERR(module, erg, "curs_set"); + if (erg == ERR) { + PyCursesSetError(module, "curs_set"); + return NULL; + } return PyLong_FromLong((long) erg); } @@ -3293,10 +3408,9 @@ _curses_getmouse_impl(PyObject *module) PyCursesStatefulInitialised(module); - rtn = getmouse( &event ); + rtn = getmouse(&event); if (rtn == ERR) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, "getmouse() returned ERR"); + PyCursesSetError(module, "getmouse"); return NULL; } return Py_BuildValue("(hiiik)", @@ -3392,6 +3506,7 @@ _curses_getwin(PyObject *module, PyObject *file) if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); + PyCursesError_SetImplementation(state, "getwin"); goto error; } cursesmodule_state *state = get_cursesmodule_state(module); @@ -3541,9 +3656,7 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) COLOR_PAIRS - 1); } else { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, "%s() returned ERR", - Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC)); + PyCursesSetError(module, Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC)); } return NULL; } @@ -3566,7 +3679,7 @@ _curses_initscr_impl(PyObject *module) WINDOW *win; if (curses_initscr_called) { - wrefresh(stdscr); + (void)wrefresh(stdscr); // TODO(picnixz): should we report an error? cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, stdscr, NULL); } @@ -3576,6 +3689,7 @@ _curses_initscr_impl(PyObject *module) if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); + PyCursesError_SetImplementation(state, "initscr"); return NULL; } @@ -3718,16 +3832,21 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) } if (!curses_setupterm_called && setupterm((char *)term, fd, &err) == ERR) { - const char* s = "setupterm: unknown error"; + const char *error_message; if (err == 0) { - s = "setupterm: could not find terminal"; - } else if (err == -1) { - s = "setupterm: could not find terminfo database"; + error_message = "setupterm: could not find terminal"; + } + else if (err == -1) { + error_message = "setupterm: could not find terminfo database"; + } + else { + error_message = "setupterm: unknown error"; } cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, s); + PyErr_SetString(state->error, error_message); + PyCursesError_SetImplementation(state, "setupterm"); return NULL; } @@ -4046,6 +4165,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); + PyCursesError_SetImplementation(state, "newpad"); return NULL; } @@ -4083,10 +4203,11 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, PyCursesStatefulInitialised(module); - win = newwin(nlines,ncols,begin_y,begin_x); + win = newwin(nlines, ncols, begin_y, begin_x); if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); + PyCursesError_SetImplementation(state, "newwin"); return NULL; } @@ -4205,9 +4326,7 @@ _curses_pair_content_impl(PyObject *module, int pair_number) COLOR_PAIRS - 1); } else { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, "%s() returned ERR", - Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC)); + PyCursesSetError(module, Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC)); } return NULL; } @@ -4536,8 +4655,7 @@ _curses_start_color_impl(PyObject *module) PyCursesStatefulInitialised(module); if (start_color() == ERR) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, "start_color() returned ERR"); + PyCursesSetError(module, "start_color"); return NULL; } @@ -4683,14 +4801,13 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9) /*[clinic end generated code: output=599f62b615c667ff input=5e30b15786f032aa]*/ { - char* result = NULL; - PyCursesStatefulSetupTermCalled(module); - result = tparm((char *)str,i1,i2,i3,i4,i5,i6,i7,i8,i9); - if (!result) { + const char *result = tparm((char *)str, i1, i2, i3, i4, i5, i6, i7, i8, i9); + if (result == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, "tparm() returned NULL"); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "tparm"); + PyCursesError_SetImplementation(state, "tparm"); return NULL; } @@ -4882,19 +4999,10 @@ static PyObject * _curses_use_default_colors_impl(PyObject *module) /*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/ { - int code; - PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); - code = use_default_colors(); - if (code != ERR) { - Py_RETURN_NONE; - } else { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, "use_default_colors() returned ERR"); - return NULL; - } + return PyCursesCheckERR(module, use_default_colors(), "use_default_colors"); } #endif /* STRICT_SYSV_CURSES */ From 73ce26c7924d0cebd39d10efcef752d65e3d1617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Wed, 16 Oct 2024 12:01:58 +0200 Subject: [PATCH 03/25] cosmetic changes! --- Modules/_cursesmodule.c | 359 ++++++++++++++++++++++------------------ 1 file changed, 200 insertions(+), 159 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 88bf969b98c44f..48223fa6396941 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -390,7 +390,7 @@ PyCursesSetError_ForWin_From(PyCursesWindowObject *win, * is imported on demand. */ static inline int -_PyCursesCheckFunction(int called, const char *funcname) +_PyCursesStatelessCheckFunction(int called, const char *funcname) { if (called == TRUE) { return 1; @@ -412,7 +412,7 @@ _PyCursesCheckFunction(int called, const char *funcname) * The exception type is obtained from the 'module' state. */ static inline int -_PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcname) +_PyCursesCheckFunction(PyObject *module, int called, const char *funcname) { if (called == TRUE) { return 1; @@ -422,34 +422,34 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam return 0; } -#define PyCursesStatefulSetupTermCalled(MODULE) \ - do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_setupterm_called, \ - "setupterm")) \ - { \ - return 0; \ - } \ +#define PyCursesCheckSetupTermCalled(MODULE) \ + do { \ + if (!_PyCursesCheckFunction(MODULE, \ + curses_setupterm_called, \ + "setupterm")) \ + { \ + return 0; \ + } \ } while (0) -#define PyCursesStatefulInitialised(MODULE) \ - do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_initscr_called, \ - "initscr")) \ - { \ - return 0; \ - } \ +#define PyCursesCheckInitialised(MODULE) \ + do { \ + if (!_PyCursesCheckFunction(MODULE, \ + curses_initscr_called, \ + "initscr")) \ + { \ + return 0; \ + } \ } while (0) -#define PyCursesStatefulInitialisedColor(MODULE) \ - do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_start_color_called, \ - "start_color")) \ - { \ - return 0; \ - } \ +#define PyCursesCheckInitialisedColor(MODULE) \ + do { \ + if (!_PyCursesCheckFunction(MODULE, \ + curses_start_color_called, \ + "start_color")) \ + { \ + return 0; \ + } \ } while (0) /* Utility Functions */ @@ -825,61 +825,84 @@ class component_converter(CConverter): The Window Object ******************************************************************************/ -/* Function prototype macros for Window object +/* + * Macros for creating a PyCursesWindowObject object's method. + * + * Parameters + * + * X The name of the curses C function or macro to invoke. + * TYPE The function parameter(s) type. + * ERGSTR The format string for construction of the return value. + * PARSESTR The format string for argument parsing. + */ + +#define Window_NoArgNoReturnFunction(X) \ + static PyObject *PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *Py_UNUSED(args)) \ + { \ + int rtn = X(self->win); \ + return PyCursesCheckERR_ForWin(self, rtn, # X); \ + } - X - function name - TYPE - parameter Type - ERGSTR - format string for construction of the return value - PARSESTR - format string for argument parsing -*/ +#define Window_NoArgTrueFalseFunction(X) \ + static PyObject * PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *Py_UNUSED(args)) \ + { \ + return PyBool_FromLong(X(self->win)); \ + } -#define Window_NoArgNoReturnFunction(X) \ - static PyObject *PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ - { return PyCursesCheckERR_ForWin(self, X(self->win), # X); } +#define Window_NoArgNoReturnVoidFunction(X) \ + static PyObject * PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *Py_UNUSED(args)) \ + { \ + X(self->win); \ + Py_RETURN_NONE; \ + } -#define Window_NoArgTrueFalseFunction(X) \ - static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ - { \ - return PyBool_FromLong(X(self->win)); } +#define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \ + static PyObject * PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *Py_UNUSED(args)) \ + { \ + TYPE arg1, arg2; \ + X(self->win, arg1, arg2); \ + return Py_BuildValue(ERGSTR, arg1, arg2); \ + } -#define Window_NoArgNoReturnVoidFunction(X) \ +#define Window_OneArgNoReturnVoidFunction(X, TYPE, PARSESTR) \ static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ + (PyCursesWindowObject *self, PyObject *args) \ { \ - X(self->win); Py_RETURN_NONE; } - -#define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \ - static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ - { \ - TYPE arg1, arg2; \ - X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); } - -#define Window_OneArgNoReturnVoidFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *args) \ - { \ - TYPE arg1; \ - if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) return NULL; \ - X(self->win,arg1); Py_RETURN_NONE; } - -#define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *args) \ - { \ - TYPE arg1; \ - if (!PyArg_ParseTuple(args,PARSESTR, &arg1)) return NULL; \ - return PyCursesCheckERR_ForWin(self, X(self->win, arg1), # X); } - -#define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *args) \ - { \ - TYPE arg1, arg2; \ - if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) return NULL; \ - return PyCursesCheckERR_ForWin(self, X(self->win, arg1, arg2), # X); } + TYPE arg; \ + if (!PyArg_ParseTuple(args, PARSESTR, &arg)) { \ + return NULL; \ + } \ + X(self->win, arg); \ + Py_RETURN_NONE; \ + } + +#define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \ + static PyObject * PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *args) \ + { \ + TYPE arg; \ + if (!PyArg_ParseTuple(args, PARSESTR, &arg)) { \ + return NULL; \ + } \ + int rtn = X(self->win, arg); \ + return PyCursesCheckERR_ForWin(self, rtn, # X); \ + } + +#define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ + static PyObject * PyCursesWindow_ ## X \ + (PyCursesWindowObject *self, PyObject *args) \ + { \ + TYPE arg1, arg2; \ + if (!PyArg_ParseTuple(args, PARSESTR, &arg1, &arg2)) { \ + return NULL; \ + } \ + int rtn = X(self->win, arg1, arg2); \ + return PyCursesCheckERR_ForWin(self, rtn, # X); \ + } /* ------------- WINDOW routines --------------- */ @@ -3027,49 +3050,67 @@ static PyType_Spec PyCursesWindow_Type_spec = { /* -------------------------------------------------------*/ -/* Function Body Macros - They are ugly but very, very useful. ;-) - - X - function name - TYPE - parameter Type - ERGSTR - format string for construction of the return value - PARSESTR - format string for argument parsing - */ - -#define NoArgNoReturnFunctionBody(X) \ -{ \ - PyCursesStatefulInitialised(module); \ - return PyCursesCheckERR(module, X(), # X); } +/* + * Macros for implementing simple module's methods. + * + * Parameters + * + * X The name of the curses C function or macro to invoke. + * FLAG When false, prefixes the function name with 'no' at runtime, + * This parameter is present in the signature and auto-generated + * by Argument Clinic. + * + * These macros should only be used for generating the body of + * the module's methods since they need a module reference. + */ -#define NoArgOrFlagNoReturnFunctionBody(X, flag) \ -{ \ - PyCursesStatefulInitialised(module); \ - if (flag) \ - return PyCursesCheckERR(module, X(), # X); \ - else \ - return PyCursesCheckERR(module, no ## X(), # X); \ +#define NoArgNoReturnFunctionBody(X) \ +{ \ + PyCursesCheckInitialised(module); \ + return PyCursesCheckERR(module, X(), # X); \ } -#define NoArgReturnIntFunctionBody(X) \ -{ \ - PyCursesStatefulInitialised(module); \ - return PyLong_FromLong((long) X()); } +#define NoArgOrFlagNoReturnFunctionBody(X, FLAG) \ +{ \ + PyCursesCheckInitialised(module); \ + int rtn; \ + const char *funcname; \ + if (FLAG) { \ + rtn = X(); \ + funcname = # X; \ + } \ + else { \ + rtn = no ## X(); \ + funcname = "no" # X; \ + } \ + return PyCursesCheckERR_From(module, rtn, \ + # X, funcname); \ +} +#define NoArgReturnIntFunctionBody(X) \ +{ \ + PyCursesCheckInitialised(module); \ + return PyLong_FromLong((long) X()); \ +} -#define NoArgReturnStringFunctionBody(X) \ -{ \ - PyCursesStatefulInitialised(module); \ - return PyBytes_FromString(X()); } +#define NoArgReturnStringFunctionBody(X) \ +{ \ + PyCursesCheckInitialised(module); \ + return PyBytes_FromString(X()); \ +} -#define NoArgTrueFalseFunctionBody(X) \ -{ \ - PyCursesStatefulInitialised(module); \ - return PyBool_FromLong(X()); } +#define NoArgTrueFalseFunctionBody(X) \ +{ \ + PyCursesCheckInitialised(module); \ + return PyBool_FromLong(X()); \ +} -#define NoArgNoReturnVoidFunctionBody(X) \ -{ \ - PyCursesStatefulInitialised(module); \ - X(); \ - Py_RETURN_NONE; } +#define NoArgNoReturnVoidFunctionBody(X) \ +{ \ + PyCursesCheckInitialised(module); \ + X(); \ + Py_RETURN_NONE; \ +} /********************************************************************* Global Functions @@ -3165,8 +3206,8 @@ _curses_color_content_impl(PyObject *module, int color_number) { _CURSES_COLOR_VAL_TYPE r,g,b; - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) { PyCursesSetError(module, Py_STRINGIFY(_COLOR_CONTENT_FUNC)); @@ -3193,8 +3234,8 @@ static PyObject * _curses_color_pair_impl(PyObject *module, int pair_number) /*[clinic end generated code: output=60718abb10ce9feb input=6034e9146f343802]*/ { - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); return PyLong_FromLong(COLOR_PAIR(pair_number)); } @@ -3220,7 +3261,7 @@ _curses_curs_set_impl(PyObject *module, int visibility) { int erg; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); erg = curs_set(visibility); if (erg == ERR) { @@ -3275,7 +3316,7 @@ static PyObject * _curses_delay_output_impl(PyObject *module, int ms) /*[clinic end generated code: output=b6613a67f17fa4f4 input=5316457f5f59196c]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, delay_output(ms), "delay_output"); } @@ -3331,7 +3372,7 @@ _curses_erasechar_impl(PyObject *module) { char ch; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); ch = erasechar(); @@ -3381,7 +3422,7 @@ _curses_getsyx_impl(PyObject *module) int x = 0; int y = 0; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); getsyx(y, x); @@ -3406,7 +3447,7 @@ _curses_getmouse_impl(PyObject *module) int rtn; MEVENT event; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); rtn = getmouse(&event); if (rtn == ERR) { @@ -3441,7 +3482,7 @@ _curses_ungetmouse_impl(PyObject *module, short id, int x, int y, int z, { MEVENT event; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); event.id = id; event.x = x; @@ -3474,7 +3515,7 @@ _curses_getwin(PyObject *module, PyObject *file) WINDOW *win; PyObject *res = NULL; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); fp = tmpfile(); if (fp == NULL) @@ -3533,7 +3574,7 @@ static PyObject * _curses_halfdelay_impl(PyObject *module, unsigned char tenths) /*[clinic end generated code: output=e92cdf0ef33c0663 input=e42dce7259c15100]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, halfdelay(tenths), "halfdelay"); } @@ -3586,7 +3627,7 @@ static PyObject * _curses_has_key_impl(PyObject *module, int key) /*[clinic end generated code: output=19ad48319414d0b1 input=78bd44acf1a4997c]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyBool_FromLong(has_key(key)); } @@ -3617,8 +3658,8 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g, short b) /*[clinic end generated code: output=d7ed71b2d818cdf2 input=ae2b8bea0f152c80]*/ { - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); return PyCursesCheckERR(module, _CURSES_INIT_COLOR_FUNC(color_number, r, g, b), @@ -3646,8 +3687,8 @@ static PyObject * _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) /*[clinic end generated code: output=a0bba03d2bbc3ee6 input=54b421b44c12c389]*/ { - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); if (_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg) == ERR) { if (pair_number >= COLOR_PAIRS) { @@ -3951,7 +3992,7 @@ static PyObject * _curses_intrflush_impl(PyObject *module, int flag) /*[clinic end generated code: output=c1986df35e999a0f input=c65fe2ef973fe40a]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, intrflush(NULL, flag), "intrflush"); } @@ -3984,7 +4025,7 @@ static PyObject * _curses_is_term_resized_impl(PyObject *module, int nlines, int ncols) /*[clinic end generated code: output=aafe04afe50f1288 input=ca9c0bd0fb8ab444]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyBool_FromLong(is_term_resized(nlines, ncols)); } @@ -4006,7 +4047,7 @@ _curses_keyname_impl(PyObject *module, int key) { const char *knp; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (key < 0) { PyErr_SetString(PyExc_ValueError, "invalid key number"); @@ -4064,7 +4105,7 @@ static PyObject * _curses_meta_impl(PyObject *module, int yes) /*[clinic end generated code: output=22f5abda46a605d8 input=cfe7da79f51d0e30]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, meta(stdscr, yes), "meta"); } @@ -4088,7 +4129,7 @@ static PyObject * _curses_mouseinterval_impl(PyObject *module, int interval) /*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, mouseinterval(interval), "mouseinterval"); } @@ -4113,7 +4154,7 @@ _curses_mousemask_impl(PyObject *module, unsigned long newmask) { mmask_t oldmask, availmask; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); availmask = mousemask((mmask_t)newmask, &oldmask); return Py_BuildValue("(kk)", (unsigned long)availmask, (unsigned long)oldmask); @@ -4134,7 +4175,7 @@ static int _curses_napms_impl(PyObject *module, int ms) /*[clinic end generated code: output=5f292a6a724491bd input=c6d6e01f2f1df9f7]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return napms(ms); } @@ -4158,7 +4199,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) { WINDOW *win; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); win = newpad(nlines, ncols); @@ -4201,7 +4242,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, { WINDOW *win; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); win = newwin(nlines, ncols, begin_y, begin_x); if (win == NULL) { @@ -4316,8 +4357,8 @@ _curses_pair_content_impl(PyObject *module, int pair_number) { _CURSES_COLOR_NUM_TYPE f, b; - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); if (_CURSES_PAIR_CONTENT_FUNC(pair_number, &f, &b) == ERR) { if (pair_number >= COLOR_PAIRS) { @@ -4349,8 +4390,8 @@ static PyObject * _curses_pair_number_impl(PyObject *module, int attr) /*[clinic end generated code: output=85bce7d65c0aa3f4 input=d478548e33f5e61a]*/ { - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); return PyLong_FromLong(PAIR_NUMBER(attr)); } @@ -4390,7 +4431,7 @@ static PyObject * _curses_qiflush_impl(PyObject *module, int flag) /*[clinic end generated code: output=9167e862f760ea30 input=6ec8b3e2b717ec40]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (flag) { qiflush(); @@ -4545,7 +4586,7 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) { PyObject *result; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); result = PyCursesCheckERR(module, resizeterm(nlines, ncols), "resizeterm"); if (!result) @@ -4584,7 +4625,7 @@ _curses_resize_term_impl(PyObject *module, short nlines, short ncols) { PyObject *result; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); result = PyCursesCheckERR(module, resize_term(nlines, ncols), "resize_term"); if (!result) @@ -4627,7 +4668,7 @@ static PyObject * _curses_setsyx_impl(PyObject *module, int y, int x) /*[clinic end generated code: output=23dcf753511a2464 input=fa7f2b208e10a557]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); setsyx(y,x); @@ -4652,7 +4693,7 @@ static PyObject * _curses_start_color_impl(PyObject *module) /*[clinic end generated code: output=8b772b41d8090ede input=0ca0ecb2b77e1a12]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (start_color() == ERR) { PyCursesSetError(module, "start_color"); @@ -4724,7 +4765,7 @@ static PyObject * _curses_tigetflag_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=8853c0e55542195b input=b0787af9e3e9a6ce]*/ { - PyCursesStatefulSetupTermCalled(module); + PyCursesCheckSetupTermCalled(module); return PyLong_FromLong( (long) tigetflag( (char *)capname ) ); } @@ -4746,7 +4787,7 @@ static PyObject * _curses_tigetnum_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=46f8b0a1b5dff42f input=5cdf2f410b109720]*/ { - PyCursesStatefulSetupTermCalled(module); + PyCursesCheckSetupTermCalled(module); return PyLong_FromLong( (long) tigetnum( (char *)capname ) ); } @@ -4768,7 +4809,7 @@ static PyObject * _curses_tigetstr_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=f22b576ad60248f3 input=36644df25c73c0a7]*/ { - PyCursesStatefulSetupTermCalled(module); + PyCursesCheckSetupTermCalled(module); capname = tigetstr( (char *)capname ); if (capname == NULL || capname == (char*) -1) { @@ -4801,7 +4842,7 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9) /*[clinic end generated code: output=599f62b615c667ff input=5e30b15786f032aa]*/ { - PyCursesStatefulSetupTermCalled(module); + PyCursesCheckSetupTermCalled(module); const char *result = tparm((char *)str, i1, i2, i3, i4, i5, i6, i7, i8, i9); if (result == NULL) { @@ -4831,7 +4872,7 @@ static PyObject * _curses_typeahead_impl(PyObject *module, int fd) /*[clinic end generated code: output=084bb649d7066583 input=f2968d8e1805051b]*/ { - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); return PyCursesCheckERR(module, typeahead( fd ), "typeahead"); } @@ -4855,7 +4896,7 @@ _curses_unctrl(PyObject *module, PyObject *ch) { chtype ch_; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (!PyCurses_ConvertToChtype(NULL, ch, &ch_)) return NULL; @@ -4878,7 +4919,7 @@ _curses_ungetch(PyObject *module, PyObject *ch) { chtype ch_; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (!PyCurses_ConvertToChtype(NULL, ch, &ch_)) return NULL; @@ -4949,7 +4990,7 @@ _curses_unget_wch(PyObject *module, PyObject *ch) { wchar_t wch; - PyCursesStatefulInitialised(module); + PyCursesCheckInitialised(module); if (!PyCurses_ConvertToWchar_t(ch, &wch)) return NULL; @@ -4999,8 +5040,8 @@ static PyObject * _curses_use_default_colors_impl(PyObject *module) /*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/ { - PyCursesStatefulInitialised(module); - PyCursesStatefulInitialisedColor(module); + PyCursesCheckInitialised(module); + PyCursesCheckInitialisedColor(module); return PyCursesCheckERR(module, use_default_colors(), "use_default_colors"); } @@ -5173,19 +5214,19 @@ static PyMethodDef cursesmodule_methods[] = { static inline int curses_capi_setupterm_called(void) { - return _PyCursesCheckFunction(curses_setupterm_called, "setupterm"); + return _PyCursesStatelessCheckFunction(curses_setupterm_called, "setupterm"); } static inline int curses_capi_initscr_called(void) { - return _PyCursesCheckFunction(curses_initscr_called, "initscr"); + return _PyCursesStatelessCheckFunction(curses_initscr_called, "initscr"); } static inline int curses_capi_start_color_called(void) { - return _PyCursesCheckFunction(curses_start_color_called, "start_color"); + return _PyCursesStatelessCheckFunction(curses_start_color_called, "start_color"); } static void * From cfe5468b205a9fb9b5f9054aae3c503cadc751a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:21:58 +0200 Subject: [PATCH 04/25] blurb --- .../Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst diff --git a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst new file mode 100644 index 00000000000000..29bc7b6325383b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst @@ -0,0 +1,3 @@ +Add :attr:`~curses.error.funcname` to :exc:`curses.error` objects to indicate +which :mod:`curses` C function or macro was responsible for the exception. +Patch by Bénédikt Tran. From a8845eed507cb40f30aafd92640596a5213756ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:25:10 +0200 Subject: [PATCH 05/25] update docs --- Doc/library/curses.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 6c7fc721a3e0fb..eff255346cb1e5 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -59,6 +59,12 @@ The module :mod:`curses` defines the following exception: Exception raised when a curses library function returns an error. + .. attribute:: funcname + + Attribute storing the name of the curses C function or macro + responsible for this exception, possibly ``None`` if no such + information is available. + .. note:: Whenever *x* or *y* arguments to a function or a method are optional, they From 55a491ae163b7d6130ed7689083df0be676f8e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:11:58 +0200 Subject: [PATCH 06/25] reduce diff --- Modules/_cursesmodule.c | 269 ++++++++++++++++++---------------------- 1 file changed, 120 insertions(+), 149 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index df8e866888f723..fbaa1c4454982f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -394,7 +394,7 @@ PyCursesSetError_ForWin_From(PyCursesWindowObject *win, * is imported on demand. */ static inline int -_PyCursesStatelessCheckFunction(int called, const char *funcname) +_PyCursesCheckFunction(int called, const char *funcname) { if (called == TRUE) { return 1; @@ -416,7 +416,7 @@ _PyCursesStatelessCheckFunction(int called, const char *funcname) * The exception type is obtained from the 'module' state. */ static inline int -_PyCursesCheckFunction(PyObject *module, int called, const char *funcname) +_PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcname) { if (called == TRUE) { return 1; @@ -426,34 +426,34 @@ _PyCursesCheckFunction(PyObject *module, int called, const char *funcname) return 0; } -#define PyCursesCheckSetupTermCalled(MODULE) \ - do { \ - if (!_PyCursesCheckFunction(MODULE, \ - curses_setupterm_called, \ - "setupterm")) \ - { \ - return 0; \ - } \ +#define PyCursesStatefulSetupTermCalled(MODULE) \ + do { \ + if (!_PyCursesStatefulCheckFunction(MODULE, \ + curses_setupterm_called, \ + "setupterm")) \ + { \ + return 0; \ + } \ } while (0) -#define PyCursesCheckInitialised(MODULE) \ - do { \ - if (!_PyCursesCheckFunction(MODULE, \ - curses_initscr_called, \ - "initscr")) \ - { \ - return 0; \ - } \ +#define PyCursesStatefulInitialised(MODULE) \ + do { \ + if (!_PyCursesStatefulCheckFunction(MODULE, \ + curses_initscr_called, \ + "initscr")) \ + { \ + return 0; \ + } \ } while (0) -#define PyCursesCheckInitialisedColor(MODULE) \ - do { \ - if (!_PyCursesCheckFunction(MODULE, \ - curses_start_color_called, \ - "start_color")) \ - { \ - return 0; \ - } \ +#define PyCursesStatefulInitialisedColor(MODULE) \ + do { \ + if (!_PyCursesStatefulCheckFunction(MODULE, \ + curses_start_color_called, \ + "start_color")) \ + { \ + return 0; \ + } \ } while (0) /* Utility Functions */ @@ -840,14 +840,6 @@ class component_converter(CConverter): * PARSESTR The format string for argument parsing. */ -#define Window_NoArgNoReturnFunction(X) \ - static PyObject *PyCursesWindow_ ## X \ - (PyCursesWindowObject *self, PyObject *Py_UNUSED(args)) \ - { \ - int rtn = X(self->win); \ - return PyCursesCheckERR_ForWin(self, rtn, # X); \ - } - #define Window_NoArgNoReturnFunction(X) \ static PyObject *PyCursesWindow_ ## X \ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ @@ -1206,9 +1198,8 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, } Py_DECREF(bytesobj); } - if (use_attr) { + if (use_attr) (void)wattrset(self->win, attr_old); - } return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -1265,9 +1256,8 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) { + if (strtype == 0) return NULL; - } if (use_attr) { attr_old = getattrs(self->win); @@ -1301,9 +1291,8 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, } Py_DECREF(bytesobj); } - if (use_attr) { + if (use_attr) (void)wattrset(self->win,attr_old); - } return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -1327,9 +1316,8 @@ _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr) { chtype bkgd; - if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) { + if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) return NULL; - } int rtn = wbkgd(self->win, bkgd | attr); return PyCursesCheckERR_ForWin_From(self, rtn, "bkgd", "wbkgd"); @@ -1405,11 +1393,10 @@ _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, { chtype bkgd; - if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) { + if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) return NULL; - } - wbkgdset(self->win, bkgd | attr); + wbkgdset(self->win, bkgd | attr); // errors are ignored Py_RETURN_NONE; } @@ -1714,9 +1701,8 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - } int rtn; const char *curses_funcname; @@ -1888,22 +1874,21 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) /*[clinic end generated code: output=9f4f86e91fe50ef3 input=dd7e5367fb49dc48]*/ { - int rtn; + int ct; wint_t wch; Py_BEGIN_ALLOW_THREADS if (!group_right_1) { - rtn = wget_wch(self->win, &wch); + ct = wget_wch(self->win, &wch); } else { - rtn = mvwget_wch(self->win, y, x, &wch); + ct = mvwget_wch(self->win, y, x, &wch); } Py_END_ALLOW_THREADS - if (rtn == ERR) { - if (PyErr_CheckSignals()) { + if (ct == ERR) { + if (PyErr_CheckSignals()) return NULL; - } /* get_wch() returns ERR in nodelay mode */ cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); @@ -1911,12 +1896,10 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, PyCursesError_SetImplementation(state, funcname); return NULL; } - else if (rtn == KEY_CODE_YES) { + if (ct == KEY_CODE_YES) return PyLong_FromLong(wch); - } - else { + else return PyUnicode_FromOrdinal(wch); - } } #endif @@ -2032,9 +2015,8 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - } if (group_left_1) { if (wmove(self->win, y, x) == ERR) { @@ -2080,9 +2062,8 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, int rtn; chtype ch_ = 0; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - } const char *curses_funcname; if (!group_left_1) { @@ -2244,9 +2225,8 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) { + if (strtype == 0) return NULL; - } if (use_attr) { attr_old = getattrs(self->win); @@ -2280,9 +2260,8 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, } Py_DECREF(bytesobj); } - if (use_attr) { + if (use_attr) (void)wattrset(self->win, attr_old); - } return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -2341,9 +2320,8 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, #else strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL); #endif - if (strtype == 0) { + if (strtype == 0) return NULL; - } if (use_attr) { attr_old = getattrs(self->win); @@ -2377,9 +2355,8 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, } Py_DECREF(bytesobj); } - if (use_attr) { + if (use_attr) (void)wattrset(self->win, attr_old); - } return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -2882,9 +2859,8 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, { chtype ch_; - if (!PyCurses_ConvertToChtype(self, ch, &ch_)) { + if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - } if (group_left_1) { if (wmove(self->win, y, x) == ERR) { PyCursesSetError_ForWin(self, "wmove"); @@ -3094,15 +3070,14 @@ static PyType_Spec PyCursesWindow_Type_spec = { * the module's methods since they need a module reference. */ -#define NoArgNoReturnFunctionBody(X) \ -{ \ - PyCursesCheckInitialised(module); \ - return PyCursesCheckERR(module, X(), # X); \ -} +#define NoArgNoReturnFunctionBody(X) \ +{ \ + PyCursesStatefulInitialised(module); \ + return PyCursesCheckERR(module, X(), # X); } #define NoArgOrFlagNoReturnFunctionBody(X, FLAG) \ { \ - PyCursesCheckInitialised(module); \ + PyCursesStatefulInitialised(module); \ int rtn; \ const char *funcname; \ if (FLAG) { \ @@ -3117,30 +3092,26 @@ static PyType_Spec PyCursesWindow_Type_spec = { # X, funcname); \ } -#define NoArgReturnIntFunctionBody(X) \ -{ \ - PyCursesCheckInitialised(module); \ - return PyLong_FromLong((long) X()); \ -} +#define NoArgReturnIntFunctionBody(X) \ +{ \ + PyCursesStatefulInitialised(module); \ + return PyLong_FromLong((long) X()); } -#define NoArgReturnStringFunctionBody(X) \ -{ \ - PyCursesCheckInitialised(module); \ - return PyBytes_FromString(X()); \ -} +#define NoArgReturnStringFunctionBody(X) \ +{ \ + PyCursesStatefulInitialised(module); \ + return PyBytes_FromString(X()); } -#define NoArgTrueFalseFunctionBody(X) \ -{ \ - PyCursesCheckInitialised(module); \ - return PyBool_FromLong(X()); \ -} +#define NoArgTrueFalseFunctionBody(X) \ +{ \ + PyCursesStatefulInitialised(module); \ + return PyBool_FromLong(X()); } -#define NoArgNoReturnVoidFunctionBody(X) \ -{ \ - PyCursesCheckInitialised(module); \ - X(); \ - Py_RETURN_NONE; \ -} +#define NoArgNoReturnVoidFunctionBody(X) \ +{ \ + PyCursesStatefulInitialised(module); \ + X(); \ + Py_RETURN_NONE; } /********************************************************************* Global Functions @@ -3236,8 +3207,8 @@ _curses_color_content_impl(PyObject *module, int color_number) { _CURSES_COLOR_VAL_TYPE r,g,b; - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) { PyCursesSetError(module, Py_STRINGIFY(_COLOR_CONTENT_FUNC)); @@ -3264,10 +3235,10 @@ static PyObject * _curses_color_pair_impl(PyObject *module, int pair_number) /*[clinic end generated code: output=60718abb10ce9feb input=6034e9146f343802]*/ { - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); - return PyLong_FromLong(COLOR_PAIR(pair_number)); + return PyLong_FromLong(COLOR_PAIR(pair_number)); } /*[clinic input] @@ -3291,7 +3262,7 @@ _curses_curs_set_impl(PyObject *module, int visibility) { int erg; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); erg = curs_set(visibility); if (erg == ERR) { @@ -3346,7 +3317,7 @@ static PyObject * _curses_delay_output_impl(PyObject *module, int ms) /*[clinic end generated code: output=b6613a67f17fa4f4 input=5316457f5f59196c]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, delay_output(ms), "delay_output"); } @@ -3402,7 +3373,7 @@ _curses_erasechar_impl(PyObject *module) { char ch; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); ch = erasechar(); @@ -3452,7 +3423,7 @@ _curses_getsyx_impl(PyObject *module) int x = 0; int y = 0; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); getsyx(y, x); @@ -3477,7 +3448,7 @@ _curses_getmouse_impl(PyObject *module) int rtn; MEVENT event; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); rtn = getmouse(&event); if (rtn == ERR) { @@ -3512,7 +3483,7 @@ _curses_ungetmouse_impl(PyObject *module, short id, int x, int y, int z, { MEVENT event; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); event.id = id; event.x = x; @@ -3545,7 +3516,7 @@ _curses_getwin(PyObject *module, PyObject *file) WINDOW *win; PyObject *res = NULL; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); fp = tmpfile(); if (fp == NULL) @@ -3604,7 +3575,7 @@ static PyObject * _curses_halfdelay_impl(PyObject *module, unsigned char tenths) /*[clinic end generated code: output=e92cdf0ef33c0663 input=e42dce7259c15100]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, halfdelay(tenths), "halfdelay"); } @@ -3657,7 +3628,7 @@ static PyObject * _curses_has_key_impl(PyObject *module, int key) /*[clinic end generated code: output=19ad48319414d0b1 input=78bd44acf1a4997c]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyBool_FromLong(has_key(key)); } @@ -3688,8 +3659,8 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g, short b) /*[clinic end generated code: output=d7ed71b2d818cdf2 input=ae2b8bea0f152c80]*/ { - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); return PyCursesCheckERR(module, _CURSES_INIT_COLOR_FUNC(color_number, r, g, b), @@ -3717,8 +3688,8 @@ static PyObject * _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) /*[clinic end generated code: output=a0bba03d2bbc3ee6 input=54b421b44c12c389]*/ { - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); if (_CURSES_INIT_PAIR_FUNC(pair_number, fg, bg) == ERR) { if (pair_number >= COLOR_PAIRS) { @@ -4025,7 +3996,7 @@ static PyObject * _curses_intrflush_impl(PyObject *module, int flag) /*[clinic end generated code: output=c1986df35e999a0f input=c65fe2ef973fe40a]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, intrflush(NULL, flag), "intrflush"); } @@ -4058,7 +4029,7 @@ static PyObject * _curses_is_term_resized_impl(PyObject *module, int nlines, int ncols) /*[clinic end generated code: output=aafe04afe50f1288 input=ca9c0bd0fb8ab444]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyBool_FromLong(is_term_resized(nlines, ncols)); } @@ -4080,7 +4051,7 @@ _curses_keyname_impl(PyObject *module, int key) { const char *knp; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (key < 0) { PyErr_SetString(PyExc_ValueError, "invalid key number"); @@ -4138,7 +4109,7 @@ static PyObject * _curses_meta_impl(PyObject *module, int yes) /*[clinic end generated code: output=22f5abda46a605d8 input=cfe7da79f51d0e30]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, meta(stdscr, yes), "meta"); } @@ -4162,7 +4133,7 @@ static PyObject * _curses_mouseinterval_impl(PyObject *module, int interval) /*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, mouseinterval(interval), "mouseinterval"); } @@ -4187,7 +4158,7 @@ _curses_mousemask_impl(PyObject *module, unsigned long newmask) { mmask_t oldmask, availmask; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); availmask = mousemask((mmask_t)newmask, &oldmask); return Py_BuildValue("(kk)", (unsigned long)availmask, (unsigned long)oldmask); @@ -4208,9 +4179,9 @@ static int _curses_napms_impl(PyObject *module, int ms) /*[clinic end generated code: output=5f292a6a724491bd input=c6d6e01f2f1df9f7]*/ { - if (!_PyCursesCheckFunction(module, - curses_initscr_called, - "initscr")) { + if (!_PyCursesStatefulCheckFunction(module, + curses_initscr_called, + "initscr")) { return -1; } return napms(ms); @@ -4235,7 +4206,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) { WINDOW *win; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); win = newpad(nlines, ncols); @@ -4278,7 +4249,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, { WINDOW *win; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); win = newwin(nlines, ncols, begin_y, begin_x); if (win == NULL) { @@ -4393,8 +4364,8 @@ _curses_pair_content_impl(PyObject *module, int pair_number) { _CURSES_COLOR_NUM_TYPE f, b; - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); if (_CURSES_PAIR_CONTENT_FUNC(pair_number, &f, &b) == ERR) { if (pair_number >= COLOR_PAIRS) { @@ -4426,8 +4397,8 @@ static PyObject * _curses_pair_number_impl(PyObject *module, int attr) /*[clinic end generated code: output=85bce7d65c0aa3f4 input=d478548e33f5e61a]*/ { - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); return PyLong_FromLong(PAIR_NUMBER(attr)); } @@ -4467,7 +4438,7 @@ static PyObject * _curses_qiflush_impl(PyObject *module, int flag) /*[clinic end generated code: output=9167e862f760ea30 input=6ec8b3e2b717ec40]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (flag) { qiflush(); @@ -4622,7 +4593,7 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) { PyObject *result; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); result = PyCursesCheckERR(module, resizeterm(nlines, ncols), "resizeterm"); if (!result) @@ -4661,7 +4632,7 @@ _curses_resize_term_impl(PyObject *module, short nlines, short ncols) { PyObject *result; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); result = PyCursesCheckERR(module, resize_term(nlines, ncols), "resize_term"); if (!result) @@ -4704,7 +4675,7 @@ static PyObject * _curses_setsyx_impl(PyObject *module, int y, int x) /*[clinic end generated code: output=23dcf753511a2464 input=fa7f2b208e10a557]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); setsyx(y,x); @@ -4729,7 +4700,7 @@ static PyObject * _curses_start_color_impl(PyObject *module) /*[clinic end generated code: output=8b772b41d8090ede input=0ca0ecb2b77e1a12]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (start_color() == ERR) { PyCursesSetError(module, "start_color"); @@ -4801,7 +4772,7 @@ static PyObject * _curses_tigetflag_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=8853c0e55542195b input=b0787af9e3e9a6ce]*/ { - PyCursesCheckSetupTermCalled(module); + PyCursesStatefulSetupTermCalled(module); return PyLong_FromLong( (long) tigetflag( (char *)capname ) ); } @@ -4823,7 +4794,7 @@ static PyObject * _curses_tigetnum_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=46f8b0a1b5dff42f input=5cdf2f410b109720]*/ { - PyCursesCheckSetupTermCalled(module); + PyCursesStatefulSetupTermCalled(module); return PyLong_FromLong( (long) tigetnum( (char *)capname ) ); } @@ -4845,7 +4816,7 @@ static PyObject * _curses_tigetstr_impl(PyObject *module, const char *capname) /*[clinic end generated code: output=f22b576ad60248f3 input=36644df25c73c0a7]*/ { - PyCursesCheckSetupTermCalled(module); + PyCursesStatefulSetupTermCalled(module); capname = tigetstr( (char *)capname ); if (capname == NULL || capname == (char*) -1) { @@ -4878,7 +4849,7 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9) /*[clinic end generated code: output=599f62b615c667ff input=5e30b15786f032aa]*/ { - PyCursesCheckSetupTermCalled(module); + PyCursesStatefulSetupTermCalled(module); const char *result = tparm((char *)str, i1, i2, i3, i4, i5, i6, i7, i8, i9); if (result == NULL) { @@ -4908,7 +4879,7 @@ static PyObject * _curses_typeahead_impl(PyObject *module, int fd) /*[clinic end generated code: output=084bb649d7066583 input=f2968d8e1805051b]*/ { - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); return PyCursesCheckERR(module, typeahead( fd ), "typeahead"); } @@ -4932,7 +4903,7 @@ _curses_unctrl(PyObject *module, PyObject *ch) { chtype ch_; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (!PyCurses_ConvertToChtype(NULL, ch, &ch_)) return NULL; @@ -4955,7 +4926,7 @@ _curses_ungetch(PyObject *module, PyObject *ch) { chtype ch_; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (!PyCurses_ConvertToChtype(NULL, ch, &ch_)) return NULL; @@ -5026,7 +4997,7 @@ _curses_unget_wch(PyObject *module, PyObject *ch) { wchar_t wch; - PyCursesCheckInitialised(module); + PyCursesStatefulInitialised(module); if (!PyCurses_ConvertToWchar_t(ch, &wch)) return NULL; @@ -5076,8 +5047,8 @@ static PyObject * _curses_use_default_colors_impl(PyObject *module) /*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/ { - PyCursesCheckInitialised(module); - PyCursesCheckInitialisedColor(module); + PyCursesStatefulInitialised(module); + PyCursesStatefulInitialisedColor(module); return PyCursesCheckERR(module, use_default_colors(), "use_default_colors"); } @@ -5250,19 +5221,19 @@ static PyMethodDef cursesmodule_methods[] = { static inline int curses_capi_setupterm_called(void) { - return _PyCursesStatelessCheckFunction(curses_setupterm_called, "setupterm"); + return _PyCursesCheckFunction(curses_setupterm_called, "setupterm"); } static inline int curses_capi_initscr_called(void) { - return _PyCursesStatelessCheckFunction(curses_initscr_called, "initscr"); + return _PyCursesCheckFunction(curses_initscr_called, "initscr"); } static inline int curses_capi_start_color_called(void) { - return _PyCursesStatelessCheckFunction(curses_start_color_called, "start_color"); + return _PyCursesCheckFunction(curses_start_color_called, "start_color"); } static void * From 758dfe5aace73a130b189606a020f5f52c04c260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:17:22 +0200 Subject: [PATCH 07/25] reduce diff even futher --- Modules/_cursesmodule.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index fbaa1c4454982f..a19c42d2bf54b6 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1199,7 +1199,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, Py_DECREF(bytesobj); } if (use_attr) - (void)wattrset(self->win, attr_old); + (void)wattrset(self->win,attr_old); return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -1875,20 +1875,21 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, /*[clinic end generated code: output=9f4f86e91fe50ef3 input=dd7e5367fb49dc48]*/ { int ct; - wint_t wch; + wint_t rtn; Py_BEGIN_ALLOW_THREADS if (!group_right_1) { - ct = wget_wch(self->win, &wch); + ct = wget_wch(self->win, &rtn); } else { - ct = mvwget_wch(self->win, y, x, &wch); + ct = mvwget_wch(self->win, y, x, &rtn); } Py_END_ALLOW_THREADS if (ct == ERR) { if (PyErr_CheckSignals()) return NULL; + /* get_wch() returns ERR in nodelay mode */ cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); @@ -1897,9 +1898,9 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, return NULL; } if (ct == KEY_CODE_YES) - return PyLong_FromLong(wch); + return PyLong_FromLong(rtn); else - return PyUnicode_FromOrdinal(wch); + return PyUnicode_FromOrdinal(rtn); } #endif @@ -2017,7 +2018,6 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - if (group_left_1) { if (wmove(self->win, y, x) == ERR) { PyCursesSetError_ForWin(self, "wmove"); @@ -2261,7 +2261,7 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, Py_DECREF(bytesobj); } if (use_attr) - (void)wattrset(self->win, attr_old); + (void)wattrset(self->win,attr_old); return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -2356,7 +2356,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, Py_DECREF(bytesobj); } if (use_attr) - (void)wattrset(self->win, attr_old); + (void)wattrset(self->win,attr_old); return PyCursesCheckERR_ForWin_From(self, rtn, simple_funcname, curses_funcname); @@ -3450,7 +3450,7 @@ _curses_getmouse_impl(PyObject *module) PyCursesStatefulInitialised(module); - rtn = getmouse(&event); + rtn = getmouse( &event ); if (rtn == ERR) { PyCursesSetError(module, "getmouse"); return NULL; @@ -3877,20 +3877,20 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) } if (!curses_setupterm_called && setupterm((char *)term, fd, &err) == ERR) { - const char *error_message; + const char *s; if (err == 0) { - error_message = "setupterm: could not find terminal"; + s = "setupterm: could not find terminal"; } else if (err == -1) { - error_message = "setupterm: could not find terminfo database"; + s = "setupterm: could not find terminfo database"; } else { - error_message = "setupterm: unknown error"; + s = "setupterm: unknown error"; } cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, error_message); + PyErr_SetString(state->error, s); PyCursesError_SetImplementation(state, "setupterm"); return NULL; } @@ -4251,7 +4251,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, PyCursesStatefulInitialised(module); - win = newwin(nlines, ncols, begin_y, begin_x); + win = newwin(nlines,ncols,begin_y,begin_x); if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, catchall_NULL); @@ -4849,10 +4849,12 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9) /*[clinic end generated code: output=599f62b615c667ff input=5e30b15786f032aa]*/ { + char* result = NULL; + PyCursesStatefulSetupTermCalled(module); - const char *result = tparm((char *)str, i1, i2, i3, i4, i5, i6, i7, i8, i9); - if (result == NULL) { + result = tparm((char *)str,i1,i2,i3,i4,i5,i6,i7,i8,i9); + if (!result) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "tparm"); PyCursesError_SetImplementation(state, "tparm"); From 3a3964b6eea78d284a72c24424f64e482b384a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:35:30 +0200 Subject: [PATCH 08/25] simplify logic --- Lib/test/test_curses.py | 32 ----- Modules/_cursesmodule.c | 197 ++++++------------------------- Modules/clinic/_cursesmodule.c.h | 44 +------ 3 files changed, 37 insertions(+), 236 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index f767335c7b13ca..ef79bf820415f7 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -132,38 +132,6 @@ def test_use_env(self): def test_error(self): self.assertTrue(issubclass(curses.error, Exception)) - def raise_curses_error(*args): - raise curses.error(*args) - - with self.assertRaisesRegex(curses.error, "test") as cm: - raise_curses_error('test') - self.assertSequenceEqual(cm.exception.args, ('test',)) - - with self.assertRaisesRegex(curses.error, "test") as cm: - raise_curses_error('test', '1', '2') - self.assertSequenceEqual(cm.exception.args, ('test', '1', '2')) - - def test_error_attributes(self): - error = curses.error() - self.assertSequenceEqual(error.args, ()) - self.assertIsNone(error.funcname) - - error = curses.error('test') - self.assertSequenceEqual(error.args, ('test',)) - self.assertIsNone(error.funcname) - - error = curses.error('test with curses function') - error.funcname = 'curses function' - self.assertSequenceEqual(error.args, ('test with curses function',)) - self.assertEqual(error.funcname, 'curses function') - - error = curses.error('unset attributes') - error.funcname = 'a' - error.funcname = None - self.assertIsNone(error.funcname) - - self.assertRaises(TypeError, setattr, error, 'funcname', 1) - def test_create_windows(self): win = curses.newwin(5, 10) self.assertEqual(win.getbegyx(), (0, 0)) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index a19c42d2bf54b6..9fb71d21bcdb4d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -194,9 +194,8 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *win) /*[clinic input] module _curses class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" -class _curses.error "PyCursesErrorObject *" "clinic_state()->error" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a6b4ac3824e7c5c3]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ /* Indicate whether the module has already been loaded or not. */ static int curses_module_loaded = 0; @@ -214,110 +213,14 @@ static const char *curses_screen_encoding = NULL; /* Error type */ -#define CURSES_ERROR_FORMAT "%s() returned ERR" -#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" -#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first" - -typedef struct { - PyException_HEAD - /* The name of the curses function that triggered the error. */ - PyObject *funcname; -} PyCursesErrorObject; - -#define _PyCursesErrorObject_CAST(PTR) ((PyCursesErrorObject *)(PTR)) - -static int -PyCursesError_clear(PyObject *self) -{ - PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self); - Py_CLEAR(exc->funcname); - return _PyType_CAST(PyExc_Exception)->tp_clear(self); -} - -static void -PyCursesError_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - (void)PyCursesError_clear(self); - tp->tp_free(self); - Py_DECREF(tp); -} - -static int -PyCursesError_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self); - Py_VISIT(exc->funcname); - return _PyType_CAST(PyExc_Exception)->tp_traverse(self, visit, arg); -} - -/*[clinic input] -@getter -_curses.error.funcname -[clinic start generated code]*/ - -static PyObject * -_curses_error_funcname_get_impl(PyCursesErrorObject *self) -/*[clinic end generated code: output=bddac78d045d9e92 input=a0ed7b814bba25e9]*/ -{ - PyObject *res = self->funcname; - return res == NULL ? Py_None : Py_NewRef(res); -} - -/*[clinic input] -@setter -_curses.error.funcname -[clinic start generated code]*/ - -static int -_curses_error_funcname_set_impl(PyCursesErrorObject *self, PyObject *value) -/*[clinic end generated code: output=1320e03bf8c27ca8 input=e7ad8f11456a402e]*/ -{ - if (PyUnicode_Check(value) || Py_IsNone(value)) { - Py_XSETREF(self->funcname, Py_NewRef(value)); - return 0; - } - PyErr_Format(PyExc_TypeError, "expecting a str or None, got %T", value); - return -1; -} +#define CURSES_ERROR_FORMAT "%s() returned ERR" +#define CURSES_ERROR_VERBOSE_FORMAT "%s() (called by %s()) returned ERR" +#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" +#define CURSES_ERROR_NULL_VERBOSE_FORMAT "%s() (called by %s()) returned NULL" +#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first" /* Utility Error Procedures */ -static inline void -PyCursesError_SetImplementation( -#ifndef NDEBUG - cursesmodule_state *state, -#else - cursesmodule_state *Py_UNUSED(state), -#endif - const char *funcname) -{ - assert(funcname != NULL); - PyObject *exc = PyErr_GetRaisedException(); - assert(PyErr_GivenExceptionMatches(exc, state->error)); - PyObject *p_funcname = PyUnicode_FromString(funcname); - if (p_funcname == NULL) { - goto error; - } - int rc = PyObject_SetAttrString(exc, "funcname", p_funcname); - Py_DECREF(p_funcname); - if (rc < 0) { - goto error; - } - -restore: - PyErr_SetRaisedException(exc); - return; - -error: - // The curses exception is likely more important than the - // exceptions that we get if we fail to set the attribute. - PyErr_Clear(); - goto restore; -} - /* * Format a curses error. * @@ -335,10 +238,18 @@ _PyCursesSetError(cursesmodule_state *state, return; } if (simple_funcname == NULL) { - simple_funcname = curses_funcname; + PyErr_Format(state->error, CURSES_ERROR_FORMAT, curses_funcname); + } + else if (curses_funcname == NULL) { + PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); + } + else if (strcmp(simple_funcname, curses_funcname) == 0) { + PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); + } + else { + PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, + curses_funcname, simple_funcname); } - PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); - PyCursesError_SetImplementation(state, curses_funcname); } static void @@ -1673,7 +1584,6 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "derwin"); - PyCursesError_SetImplementation(state, "derwin"); return NULL; } @@ -1830,9 +1740,8 @@ _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, PyErr_CheckSignals(); if (!PyErr_Occurred()) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_SetString(state->error, "no input"); const char *funcname = group_right_1 ? "mvwgetch" : "wgetch"; - PyCursesError_SetImplementation(state, funcname); + PyErr_Format(state->error, "getkey(): %s(): no input", funcname); } return NULL; } else if (rtn <= 255) { @@ -1894,7 +1803,7 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_SetString(state->error, "no input"); const char *funcname = group_right_1 ? "mvwget_wch" : "wget_wch"; - PyCursesError_SetImplementation(state, funcname); + PyErr_Format(state->error, "get_wch(): %s(): no input", funcname); return NULL; } if (ct == KEY_CODE_YES) @@ -2752,8 +2661,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_SetString(state->error, catchall_NULL); - PyCursesError_SetImplementation(state, curses_funcname); + PyErr_Format(state->error, CURSES_ERROR_NULL_VERBOSE_FORMAT, + curses_funcname, "subwin"); return NULL; } @@ -2916,29 +2825,6 @@ PyCursesWindow_set_encoding(PyObject *op, PyObject *value, void *Py_UNUSED(ignor #include "clinic/_cursesmodule.c.h" #undef clinic_state -static PyGetSetDef PyCursesError_Type_getsets[] = { - _CURSES_ERROR_FUNCNAME_GETSETDEF - {NULL} -}; - -static PyType_Slot PyCursesError_Type_slots[] = { - {Py_tp_getset, PyCursesError_Type_getsets}, - {Py_tp_dealloc, PyCursesError_dealloc}, - {Py_tp_traverse, PyCursesError_traverse}, - {Py_tp_clear, PyCursesError_clear}, - {0, NULL}, -}; - -static PyType_Spec PyCursesError_Type_spec = { - .name = "_curses.error", - .basicsize = sizeof(PyCursesErrorObject), - .flags = Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_HAVE_GC, - .slots = PyCursesError_Type_slots, -}; - static PyMethodDef PyCursesWindow_methods[] = { _CURSES_WINDOW_ADDCH_METHODDEF _CURSES_WINDOW_ADDNSTR_METHODDEF @@ -3547,8 +3433,7 @@ _curses_getwin(PyObject *module, PyObject *file) win = getwin(fp); if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, catchall_NULL); - PyCursesError_SetImplementation(state, "getwin"); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "getwin"); goto error; } cursesmodule_state *state = get_cursesmodule_state(module); @@ -3730,8 +3615,7 @@ _curses_initscr_impl(PyObject *module) if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, catchall_NULL); - PyCursesError_SetImplementation(state, "initscr"); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "initscr"); return NULL; } @@ -3891,7 +3775,6 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, s); - PyCursesError_SetImplementation(state, "setupterm"); return NULL; } @@ -4212,8 +4095,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, catchall_NULL); - PyCursesError_SetImplementation(state, "newpad"); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newpad"); return NULL; } @@ -4254,8 +4136,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, win = newwin(nlines,ncols,begin_y,begin_x); if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_SetString(state->error, catchall_NULL); - PyCursesError_SetImplementation(state, "newwin"); + PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newwin"); return NULL; } @@ -4857,7 +4738,6 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, if (!result) { cursesmodule_state *state = get_cursesmodule_state(module); PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "tparm"); - PyCursesError_SetImplementation(state, "tparm"); return NULL; } @@ -5348,22 +5228,7 @@ cursesmodule_exec(PyObject *module) curses_module_loaded = 1; cursesmodule_state *state = get_cursesmodule_state(module); - /* Initialize error type */ - PyObject *bases = PyTuple_Pack(1, PyExc_Exception); - if (bases == NULL) { - return -1; - } - state->error = PyType_FromModuleAndSpec(module, &PyCursesError_Type_spec, - bases); - Py_DECREF(bases); - if (state->error == NULL) { - return -1; - } - if (PyModule_AddType(module, _PyType_CAST(state->error)) < 0) { - return -1; - } - - /* Initialize window type */ + /* Initialize object type */ state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( module, &PyCursesWindow_Type_spec, NULL); if (state->window_type == NULL) { @@ -5396,6 +5261,16 @@ cursesmodule_exec(PyObject *module) return -1; } + /* For exception curses.error */ + state->error = PyErr_NewException("_curses.error", NULL, NULL); + if (state->error == NULL) { + return -1; + } + rc = PyDict_SetItemString(module_dict, "error", state->error); + if (rc < 0) { + return -1; + } + /* Make the version available */ PyObject *curses_version = PyBytes_FromString(PyCursesVersion); if (curses_version == NULL) { diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 8d418c2dc21d96..0346cc88782941 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -8,48 +8,6 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_CheckPositional() -#if !defined(_curses_error_funcname_DOCSTR) -# define _curses_error_funcname_DOCSTR NULL -#endif -#if defined(_CURSES_ERROR_FUNCNAME_GETSETDEF) -# undef _CURSES_ERROR_FUNCNAME_GETSETDEF -# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, (setter)_curses_error_funcname_set, _curses_error_funcname_DOCSTR}, -#else -# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, NULL, _curses_error_funcname_DOCSTR}, -#endif - -static PyObject * -_curses_error_funcname_get_impl(PyCursesErrorObject *self); - -static PyObject * -_curses_error_funcname_get(PyObject *self, void *Py_UNUSED(context)) -{ - return _curses_error_funcname_get_impl((PyCursesErrorObject *)self); -} - -#if !defined(_curses_error_funcname_DOCSTR) -# define _curses_error_funcname_DOCSTR NULL -#endif -#if defined(_CURSES_ERROR_FUNCNAME_GETSETDEF) -# undef _CURSES_ERROR_FUNCNAME_GETSETDEF -# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", (getter)_curses_error_funcname_get, (setter)_curses_error_funcname_set, _curses_error_funcname_DOCSTR}, -#else -# define _CURSES_ERROR_FUNCNAME_GETSETDEF {"funcname", NULL, (setter)_curses_error_funcname_set, NULL}, -#endif - -static int -_curses_error_funcname_set_impl(PyCursesErrorObject *self, PyObject *value); - -static int -_curses_error_funcname_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -{ - int return_value; - - return_value = _curses_error_funcname_set_impl((PyCursesErrorObject *)self, value); - - return return_value; -} - PyDoc_STRVAR(_curses_window_addch__doc__, "addch([y, x,] ch, [attr=_curses.A_NORMAL])\n" "Paint the character.\n" @@ -4436,4 +4394,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=98ab9ae9474d55e9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=acae2eb9cf75e76d input=a9049054013a1b77]*/ From 92e62cfee4ee40ae4422ba84071fc63982b00a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:38:32 +0200 Subject: [PATCH 09/25] simplify logic x2 --- Doc/library/curses.rst | 6 ------ Lib/test/test_curses.py | 2 +- .../Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst | 5 ++--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index eff255346cb1e5..6c7fc721a3e0fb 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -59,12 +59,6 @@ The module :mod:`curses` defines the following exception: Exception raised when a curses library function returns an error. - .. attribute:: funcname - - Attribute storing the name of the curses C function or macro - responsible for this exception, possibly ``None`` if no such - information is available. - .. note:: Whenever *x* or *y* arguments to a function or a method are optional, they diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index ef79bf820415f7..b20afe88facf7c 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -130,7 +130,7 @@ def test_use_env(self): curses.use_env(True) def test_error(self): - self.assertTrue(issubclass(curses.error, Exception)) + self.assertIsSubclass(curses.error, Exception) def test_create_windows(self): win = curses.newwin(5, 10) diff --git a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst index 29bc7b6325383b..132aaf8315c9c1 100644 --- a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst +++ b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst @@ -1,3 +1,2 @@ -Add :attr:`~curses.error.funcname` to :exc:`curses.error` objects to indicate -which :mod:`curses` C function or macro was responsible for the exception. -Patch by Bénédikt Tran. +If possible, indicate which :mod:`curses` C function or macro is responsible +for raising a :exc.`curses.error` exception. Patch by Bénédikt Tran. From 4d8f47ffb2f4517d410eb3a8cbe194b96c0f7d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:43:29 +0200 Subject: [PATCH 10/25] reduce diff again! --- Modules/_cursesmodule.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 9fb71d21bcdb4d..4f78da1588a02e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1076,7 +1076,6 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 0) { return NULL; } - if (use_attr) { attr_old = getattrs(self->win); (void)wattrset(self->win,attr); @@ -1406,7 +1405,7 @@ _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, return NULL; } } - (void)box(self->win, ch1, ch2); + (void)box(self->win,ch1,ch2); Py_RETURN_NONE; } @@ -1504,15 +1503,14 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) attr = attr & A_ATTRIBUTES; if (use_xy) { - rtn = mvwchgat(self->win, y, x, num, attr, color, NULL); + rtn = mvwchgat(self->win,y,x,num,attr,color,NULL); curses_funcname = "mvwchgat"; - (void)touchline(self->win, y, 1); - } - else { - getyx(self->win, y, x); - rtn = wchgat(self->win, num, attr, color, NULL); + (void)touchline(self->win,y,1); + } else { + getyx(self->win,y,x); + rtn = wchgat(self->win,num,attr,color,NULL); curses_funcname = "wchgat"; - (void)touchline(self->win, y, 1); + (void)touchline(self->win,y,1); } return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", curses_funcname); } @@ -1788,7 +1786,7 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, Py_BEGIN_ALLOW_THREADS if (!group_right_1) { - ct = wget_wch(self->win, &rtn); + ct = wget_wch(self->win ,&rtn); } else { ct = mvwget_wch(self->win, y, x, &rtn); @@ -3761,17 +3759,13 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) } if (!curses_setupterm_called && setupterm((char *)term, fd, &err) == ERR) { - const char *s; + const char *s = "setupterm: unknown error"; if (err == 0) { s = "setupterm: could not find terminal"; - } - else if (err == -1) { + } else if (err == -1) { s = "setupterm: could not find terminfo database"; } - else { - s = "setupterm: unknown error"; - } cursesmodule_state *state = get_cursesmodule_state(module); PyErr_SetString(state->error, s); From 5b8ff990c5370e479ce8a3183978e657c0e7df5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:47:29 +0200 Subject: [PATCH 11/25] simplify logic x3 --- Modules/_cursesmodule.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4f78da1588a02e..f011205cb28ed0 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -243,9 +243,6 @@ _PyCursesSetError(cursesmodule_state *state, else if (curses_funcname == NULL) { PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); } - else if (strcmp(simple_funcname, curses_funcname) == 0) { - PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); - } else { PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, curses_funcname, simple_funcname); @@ -262,7 +259,7 @@ PyCursesSetError_From(PyObject *, const char *, const char *); static inline void PyCursesSetError(PyObject *module, const char *funcname) { - PyCursesSetError_From(module, funcname, funcname); + PyCursesSetError_From(module, funcname, NULL); } static void @@ -281,7 +278,7 @@ PyCursesSetError_ForWin_From(PyCursesWindowObject *, static inline void PyCursesSetError_ForWin(PyCursesWindowObject *win, const char *funcname) { - PyCursesSetError_ForWin_From(win, funcname, funcname); + PyCursesSetError_ForWin_From(win, funcname, NULL); } static void @@ -374,13 +371,13 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam * on success and setting an exception on error. */ -static PyObject *PyCursesCheckERR_From(PyObject *, int, - const char *, const char *); +static PyObject * +PyCursesCheckERR_From(PyObject *, int, const char *, const char *); static inline PyObject * PyCursesCheckERR(PyObject *module, int code, const char *funcname) { - return PyCursesCheckERR_From(module, code, funcname, funcname); + return PyCursesCheckERR_From(module, code, funcname, NULL); } static PyObject * @@ -402,7 +399,7 @@ static inline PyObject * PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, const char *funcname) { - return PyCursesCheckERR_ForWin_From(win, code, funcname, funcname); + return PyCursesCheckERR_ForWin_From(win, code, funcname, NULL); } static PyObject * From 43d2e9943142afc6f8f07cea75d7781921b02325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:58:09 +0200 Subject: [PATCH 12/25] lint --- .../next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst index 132aaf8315c9c1..ec8f3a750065ff 100644 --- a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst +++ b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst @@ -1,2 +1,2 @@ If possible, indicate which :mod:`curses` C function or macro is responsible -for raising a :exc.`curses.error` exception. Patch by Bénédikt Tran. +for raising a :exc:`curses.error` exception. Patch by Bénédikt Tran. From 12f0b30fcf997aae86ece101dc4bfb74d31abbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 21:42:51 +0200 Subject: [PATCH 13/25] reduce diff x4 --- Modules/_cursesmodule.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index f011205cb28ed0..9496cde7e45d4a 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -392,8 +392,9 @@ PyCursesCheckERR_From(PyObject *module, int code, return NULL; } -static PyObject *PyCursesCheckERR_ForWin_From(PyCursesWindowObject *, int, - const char *, const char *); +static PyObject * +PyCursesCheckERR_ForWin_From(PyCursesWindowObject *, int, + const char *, const char *); static inline PyObject * PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, @@ -1189,11 +1190,11 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, const char *str = PyBytes_AS_STRING(bytesobj); simple_funcname = "addnstr"; if (use_xy) { - rtn = mvwaddnstr(self->win, y, x, str, n); + rtn = mvwaddnstr(self->win,y,x,str,n); curses_funcname = "mvwaddnstr"; } else { - rtn = waddnstr(self->win, str, n); + rtn = waddnstr(self->win,str,n); curses_funcname = "waddnstr"; } Py_DECREF(bytesobj); @@ -1501,13 +1502,13 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) if (use_xy) { rtn = mvwchgat(self->win,y,x,num,attr,color,NULL); - curses_funcname = "mvwchgat"; (void)touchline(self->win,y,1); + curses_funcname = "mvwchgat"; } else { getyx(self->win,y,x); rtn = wchgat(self->win,num,attr,color,NULL); - curses_funcname = "wchgat"; (void)touchline(self->win,y,1); + curses_funcname = "wchgat"; } return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", curses_funcname); } @@ -2140,11 +2141,11 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 2) { simple_funcname = "inswstr"; if (use_xy) { - rtn = mvwins_wstr(self->win, y, x, wstr); + rtn = mvwins_wstr(self->win,y,x,wstr); curses_funcname = "mvwins_wstr"; } else { - rtn = wins_wstr(self->win, wstr); + rtn = wins_wstr(self->win,wstr); curses_funcname = "wins_wstr"; } PyMem_Free(wstr); @@ -2152,14 +2153,14 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, else #endif { - const char *text = PyBytes_AS_STRING(bytesobj); + const char *str = PyBytes_AS_STRING(bytesobj); simple_funcname = "insstr"; if (use_xy) { - rtn = mvwinsstr(self->win, y, x, text); + rtn = mvwinsstr(self->win,y,x,str); curses_funcname = "mvwinsstr"; } else { - rtn = winsstr(self->win, text); + rtn = winsstr(self->win,str); curses_funcname = "winsstr"; } Py_DECREF(bytesobj); @@ -2235,11 +2236,11 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 2) { simple_funcname = "insn_wstr"; if (use_xy) { - rtn = mvwins_nwstr(self->win, y, x, wstr, n); + rtn = mvwins_nwstr(self->win,y,x,wstr,n); curses_funcname = "mvwins_nwstr"; } else { - rtn = wins_nwstr(self->win, wstr, n); + rtn = wins_nwstr(self->win,wstr,n); curses_funcname = "wins_nwstr"; } PyMem_Free(wstr); @@ -2247,14 +2248,14 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, else #endif { - const char *text = PyBytes_AS_STRING(bytesobj); + const char *str = PyBytes_AS_STRING(bytesobj); simple_funcname = "insnstr"; if (use_xy) { - rtn = mvwinsnstr(self->win, y, x, text, n); + rtn = mvwinsnstr(self->win,y,x,str,n); curses_funcname = "mvwinsnstr"; } else { - rtn = winsnstr(self->win, text, n); + rtn = winsnstr(self->win,str,n); curses_funcname = "winsnstr"; } Py_DECREF(bytesobj); From eaaad716af69fd72d19530a909d84f79b3bc2617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 25 Apr 2025 21:46:19 +0200 Subject: [PATCH 14/25] reduce diff x5 --- Modules/_cursesmodule.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 9496cde7e45d4a..b414220e6df1c0 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -992,7 +992,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, wstr[1] = L'\0'; setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL); if (coordinates_group) { - rtn = mvwadd_wch(self->win, y, x, &wcval); + rtn = mvwadd_wch(self->win,y,x, &wcval); curses_funcname = "mvwadd_wch"; } else { @@ -1007,7 +1007,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, if (type == 1) { simple_funcname = "addch"; if (coordinates_group) { - rtn = mvwaddch(self->win, y, x, cch | (attr_t) attr); + rtn = mvwaddch(self->win,y,x, cch | (attr_t) attr); curses_funcname = "mvwaddch"; } else { @@ -1082,11 +1082,11 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 2) { simple_funcname = "addwstr"; if (use_xy) { - rtn = mvwaddwstr(self->win, y, x, wstr); + rtn = mvwaddwstr(self->win,y,x,wstr); curses_funcname = "mvwaddwstr"; } else { - rtn = waddwstr(self->win, wstr); + rtn = waddwstr(self->win,wstr); curses_funcname = "waddwstr"; } PyMem_Free(wstr); @@ -1094,14 +1094,14 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, else #endif { - const char *text = PyBytes_AS_STRING(bytesobj); + const char *str = PyBytes_AS_STRING(bytesobj); simple_funcname = "addstr"; if (use_xy) { - rtn = mvwaddstr(self->win, y, x, text); + rtn = mvwaddstr(self->win,y,x,str); curses_funcname = "mvwaddstr"; } else { - rtn = waddstr(self->win, text); + rtn = waddstr(self->win,str); curses_funcname = "waddstr"; } Py_DECREF(bytesobj); @@ -1175,11 +1175,11 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, if (strtype == 2) { simple_funcname = "addnwstr"; if (use_xy) { - rtn = mvwaddnwstr(self->win, y, x, wstr, n); + rtn = mvwaddnwstr(self->win,y,x,wstr,n); curses_funcname = "mvwaddnwstr"; } else { - rtn = waddnwstr(self->win, wstr, n); + rtn = waddnwstr(self->win,wstr,n); curses_funcname = "waddnwstr"; } PyMem_Free(wstr); @@ -3757,7 +3757,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) } if (!curses_setupterm_called && setupterm((char *)term, fd, &err) == ERR) { - const char *s = "setupterm: unknown error"; + const char* s = "setupterm: unknown error"; if (err == 0) { s = "setupterm: could not find terminal"; From b96b54261aafed7f5ef7d60e12ce89c447ccc36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 26 Apr 2025 09:38:57 +0200 Subject: [PATCH 15/25] simplify even more! --- Modules/_cursesmodule.c | 166 ++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 93 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index b414220e6df1c0..2080de67e105cf 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -224,28 +224,28 @@ static const char *curses_screen_encoding = NULL; /* * Format a curses error. * - * The function name in the error message is 'simple_funcname'. - * If 'simple_funcname' is NULL, it falls back 'curses_funcname'. + * A NULL 'python_funcname' falls back to 'curses_funcname' and vice-versa. + * If both names are NULL, the error message is 'catchall_ERR'. */ static void _PyCursesSetError(cursesmodule_state *state, - const char *simple_funcname, + const char *python_funcname, const char *curses_funcname) { assert(!PyErr_Occurred()); - if (simple_funcname == NULL && curses_funcname == NULL) { + if (python_funcname == NULL && curses_funcname == NULL) { PyErr_SetString(state->error, catchall_ERR); return; } - if (simple_funcname == NULL) { + if (python_funcname == NULL) { PyErr_Format(state->error, CURSES_ERROR_FORMAT, curses_funcname); } else if (curses_funcname == NULL) { - PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname); + PyErr_Format(state->error, CURSES_ERROR_FORMAT, python_funcname); } else { PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, - curses_funcname, simple_funcname); + curses_funcname, python_funcname); } } @@ -264,11 +264,11 @@ PyCursesSetError(PyObject *module, const char *funcname) static void PyCursesSetError_From(PyObject *module, - const char *simple_funcname, + const char *python_funcname, const char *curses_funcname) { cursesmodule_state *state = get_cursesmodule_state(module); - _PyCursesSetError(state, simple_funcname, curses_funcname); + _PyCursesSetError(state, python_funcname, curses_funcname); } static void @@ -283,11 +283,11 @@ PyCursesSetError_ForWin(PyCursesWindowObject *win, const char *funcname) static void PyCursesSetError_ForWin_From(PyCursesWindowObject *win, - const char *simple_funcname, + const char *python_funcname, const char *curses_funcname) { cursesmodule_state *state = get_cursesmodule_state_by_win(win); - _PyCursesSetError(state, simple_funcname, curses_funcname); + _PyCursesSetError(state, python_funcname, curses_funcname); } /* Utility Checking Procedures */ @@ -382,13 +382,13 @@ PyCursesCheckERR(PyObject *module, int code, const char *funcname) static PyObject * PyCursesCheckERR_From(PyObject *module, int code, - const char *simple_funcname, + const char *python_funcname, const char *curses_funcname) { if (code != ERR) { Py_RETURN_NONE; } - PyCursesSetError_From(module, simple_funcname, curses_funcname); + PyCursesSetError_From(module, python_funcname, curses_funcname); return NULL; } @@ -405,13 +405,13 @@ PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, static PyObject * PyCursesCheckERR_ForWin_From(PyCursesWindowObject *win, int code, - const char *simple_funcname, + const char *python_funcname, const char *curses_funcname) { if (code != ERR) { Py_RETURN_NONE; } - PyCursesSetError_ForWin_From(win, simple_funcname, curses_funcname); + PyCursesSetError_ForWin_From(win, python_funcname, curses_funcname); return NULL; } @@ -983,21 +983,20 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, wchar_t wstr[2]; cchar_t wcval; #endif - const char *simple_funcname, *curses_funcname; + const char *funcname; #ifdef HAVE_NCURSESW type = PyCurses_ConvertToCchar_t(self, ch, &cch, wstr); if (type == 2) { - simple_funcname = "add_wch"; wstr[1] = L'\0'; setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL); if (coordinates_group) { rtn = mvwadd_wch(self->win,y,x, &wcval); - curses_funcname = "mvwadd_wch"; + funcname = "mvwadd_wch"; } else { rtn = wadd_wch(self->win, &wcval); - curses_funcname = "wadd_wch"; + funcname = "wadd_wch"; } } else @@ -1005,22 +1004,19 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, type = PyCurses_ConvertToCchar_t(self, ch, &cch); #endif if (type == 1) { - simple_funcname = "addch"; if (coordinates_group) { rtn = mvwaddch(self->win,y,x, cch | (attr_t) attr); - curses_funcname = "mvwaddch"; + funcname = "mvwaddch"; } else { rtn = waddch(self->win, cch | (attr_t) attr); - curses_funcname = "waddch"; + funcname = "waddch"; } } else { return NULL; } - return PyCursesCheckERR_ForWin_From(self, rtn, - simple_funcname, - curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "addch", funcname); } /*[clinic input] @@ -1064,7 +1060,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *simple_funcname, *curses_funcname; + const char *funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); @@ -1080,14 +1076,13 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - simple_funcname = "addwstr"; if (use_xy) { rtn = mvwaddwstr(self->win,y,x,wstr); - curses_funcname = "mvwaddwstr"; + funcname = "mvwaddwstr"; } else { rtn = waddwstr(self->win,wstr); - curses_funcname = "waddwstr"; + funcname = "waddwstr"; } PyMem_Free(wstr); } @@ -1095,22 +1090,19 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, #endif { const char *str = PyBytes_AS_STRING(bytesobj); - simple_funcname = "addstr"; if (use_xy) { rtn = mvwaddstr(self->win,y,x,str); - curses_funcname = "mvwaddstr"; + funcname = "mvwaddstr"; } else { rtn = waddstr(self->win,str); - curses_funcname = "waddstr"; + funcname = "waddstr"; } Py_DECREF(bytesobj); } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, - simple_funcname, - curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "addstr", funcname); } /*[clinic input] @@ -1157,7 +1149,7 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *simple_funcname, *curses_funcname; + const char *funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); @@ -1173,14 +1165,13 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - simple_funcname = "addnwstr"; if (use_xy) { rtn = mvwaddnwstr(self->win,y,x,wstr,n); - curses_funcname = "mvwaddnwstr"; + funcname = "mvwaddnwstr"; } else { rtn = waddnwstr(self->win,wstr,n); - curses_funcname = "waddnwstr"; + funcname = "waddnwstr"; } PyMem_Free(wstr); } @@ -1188,22 +1179,19 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif { const char *str = PyBytes_AS_STRING(bytesobj); - simple_funcname = "addnstr"; if (use_xy) { rtn = mvwaddnstr(self->win,y,x,str,n); - curses_funcname = "mvwaddnstr"; + funcname = "mvwaddnstr"; } else { rtn = waddnstr(self->win,str,n); - curses_funcname = "waddnstr"; + funcname = "waddnstr"; } Py_DECREF(bytesobj); } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, - simple_funcname, - curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "addnstr", funcname); } /*[clinic input] @@ -1461,7 +1449,7 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); int rtn; - const char *curses_funcname; + const char *funcname; int x, y; int num = -1; short color; @@ -1503,14 +1491,14 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) if (use_xy) { rtn = mvwchgat(self->win,y,x,num,attr,color,NULL); (void)touchline(self->win,y,1); - curses_funcname = "mvwchgat"; + funcname = "mvwchgat"; } else { getyx(self->win,y,x); rtn = wchgat(self->win,num,attr,color,NULL); (void)touchline(self->win,y,1); - curses_funcname = "wchgat"; + funcname = "wchgat"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", funcname); } #endif @@ -1534,16 +1522,16 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, /*[clinic end generated code: output=22e77bb9fa11b461 input=d2f79e630a4fc6d0]*/ { int rtn; - const char *curses_funcname; + const char *funcname; if (!group_right_1) { rtn = wdelch(self->win); - curses_funcname = "wdelch"; + funcname = "wdelch"; } else { rtn = py_mvwdelch(self->win, y, x); - curses_funcname = "mvwdelch"; + funcname = "mvwdelch"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "wdelch", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "wdelch", funcname); } /*[clinic input] @@ -1611,19 +1599,19 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, return NULL; int rtn; - const char *curses_funcname; + const char *funcname; #ifdef py_is_pad if (py_is_pad(self->win)) { rtn = pechochar(self->win, ch_ | (attr_t)attr); - curses_funcname = "pechochar"; + funcname = "pechochar"; } else #endif { rtn = wechochar(self->win, ch_ | (attr_t)attr); - curses_funcname = "wechochar"; + funcname = "wechochar"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "echochar", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "echochar", funcname); } #ifdef NCURSES_MOUSE_VERSION @@ -1970,17 +1958,17 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, if (!PyCurses_ConvertToChtype(self, ch, &ch_)) return NULL; - const char *curses_funcname; + const char *funcname; if (!group_left_1) { rtn = winsch(self->win, ch_ | (attr_t)attr); - curses_funcname = "winsch"; + funcname = "winsch"; } else { rtn = mvwinsch(self->win, y, x, ch_ | (attr_t)attr); - curses_funcname = "mvwwinsch"; + funcname = "mvwwinsch"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "insch", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "insch", funcname); } /*[clinic input] @@ -2123,7 +2111,7 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *simple_funcname, *curses_funcname; + const char *funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); @@ -2139,14 +2127,13 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - simple_funcname = "inswstr"; if (use_xy) { rtn = mvwins_wstr(self->win,y,x,wstr); - curses_funcname = "mvwins_wstr"; + funcname = "mvwins_wstr"; } else { rtn = wins_wstr(self->win,wstr); - curses_funcname = "wins_wstr"; + funcname = "wins_wstr"; } PyMem_Free(wstr); } @@ -2154,22 +2141,19 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, #endif { const char *str = PyBytes_AS_STRING(bytesobj); - simple_funcname = "insstr"; if (use_xy) { rtn = mvwinsstr(self->win,y,x,str); - curses_funcname = "mvwinsstr"; + funcname = "mvwinsstr"; } else { rtn = winsstr(self->win,str); - curses_funcname = "winsstr"; + funcname = "winsstr"; } Py_DECREF(bytesobj); } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, - simple_funcname, - curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "insstr", funcname); } /*[clinic input] @@ -2218,7 +2202,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif attr_t attr_old = A_NORMAL; int use_xy = group_left_1, use_attr = group_right_1; - const char *simple_funcname, *curses_funcname; + const char *funcname; #ifdef HAVE_NCURSESW strtype = PyCurses_ConvertToString(self, str, &bytesobj, &wstr); @@ -2234,14 +2218,13 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW if (strtype == 2) { - simple_funcname = "insn_wstr"; if (use_xy) { rtn = mvwins_nwstr(self->win,y,x,wstr,n); - curses_funcname = "mvwins_nwstr"; + funcname = "mvwins_nwstr"; } else { rtn = wins_nwstr(self->win,wstr,n); - curses_funcname = "wins_nwstr"; + funcname = "wins_nwstr"; } PyMem_Free(wstr); } @@ -2249,22 +2232,19 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, #endif { const char *str = PyBytes_AS_STRING(bytesobj); - simple_funcname = "insnstr"; if (use_xy) { rtn = mvwinsnstr(self->win,y,x,str,n); - curses_funcname = "mvwinsnstr"; + funcname = "mvwinsnstr"; } else { rtn = winsnstr(self->win,str,n); - curses_funcname = "winsnstr"; + funcname = "winsnstr"; } Py_DECREF(bytesobj); } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, - simple_funcname, - curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "insnstr", funcname); } /*[clinic input] @@ -2640,25 +2620,25 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, /*[clinic end generated code: output=93e898afc348f59a input=2129fa47fd57721c]*/ { WINDOW *win; - const char *curses_funcname; + const char *funcname; /* printf("Subwin: %i %i %i %i \n", nlines, ncols, begin_y, begin_x); */ #ifdef py_is_pad if (py_is_pad(self->win)) { win = subpad(self->win, nlines, ncols, begin_y, begin_x); - curses_funcname = "subpad"; + funcname = "subpad"; } else #endif { win = subwin(self->win, nlines, ncols, begin_y, begin_x); - curses_funcname = "subwin"; + funcname = "subwin"; } if (win == NULL) { cursesmodule_state *state = get_cursesmodule_state_by_win(self); PyErr_Format(state->error, CURSES_ERROR_NULL_VERBOSE_FORMAT, - curses_funcname, "subwin"); + funcname, "subwin"); return NULL; } @@ -2686,16 +2666,16 @@ _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, /*[clinic end generated code: output=4541a8a11852d360 input=c969ca0cfabbdbec]*/ { int rtn; - const char *curses_funcname; + const char *funcname; if (!group_right_1) { rtn = scroll(self->win); - curses_funcname = "scroll"; + funcname = "scroll"; } else { rtn = wscrl(self->win, lines); - curses_funcname = "wscrl"; + funcname = "wscrl"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "scroll", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "scroll", funcname); } /*[clinic input] @@ -2720,16 +2700,16 @@ _curses_window_touchline_impl(PyCursesWindowObject *self, int start, /*[clinic end generated code: output=65d05b3f7438c61d input=a98aa4f79b6be845]*/ { int rtn; - const char *curses_funcname; + const char *funcname; if (!group_right_1) { rtn = touchline(self->win, start, count); - curses_funcname = "touchline"; + funcname = "touchline"; } else { rtn = wtouchln(self->win, start, count, changed); - curses_funcname = "wtouchln"; + funcname = "wtouchln"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "touchline", curses_funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "touchline", funcname); } /*[clinic input] From 39f102fded687b81f436fbabac03e48367ac17c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 26 Apr 2025 09:47:48 +0200 Subject: [PATCH 16/25] nits(cosmetics) --- Modules/_cursesmodule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 2080de67e105cf..12406b8b1f0629 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -235,9 +235,8 @@ _PyCursesSetError(cursesmodule_state *state, assert(!PyErr_Occurred()); if (python_funcname == NULL && curses_funcname == NULL) { PyErr_SetString(state->error, catchall_ERR); - return; } - if (python_funcname == NULL) { + else if (python_funcname == NULL) { PyErr_Format(state->error, CURSES_ERROR_FORMAT, curses_funcname); } else if (curses_funcname == NULL) { @@ -301,7 +300,7 @@ PyCursesSetError_ForWin_From(PyCursesWindowObject *win, * have a direct access to the module's state, '_curses.error' * is imported on demand. */ -static inline int +static int _PyCursesCheckFunction(int called, const char *funcname) { if (called == TRUE) { @@ -323,8 +322,9 @@ _PyCursesCheckFunction(int called, const char *funcname) * * The exception type is obtained from the 'module' state. */ -static inline int -_PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcname) +static int +_PyCursesStatefulCheckFunction(PyObject *module, + int called, const char *funcname) { if (called == TRUE) { return 1; From 6bc9c3e2728507023ffcbb3d3d92eb94d97e4de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 27 Apr 2025 13:07:17 +0200 Subject: [PATCH 17/25] update messages --- Modules/_cursesmodule.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 12406b8b1f0629..73375300783dde 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -270,16 +270,6 @@ PyCursesSetError_From(PyObject *module, _PyCursesSetError(state, python_funcname, curses_funcname); } -static void -PyCursesSetError_ForWin_From(PyCursesWindowObject *, - const char *, const char *); - -static inline void -PyCursesSetError_ForWin(PyCursesWindowObject *win, const char *funcname) -{ - PyCursesSetError_ForWin_From(win, funcname, NULL); -} - static void PyCursesSetError_ForWin_From(PyCursesWindowObject *win, const char *python_funcname, @@ -1531,7 +1521,7 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, rtn = py_mvwdelch(self->win, y, x); funcname = "mvwdelch"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "wdelch", funcname); + return PyCursesCheckERR_ForWin_From(self, rtn, "delch", funcname); } /*[clinic input] @@ -1913,7 +1903,7 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, return NULL; if (group_left_1) { if (wmove(self->win, y, x) == ERR) { - PyCursesSetError_ForWin(self, "wmove"); + PyCursesSetError_ForWin_From(self, "hline", "wmove"); return NULL; } } @@ -2331,7 +2321,8 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) rtn = pnoutrefresh(self->win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin(self, rtn, "pnoutrefresh"); + return PyCursesCheckERR_ForWin_From(self, rtn, + "noutrefresh", "pnoutrefresh"); } if (group_right_1) { PyErr_SetString(PyExc_TypeError, @@ -2342,7 +2333,8 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) Py_BEGIN_ALLOW_THREADS rtn = wnoutrefresh(self->win); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin(self, rtn, "wnoutrefresh"); + return PyCursesCheckERR_ForWin_From(self, rtn, + "noutrefresh", "wnoutrefresh"); } /*[clinic input] @@ -2384,7 +2376,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, if (group_right_1) { rtn = copywin(self->win, destwin->win, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, TRUE); - return PyCursesCheckERR_ForWin(self, rtn, "copywin"); + return PyCursesCheckERR_ForWin_From(self, rtn, "overlay", "copywin"); } else { rtn = overlay(self->win, destwin->win); @@ -2432,7 +2424,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, if (group_right_1) { rtn = copywin(self->win, destwin->win, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, FALSE); - return PyCursesCheckERR_ForWin(self, rtn, "copywin"); + return PyCursesCheckERR_ForWin_From(self, rtn, "overwrite", "copywin"); } else { rtn = overwrite(self->win, destwin->win); @@ -2556,7 +2548,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, rtn = prefresh(self->win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin(self, rtn, "prefresh"); + return PyCursesCheckERR_ForWin_From(self, rtn, "refresh", "prefresh"); } #endif if (group_right_1) { @@ -2567,7 +2559,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, Py_BEGIN_ALLOW_THREADS rtn = wrefresh(self->win); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin_From(self, rtn, "prefresh", "wrefresh"); + return PyCursesCheckERR_ForWin_From(self, rtn, "refresh", "wrefresh"); } /*[clinic input] @@ -2590,7 +2582,7 @@ _curses_window_setscrreg_impl(PyCursesWindowObject *self, int top, /*[clinic end generated code: output=486ab5db218d2b1a input=1b517b986838bf0e]*/ { int rtn = wsetscrreg(self->win, top, bottom); - return PyCursesCheckERR_ForWin(self, rtn, "wsetscrreg"); + return PyCursesCheckERR_ForWin_From(self, rtn, "setscrreg", "wsetscrreg"); } /*[clinic input] @@ -2748,7 +2740,7 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, return NULL; if (group_left_1) { if (wmove(self->win, y, x) == ERR) { - PyCursesSetError_ForWin(self, "wmove"); + PyCursesSetError_ForWin_From(self, "vline", "wmove"); return NULL; } } From 5addb78e0f158baaa4c355d9f71337635e21921e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 27 Apr 2025 13:15:23 +0200 Subject: [PATCH 18/25] remove un-necessary prototypes and rearrange code --- Modules/_cursesmodule.c | 52 +++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 73375300783dde..8c174a96e5d24e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -249,16 +249,12 @@ _PyCursesSetError(cursesmodule_state *state, } static void -PyCursesSetError_From(PyObject *, const char *, const char *); - -/* - * Format a curses error using 'funcname' as the displayed - * function name and underlying curses function name. - */ -static inline void -PyCursesSetError(PyObject *module, const char *funcname) +PyCursesSetError_ForWin_From(PyCursesWindowObject *win, + const char *python_funcname, + const char *curses_funcname) { - PyCursesSetError_From(module, funcname, NULL); + cursesmodule_state *state = get_cursesmodule_state_by_win(win); + _PyCursesSetError(state, python_funcname, curses_funcname); } static void @@ -270,13 +266,14 @@ PyCursesSetError_From(PyObject *module, _PyCursesSetError(state, python_funcname, curses_funcname); } -static void -PyCursesSetError_ForWin_From(PyCursesWindowObject *win, - const char *python_funcname, - const char *curses_funcname) +/* + * Format a curses error using 'funcname' as the displayed + * function name and underlying curses function name. + */ +static inline void +PyCursesSetError(PyObject *module, const char *funcname) { - cursesmodule_state *state = get_cursesmodule_state_by_win(win); - _PyCursesSetError(state, python_funcname, curses_funcname); + PyCursesSetError_From(module, funcname, NULL); } /* Utility Checking Procedures */ @@ -361,15 +358,6 @@ _PyCursesStatefulCheckFunction(PyObject *module, * on success and setting an exception on error. */ -static PyObject * -PyCursesCheckERR_From(PyObject *, int, const char *, const char *); - -static inline PyObject * -PyCursesCheckERR(PyObject *module, int code, const char *funcname) -{ - return PyCursesCheckERR_From(module, code, funcname, NULL); -} - static PyObject * PyCursesCheckERR_From(PyObject *module, int code, const char *python_funcname, @@ -382,15 +370,10 @@ PyCursesCheckERR_From(PyObject *module, int code, return NULL; } -static PyObject * -PyCursesCheckERR_ForWin_From(PyCursesWindowObject *, int, - const char *, const char *); - static inline PyObject * -PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, - const char *funcname) +PyCursesCheckERR(PyObject *module, int code, const char *funcname) { - return PyCursesCheckERR_ForWin_From(win, code, funcname, NULL); + return PyCursesCheckERR_From(module, code, funcname, NULL); } static PyObject * @@ -405,6 +388,13 @@ PyCursesCheckERR_ForWin_From(PyCursesWindowObject *win, int code, return NULL; } +static inline PyObject * +PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, + const char *funcname) +{ + return PyCursesCheckERR_ForWin_From(win, code, funcname, NULL); +} + /* Convert an object to a byte (an integer of type chtype): - int From 34583e016c88e10fefc64d17cbdc1b9840a88907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 6 May 2025 11:03:23 +0200 Subject: [PATCH 19/25] address review - use `curses_set_error_*` prefix for error helpers - remove some macros with predefined messages - cleanly report both NULL and ERR cases --- Include/py_curses.h | 7 + Modules/_cursesmodule.c | 336 ++++++++++++++++++++++------------------ 2 files changed, 188 insertions(+), 155 deletions(-) diff --git a/Include/py_curses.h b/Include/py_curses.h index e11bfedb17d205..9cf0744da9bac8 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -108,6 +108,13 @@ static void **PyCurses_API; static const char catchall_ERR[] = "curses function returned ERR"; static const char catchall_NULL[] = "curses function returned NULL"; +#if defined(CURSES_MODULE) || defined(CURSES_PANEL_MODULE) +/* Error messages shared by the curses package */ +# define CURSES_ERROR_FORMAT "%s() returned %s" +# define CURSES_ERROR_VERBOSE_FORMAT "%s() (called by %s()) returned %s" +# define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first" +#endif + #ifdef __cplusplus } #endif diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 8c174a96e5d24e..e16c95e7f365d1 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -211,81 +211,114 @@ static int curses_start_color_called = FALSE; static const char *curses_screen_encoding = NULL; -/* Error type */ - -#define CURSES_ERROR_FORMAT "%s() returned ERR" -#define CURSES_ERROR_VERBOSE_FORMAT "%s() (called by %s()) returned ERR" -#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL" -#define CURSES_ERROR_NULL_VERBOSE_FORMAT "%s() (called by %s()) returned NULL" -#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first" - /* Utility Error Procedures */ -/* - * Format a curses error. - * - * A NULL 'python_funcname' falls back to 'curses_funcname' and vice-versa. - * If both names are NULL, the error message is 'catchall_ERR'. - */ static void -_PyCursesSetError(cursesmodule_state *state, - const char *python_funcname, - const char *curses_funcname) +_curses_format_error(cursesmodule_state *state, + const char *curses_funcname, + const char *python_funcname, + const char *return_value, + const char *default_message) { assert(!PyErr_Occurred()); if (python_funcname == NULL && curses_funcname == NULL) { - PyErr_SetString(state->error, catchall_ERR); + PyErr_SetString(state->error, default_message); } else if (python_funcname == NULL) { - PyErr_Format(state->error, CURSES_ERROR_FORMAT, curses_funcname); - } - else if (curses_funcname == NULL) { - PyErr_Format(state->error, CURSES_ERROR_FORMAT, python_funcname); + (void)PyErr_Format(state->error, CURSES_ERROR_FORMAT, + curses_funcname, return_value); } else { - PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, - curses_funcname, python_funcname); + assert(python_funcname != NULL); + (void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, + curses_funcname, python_funcname, return_value); } } +/* + * Format a curses error for a function that returned ERR. + * + * Specify a non-NULL 'python_funcname' when the latter differs from + * 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR' + * message instead. + */ static void -PyCursesSetError_ForWin_From(PyCursesWindowObject *win, - const char *python_funcname, - const char *curses_funcname) +_curses_set_error(cursesmodule_state *state, + const char *curses_funcname, + const char *python_funcname) { - cursesmodule_state *state = get_cursesmodule_state_by_win(win); - _PyCursesSetError(state, python_funcname, curses_funcname); + _curses_format_error(state, curses_funcname, python_funcname, + "ERR", catchall_ERR); } +/* + * Format a curses error for a function that returned NULL. + * + * Specify a non-NULL 'python_funcname' when the latter differs from + * 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL' + * message instead. + */ +static inline void +_curses_set_null_error(cursesmodule_state *state, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_format_error(state, curses_funcname, python_funcname, + "NULL", catchall_NULL); +} + +/* Same as _curses_set_error() for a module object. */ static void -PyCursesSetError_From(PyObject *module, - const char *python_funcname, - const char *curses_funcname) +curses_set_error(PyObject *module, + const char *curses_funcname, + const char *python_funcname) { cursesmodule_state *state = get_cursesmodule_state(module); - _PyCursesSetError(state, python_funcname, curses_funcname); + _curses_set_error(state, curses_funcname, python_funcname); } -/* - * Format a curses error using 'funcname' as the displayed - * function name and underlying curses function name. - */ -static inline void -PyCursesSetError(PyObject *module, const char *funcname) +/* Same as _curses_set_null_error() for a module object. */ +static void +curses_set_null_error(PyObject *module, + const char *curses_funcname, + const char *python_funcname) +{ + cursesmodule_state *state = get_cursesmodule_state(module); + _curses_set_null_error(state, curses_funcname, python_funcname); +} + +/* Same as _curses_set_error() for a Window object. */ +static void +curses_window_set_error(PyCursesWindowObject *win, + const char *curses_funcname, + const char *python_funcname) { - PyCursesSetError_From(module, funcname, NULL); + cursesmodule_state *state = get_cursesmodule_state_by_win(win); + _curses_set_error(state, curses_funcname, python_funcname); +} + +/* Same as _curses_set_null_error() for a Window object. */ +static void +curses_window_set_null_error(PyCursesWindowObject *win, + const char *curses_funcname, + const char *python_funcname) +{ + cursesmodule_state *state = get_cursesmodule_state_by_win(win); + _curses_set_null_error(state, curses_funcname, python_funcname); } /* Utility Checking Procedures */ /* * Function to check that 'funcname' has been called by testing - * the 'called' boolean. If an error occurs, a PyCursesError is + * the 'called' boolean. If an error occurs, an exception is * set and this returns 0. Otherwise, this returns 1. * * Since this function can be called in functions that do not * have a direct access to the module's state, '_curses.error' * is imported on demand. + * + * Use _PyCursesStatefulCheckFunction() if the module is given. */ static int _PyCursesCheckFunction(int called, const char *funcname) @@ -358,43 +391,36 @@ _PyCursesStatefulCheckFunction(PyObject *module, * on success and setting an exception on error. */ +/* + * Return None if 'code' is ERR. Otherwise, set an exception + * using curses_set_error() and the remaining arguments, and + * return NULL. + */ static PyObject * -PyCursesCheckERR_From(PyObject *module, int code, - const char *python_funcname, - const char *curses_funcname) +curses_check_err(PyObject *module, int code, + const char *curses_funcname, + const char *python_funcname) { if (code != ERR) { Py_RETURN_NONE; } - PyCursesSetError_From(module, python_funcname, curses_funcname); + curses_set_error(module, curses_funcname, python_funcname); return NULL; } -static inline PyObject * -PyCursesCheckERR(PyObject *module, int code, const char *funcname) -{ - return PyCursesCheckERR_From(module, code, funcname, NULL); -} - +/* Same as curses_check_err() for a Window object. */ static PyObject * -PyCursesCheckERR_ForWin_From(PyCursesWindowObject *win, int code, - const char *python_funcname, - const char *curses_funcname) +curses_window_check_err(PyCursesWindowObject *win, int code, + const char *curses_funcname, + const char *python_funcname) { if (code != ERR) { Py_RETURN_NONE; } - PyCursesSetError_ForWin_From(win, python_funcname, curses_funcname); + curses_window_set_error(win, curses_funcname, python_funcname); return NULL; } -static inline PyObject * -PyCursesCheckERR_ForWin(PyCursesWindowObject *win, int code, - const char *funcname) -{ - return PyCursesCheckERR_ForWin_From(win, code, funcname, NULL); -} - /* Convert an object to a byte (an integer of type chtype): - int @@ -735,7 +761,7 @@ class component_converter(CConverter): { \ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ int code = X(self->win); \ - return PyCursesCheckERR_ForWin(self, code, # X); \ + return curses_window_check_err(self, code, # X, NULL); \ } #define Window_NoArgTrueFalseFunction(X) \ @@ -788,7 +814,7 @@ class component_converter(CConverter): } \ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ int code = X(self->win, arg1); \ - return PyCursesCheckERR_ForWin(self, code, # X); \ + return curses_window_check_err(self, code, # X, NULL); \ } #define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ @@ -801,7 +827,7 @@ class component_converter(CConverter): } \ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ int code = X(self->win, arg1, arg2); \ - return PyCursesCheckERR_ForWin(self, code, # X); \ + return curses_window_check_err(self, code, # X, NULL); \ } /* ------------- WINDOW routines --------------- */ @@ -996,7 +1022,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, else { return NULL; } - return PyCursesCheckERR_ForWin_From(self, rtn, "addch", funcname); + return curses_window_check_err(self, rtn, funcname, "addch"); } /*[clinic input] @@ -1082,7 +1108,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, "addstr", funcname); + return curses_window_check_err(self, rtn, funcname, "addstr"); } /*[clinic input] @@ -1171,7 +1197,7 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, "addnstr", funcname); + return curses_window_check_err(self, rtn, funcname, "addnstr"); } /*[clinic input] @@ -1196,7 +1222,7 @@ _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr) return NULL; int rtn = wbkgd(self->win, bkgd | attr); - return PyCursesCheckERR_ForWin_From(self, rtn, "bkgd", "wbkgd"); + return curses_window_check_err(self, rtn, "wbkgd", "bkgd"); } /*[clinic input] @@ -1213,7 +1239,7 @@ _curses_window_attroff_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=8a2fcd4df682fc64 input=786beedf06a7befe]*/ { int rtn = wattroff(self->win, (attr_t)attr); - return PyCursesCheckERR_ForWin_From(self, rtn, "attroff", "wattroff"); + return curses_window_check_err(self, rtn, "wattroff", "attroff"); } /*[clinic input] @@ -1230,7 +1256,7 @@ _curses_window_attron_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=7afea43b237fa870 input=5a88fba7b1524f32]*/ { int rtn = wattron(self->win, (attr_t)attr); - return PyCursesCheckERR_ForWin_From(self, rtn, "attron", "wattron"); + return curses_window_check_err(self, rtn, "wattron", "attron"); } /*[clinic input] @@ -1247,7 +1273,7 @@ _curses_window_attrset_impl(PyCursesWindowObject *self, long attr) /*[clinic end generated code: output=84e379bff20c0433 input=42e400c0d0154ab5]*/ { int rtn = wattrset(self->win, (attr_t)attr); - return PyCursesCheckERR_ForWin_From(self, rtn, "attrset", "wattrset"); + return curses_window_check_err(self, rtn, "wattrset", "attrset"); } /*[clinic input] @@ -1272,7 +1298,7 @@ _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, if (!PyCurses_ConvertToChtype(self, ch, &bkgd)) return NULL; - wbkgdset(self->win, bkgd | attr); // errors are ignored + wbkgdset(self->win, bkgd | attr); Py_RETURN_NONE; } @@ -1478,7 +1504,7 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) (void)touchline(self->win,y,1); funcname = "wchgat"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "chgat", funcname); + return curses_window_check_err(self, rtn, funcname, "chgat"); } #endif @@ -1511,7 +1537,7 @@ _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, rtn = py_mvwdelch(self->win, y, x); funcname = "mvwdelch"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "delch", funcname); + return curses_window_check_err(self, rtn, funcname, "delch"); } /*[clinic input] @@ -1546,8 +1572,7 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, win = derwin(self->win,nlines,ncols,begin_y,begin_x); if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "derwin"); + curses_window_set_error(self, "derwin", NULL); return NULL; } @@ -1591,7 +1616,7 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, rtn = wechochar(self->win, ch_ | (attr_t)attr); funcname = "wechochar"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "echochar", funcname); + return curses_window_check_err(self, rtn, funcname, "echochar"); } #ifdef NCURSES_MOUSE_VERSION @@ -1765,7 +1790,6 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, /* get_wch() returns ERR in nodelay mode */ cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_SetString(state->error, "no input"); const char *funcname = group_right_1 ? "mvwget_wch" : "wget_wch"; PyErr_Format(state->error, "get_wch(): %s(): no input", funcname); return NULL; @@ -1893,12 +1917,12 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, return NULL; if (group_left_1) { if (wmove(self->win, y, x) == ERR) { - PyCursesSetError_ForWin_From(self, "hline", "wmove"); + curses_window_set_error(self, "wmove", "hline"); return NULL; } } int rtn = whline(self->win, ch_ | (attr_t)attr, n); - return PyCursesCheckERR_ForWin_From(self, rtn, "hline", "whline"); + return curses_window_check_err(self, rtn, "whline", "hline"); } /*[clinic input] @@ -1948,7 +1972,7 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, funcname = "mvwwinsch"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "insch", funcname); + return curses_window_check_err(self, rtn, funcname, "insch"); } /*[clinic input] @@ -2133,7 +2157,7 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, "insstr", funcname); + return curses_window_check_err(self, rtn, funcname, "insstr"); } /*[clinic input] @@ -2224,7 +2248,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, } if (use_attr) (void)wattrset(self->win,attr_old); - return PyCursesCheckERR_ForWin_From(self, rtn, "insnstr", funcname); + return curses_window_check_err(self, rtn, funcname, "insnstr"); } /*[clinic input] @@ -2311,8 +2335,8 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) rtn = pnoutrefresh(self->win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin_From(self, rtn, - "noutrefresh", "pnoutrefresh"); + return curses_window_check_err(self, rtn, + "pnoutrefresh", "noutrefresh"); } if (group_right_1) { PyErr_SetString(PyExc_TypeError, @@ -2323,8 +2347,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) Py_BEGIN_ALLOW_THREADS rtn = wnoutrefresh(self->win); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin_From(self, rtn, - "noutrefresh", "wnoutrefresh"); + return curses_window_check_err(self, rtn, "wnoutrefresh", "noutrefresh"); } /*[clinic input] @@ -2366,11 +2389,11 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, if (group_right_1) { rtn = copywin(self->win, destwin->win, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, TRUE); - return PyCursesCheckERR_ForWin_From(self, rtn, "overlay", "copywin"); + return curses_window_check_err(self, rtn, "copywin", "overlay"); } else { rtn = overlay(self->win, destwin->win); - return PyCursesCheckERR_ForWin(self, rtn, "overlay"); + return curses_window_check_err(self, rtn, "overlay", NULL); } } @@ -2414,11 +2437,11 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, if (group_right_1) { rtn = copywin(self->win, destwin->win, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, FALSE); - return PyCursesCheckERR_ForWin_From(self, rtn, "overwrite", "copywin"); + return curses_window_check_err(self, rtn, "copywin", "overwrite"); } else { rtn = overwrite(self->win, destwin->win); - return PyCursesCheckERR_ForWin(self, rtn, "overwrite"); + return curses_window_check_err(self, rtn, "overwrite", NULL); } } @@ -2447,7 +2470,7 @@ _curses_window_putwin_impl(PyCursesWindowObject *self, PyObject *file) return PyErr_SetFromErrno(PyExc_OSError); if (_Py_set_inheritable(fileno(fp), 0, NULL) < 0) goto exit; - res = PyCursesCheckERR_ForWin(self, putwin(self->win, fp), "putwin"); + res = curses_window_check_err(self, putwin(self->win, fp), "putwin", NULL); if (res == NULL) goto exit; fseek(fp, 0, 0); @@ -2487,7 +2510,7 @@ _curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num) /*[clinic end generated code: output=ea216e334f9ce1b4 input=152155e258a77a7a]*/ { int rtn = wredrawln(self->win,beg, num); - return PyCursesCheckERR_ForWin_From(self, rtn, "redrawln", "wredrawln"); + return curses_window_check_err(self, rtn, "wredrawln", "redrawln"); } /*[clinic input] @@ -2538,7 +2561,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, rtn = prefresh(self->win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin_From(self, rtn, "refresh", "prefresh"); + return curses_window_check_err(self, rtn, "prefresh", "refresh"); } #endif if (group_right_1) { @@ -2549,7 +2572,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, Py_BEGIN_ALLOW_THREADS rtn = wrefresh(self->win); Py_END_ALLOW_THREADS - return PyCursesCheckERR_ForWin_From(self, rtn, "refresh", "wrefresh"); + return curses_window_check_err(self, rtn, "wrefresh", "refresh"); } /*[clinic input] @@ -2572,7 +2595,7 @@ _curses_window_setscrreg_impl(PyCursesWindowObject *self, int top, /*[clinic end generated code: output=486ab5db218d2b1a input=1b517b986838bf0e]*/ { int rtn = wsetscrreg(self->win, top, bottom); - return PyCursesCheckERR_ForWin_From(self, rtn, "setscrreg", "wsetscrreg"); + return curses_window_check_err(self, rtn, "wsetscrreg", "setscrreg"); } /*[clinic input] @@ -2618,9 +2641,7 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, } if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state_by_win(self); - PyErr_Format(state->error, CURSES_ERROR_NULL_VERBOSE_FORMAT, - funcname, "subwin"); + curses_window_set_null_error(self, funcname, "subwin"); return NULL; } @@ -2657,7 +2678,7 @@ _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, rtn = wscrl(self->win, lines); funcname = "wscrl"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "scroll", funcname); + return curses_window_check_err(self, rtn, funcname, "scroll"); } /*[clinic input] @@ -2691,7 +2712,7 @@ _curses_window_touchline_impl(PyCursesWindowObject *self, int start, rtn = wtouchln(self->win, start, count, changed); funcname = "wtouchln"; } - return PyCursesCheckERR_ForWin_From(self, rtn, "touchline", funcname); + return curses_window_check_err(self, rtn, funcname, "touchline"); } /*[clinic input] @@ -2730,12 +2751,12 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, return NULL; if (group_left_1) { if (wmove(self->win, y, x) == ERR) { - PyCursesSetError_ForWin_From(self, "vline", "wmove"); + curses_window_set_error(self, "wmove", "vline"); return NULL; } } int rtn = wvline(self->win, ch_ | (attr_t)attr, n); - return PyCursesCheckERR_ForWin_From(self, rtn, "vline", "wvline"); + return curses_window_check_err(self, rtn, "wvline", "vline"); } static PyObject * @@ -2917,23 +2938,22 @@ static PyType_Spec PyCursesWindow_Type_spec = { #define NoArgNoReturnFunctionBody(X) \ { \ PyCursesStatefulInitialised(module); \ - return PyCursesCheckERR(module, X(), # X); } - -#define NoArgOrFlagNoReturnFunctionBody(X, FLAG) \ -{ \ - PyCursesStatefulInitialised(module); \ - int rtn; \ - const char *funcname; \ - if (FLAG) { \ - rtn = X(); \ - funcname = # X; \ - } \ - else { \ - rtn = no ## X(); \ - funcname = "no" # X; \ - } \ - return PyCursesCheckERR_From(module, rtn, \ - # X, funcname); \ + return curses_check_err(module, X(), # X, NULL); } + +#define NoArgOrFlagNoReturnFunctionBody(X, FLAG) \ +{ \ + PyCursesStatefulInitialised(module); \ + int rtn; \ + const char *funcname; \ + if (FLAG) { \ + rtn = X(); \ + funcname = # X; \ + } \ + else { \ + rtn = no ## X(); \ + funcname = "no" # X; \ + } \ + return curses_check_err(module, rtn, funcname, # X); \ } #define NoArgReturnIntFunctionBody(X) \ @@ -3055,7 +3075,8 @@ _curses_color_content_impl(PyObject *module, int color_number) PyCursesStatefulInitialisedColor(module); if (_COLOR_CONTENT_FUNC(color_number, &r, &g, &b) == ERR) { - PyCursesSetError(module, Py_STRINGIFY(_COLOR_CONTENT_FUNC)); + const char *funcname = Py_STRINGIFY(_COLOR_CONTENT_FUNC); + curses_set_error(module, funcname, "color_content"); return NULL; } @@ -3110,7 +3131,7 @@ _curses_curs_set_impl(PyObject *module, int visibility) erg = curs_set(visibility); if (erg == ERR) { - PyCursesSetError(module, "curs_set"); + curses_set_error(module, "curs_set", NULL); return NULL; } @@ -3163,7 +3184,7 @@ _curses_delay_output_impl(PyObject *module, int ms) { PyCursesStatefulInitialised(module); - return PyCursesCheckERR(module, delay_output(ms), "delay_output"); + return curses_check_err(module, delay_output(ms), "delay_output", NULL); } /*[clinic input] @@ -3296,7 +3317,7 @@ _curses_getmouse_impl(PyObject *module) rtn = getmouse( &event ); if (rtn == ERR) { - PyCursesSetError(module, "getmouse"); + curses_set_error(module, "getmouse", NULL); return NULL; } return Py_BuildValue("(hiiik)", @@ -3334,7 +3355,7 @@ _curses_ungetmouse_impl(PyObject *module, short id, int x, int y, int z, event.y = y; event.z = z; event.bstate = bstate; - return PyCursesCheckERR(module, ungetmouse(&event), "ungetmouse"); + return curses_check_err(module, ungetmouse(&event), "ungetmouse", NULL); } #endif @@ -3390,8 +3411,7 @@ _curses_getwin(PyObject *module, PyObject *file) fseek(fp, 0, 0); win = getwin(fp); if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "getwin"); + curses_set_null_error(module, "getwin", NULL); goto error; } cursesmodule_state *state = get_cursesmodule_state(module); @@ -3420,7 +3440,7 @@ _curses_halfdelay_impl(PyObject *module, unsigned char tenths) { PyCursesStatefulInitialised(module); - return PyCursesCheckERR(module, halfdelay(tenths), "halfdelay"); + return curses_check_err(module, halfdelay(tenths), "halfdelay", NULL); } /*[clinic input] @@ -3505,9 +3525,10 @@ _curses_init_color_impl(PyObject *module, int color_number, short r, short g, PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); - return PyCursesCheckERR(module, + return curses_check_err(module, _CURSES_INIT_COLOR_FUNC(color_number, r, g, b), - Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC)); + Py_STRINGIFY(_CURSES_INIT_COLOR_FUNC), + NULL); } /*[clinic input] @@ -3541,7 +3562,8 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) COLOR_PAIRS - 1); } else { - PyCursesSetError(module, Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC)); + const char *funcname = Py_STRINGIFY(_CURSES_INIT_PAIR_FUNC); + curses_set_error(module, funcname, "init_pair"); } return NULL; } @@ -3572,8 +3594,7 @@ _curses_initscr_impl(PyObject *module) win = initscr(); if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "initscr"); + curses_set_null_error(module, "initscr", NULL); return NULL; } @@ -3778,7 +3799,7 @@ _curses_set_escdelay_impl(PyObject *module, int ms) return NULL; } - return PyCursesCheckERR(module, set_escdelay(ms), "set_escdelay"); + return curses_check_err(module, set_escdelay(ms), "set_escdelay", NULL); } /*[clinic input] @@ -3817,7 +3838,7 @@ _curses_set_tabsize_impl(PyObject *module, int size) return NULL; } - return PyCursesCheckERR(module, set_tabsize(size), "set_tabsize"); + return curses_check_err(module, set_tabsize(size), "set_tabsize", NULL); } #endif @@ -3835,7 +3856,7 @@ _curses_intrflush_impl(PyObject *module, int flag) { PyCursesStatefulInitialised(module); - return PyCursesCheckERR(module, intrflush(NULL, flag), "intrflush"); + return curses_check_err(module, intrflush(NULL, flag), "intrflush", NULL); } /*[clinic input] @@ -3948,7 +3969,7 @@ _curses_meta_impl(PyObject *module, int yes) { PyCursesStatefulInitialised(module); - return PyCursesCheckERR(module, meta(stdscr, yes), "meta"); + return curses_check_err(module, meta(stdscr, yes), "meta", NULL); } #ifdef NCURSES_MOUSE_VERSION @@ -3971,8 +3992,8 @@ _curses_mouseinterval_impl(PyObject *module, int interval) /*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/ { PyCursesStatefulInitialised(module); - - return PyCursesCheckERR(module, mouseinterval(interval), "mouseinterval"); + int rtn = mouseinterval(interval); + return curses_check_err(module, rtn, "mouseinterval", NULL); } /*[clinic input] @@ -4048,8 +4069,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) win = newpad(nlines, ncols); if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newpad"); + curses_set_null_error(module, "newpad", NULL); return NULL; } @@ -4089,8 +4109,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, win = newwin(nlines,ncols,begin_y,begin_x); if (win == NULL) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newwin"); + curses_set_null_error(module, "newwin", NULL); return NULL; } @@ -4209,7 +4228,8 @@ _curses_pair_content_impl(PyObject *module, int pair_number) COLOR_PAIRS - 1); } else { - PyCursesSetError(module, Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC)); + const char *funcname = Py_STRINGIFY(_CURSES_PAIR_CONTENT_FUNC); + curses_set_error(module, funcname, "pair_content"); } return NULL; } @@ -4253,7 +4273,7 @@ static PyObject * _curses_putp_impl(PyObject *module, const char *string) /*[clinic end generated code: output=e98081d1b8eb5816 input=1601faa828b44cb3]*/ { - return PyCursesCheckERR(module, putp(string), "putp"); + return curses_check_err(module, putp(string), "putp", NULL); } /*[clinic input] @@ -4427,10 +4447,12 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) /*[clinic end generated code: output=4de3abab50c67f02 input=414e92a63e3e9899]*/ { PyObject *result; + int code; PyCursesStatefulInitialised(module); - result = PyCursesCheckERR(module, resizeterm(nlines, ncols), "resizeterm"); + code = resizeterm(nlines, ncols); + result = curses_check_err(module, code, "resizeterm", NULL); if (!result) return NULL; if (!update_lines_cols(module)) { @@ -4466,10 +4488,12 @@ _curses_resize_term_impl(PyObject *module, short nlines, short ncols) /*[clinic end generated code: output=46c6d749fa291dbd input=276afa43d8ea7091]*/ { PyObject *result; + int code; PyCursesStatefulInitialised(module); - result = PyCursesCheckERR(module, resize_term(nlines, ncols), "resize_term"); + code = resize_term(nlines, ncols); + result = curses_check_err(module, code, "resize_term", NULL); if (!result) return NULL; if (!update_lines_cols(module)) { @@ -4538,7 +4562,7 @@ _curses_start_color_impl(PyObject *module) PyCursesStatefulInitialised(module); if (start_color() == ERR) { - PyCursesSetError(module, "start_color"); + curses_set_error(module, "start_color", NULL); return NULL; } @@ -4690,8 +4714,7 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3, result = tparm((char *)str,i1,i2,i3,i4,i5,i6,i7,i8,i9); if (!result) { - cursesmodule_state *state = get_cursesmodule_state(module); - PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "tparm"); + curses_set_null_error(module, "tparm", NULL); return NULL; } @@ -4717,7 +4740,7 @@ _curses_typeahead_impl(PyObject *module, int fd) { PyCursesStatefulInitialised(module); - return PyCursesCheckERR(module, typeahead( fd ), "typeahead"); + return curses_check_err(module, typeahead(fd), "typeahead", NULL); } #endif @@ -4767,7 +4790,7 @@ _curses_ungetch(PyObject *module, PyObject *ch) if (!PyCurses_ConvertToChtype(NULL, ch, &ch_)) return NULL; - return PyCursesCheckERR(module, ungetch(ch_), "ungetch"); + return curses_check_err(module, ungetch(ch_), "ungetch", NULL); } #ifdef HAVE_NCURSESW @@ -4837,7 +4860,7 @@ _curses_unget_wch(PyObject *module, PyObject *ch) if (!PyCurses_ConvertToWchar_t(ch, &wch)) return NULL; - return PyCursesCheckERR(module, unget_wch(wch), "unget_wch"); + return curses_check_err(module, unget_wch(wch), "unget_wch", NULL); } #endif @@ -4883,10 +4906,13 @@ static PyObject * _curses_use_default_colors_impl(PyObject *module) /*[clinic end generated code: output=a3b81ff71dd901be input=656844367470e8fc]*/ { + int code; + PyCursesStatefulInitialised(module); PyCursesStatefulInitialisedColor(module); - return PyCursesCheckERR(module, use_default_colors(), "use_default_colors"); + code = use_default_colors(); + return curses_check_err(module, code, "use_default_colors", NULL); } #endif /* STRICT_SYSV_CURSES */ From 236bea51e25b21c8f8c5b70e19221787f5200b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Wed, 7 May 2025 11:15:11 +0200 Subject: [PATCH 20/25] update error messages in `_curses_panel` --- Modules/_curses_panel.c | 340 ++++++++++++++++++++----------- Modules/clinic/_curses_panel.c.h | 159 ++++----------- 2 files changed, 257 insertions(+), 242 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index eecf7a1c8a1e56..3b0647fd7d4566 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -17,6 +17,7 @@ static const char PyCursesVersion[] = "2.1"; #include "Python.h" +#define CURSES_PANEL_MODULE #include "py_curses.h" #if defined(HAVE_NCURSESW_PANEL_H) @@ -28,10 +29,12 @@ static const char PyCursesVersion[] = "2.1"; #endif typedef struct { - PyObject *PyCursesError; + PyObject *error; PyTypeObject *PyCursesPanel_Type; } _curses_panel_state; +typedef struct PyCursesPanelObject PyCursesPanelObject; + static inline _curses_panel_state * get_curses_panel_state(PyObject *module) { @@ -40,11 +43,30 @@ get_curses_panel_state(PyObject *module) return (_curses_panel_state *)state; } +static inline _curses_panel_state * +get_curses_panel_state_by_panel(PyCursesPanelObject *panel) +{ + /* + * Note: 'state' may be NULL if Py_TYPE(panel) is not a heap + * type associated with this module, but the compiler would + * have likely already complained with an "invalid pointer + * type" at compile-time. + * + * To make it more robust, all functions recovering a module's + * state from an object should expect to return NULL with an + * exception set (in contrast to functions recovering a module's + * state from a module itself). + */ + void *state = PyType_GetModuleState(Py_TYPE(panel)); + assert(state != NULL); + return (_curses_panel_state *)state; +} + static int _curses_panel_clear(PyObject *mod) { _curses_panel_state *state = get_curses_panel_state(mod); - Py_CLEAR(state->PyCursesError); + Py_CLEAR(state->error); Py_CLEAR(state->PyCursesPanel_Type); return 0; } @@ -54,7 +76,7 @@ _curses_panel_traverse(PyObject *mod, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(mod)); _curses_panel_state *state = get_curses_panel_state(mod); - Py_VISIT(state->PyCursesError); + Py_VISIT(state->error); Py_VISIT(state->PyCursesPanel_Type); return 0; } @@ -65,28 +87,144 @@ _curses_panel_free(void *mod) (void)_curses_panel_clear((PyObject *)mod); } +/* Utility Error Procedures + * + * The naming and implementations are identical to those in _cursesmodule.c. + * Functions that are not yet needed (for instance, reporting an ERR value + * from a module-wide function, namely curses_panel_set_error()) are + * omitted and should only be added if needed. + */ + +static void +_curses_panel_format_error(_curses_panel_state *state, + const char *curses_funcname, + const char *python_funcname, + const char *return_value, + const char *default_message) +{ + assert(!PyErr_Occurred()); + if (python_funcname == NULL && curses_funcname == NULL) { + PyErr_SetString(state->error, default_message); + } + else if (python_funcname == NULL) { + (void)PyErr_Format(state->error, CURSES_ERROR_FORMAT, + curses_funcname, return_value); + } + else { + assert(python_funcname != NULL); + (void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, + curses_funcname, python_funcname, return_value); + } +} + +/* + * Format a curses error for a function that returned ERR. + * + * Specify a non-NULL 'python_funcname' when the latter differs from + * 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR' + * message instead. + */ +static void +_curses_panel_set_error(_curses_panel_state *state, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_panel_format_error(state, curses_funcname, python_funcname, + "ERR", catchall_ERR); +} + +/* + * Format a curses error for a function that returned NULL. + * + * Specify a non-NULL 'python_funcname' when the latter differs from + * 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL' + * message instead. + */ +static void +_curses_panel_set_null_error(_curses_panel_state *state, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_panel_format_error(state, curses_funcname, python_funcname, + "NULL", catchall_NULL); +} + +/* Same as _curses_panel_set_null_error() for a module object. */ +static void +curses_panel_set_null_error(PyObject *module, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_panel_state *state = get_curses_panel_state(module); + _curses_panel_set_null_error(state, curses_funcname, python_funcname); +} + +/* Same as _curses_panel_set_error() for a panel object. */ +static void +curses_panel_panel_set_error(PyCursesPanelObject *panel, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_panel_state *state = get_curses_panel_state_by_panel(panel); + _curses_panel_set_error(state, curses_funcname, python_funcname); +} + +/* Same as _curses_panel_set_null_error() for a panel object. */ +static void +curses_panel_panel_set_null_error(PyCursesPanelObject *panel, + const char *curses_funcname, + const char *python_funcname) +{ + _curses_panel_state *state = get_curses_panel_state_by_panel(panel); + _curses_panel_set_null_error(state, curses_funcname, python_funcname); +} + +/* + * Indicate that a panel object couldn't be found. + * + * Use it for the following constructions: + * + * PROC caller_funcname: + * pan = called_funcname() + * find_po(panel) + * + * PROC caller_funcname: + * find_po(self->pan) +*/ +static void +curses_panel_notfound_error(const char *called_funcname, + const char *caller_funcname) +{ + assert(!(called_funcname == NULL && caller_funcname == NULL)); + if (caller_funcname == NULL) { + (void)PyErr_Format(PyExc_RuntimeError, + "%s(): cannot find panel object", + called_funcname); + } + else { + (void)PyErr_Format(PyExc_RuntimeError, + "%s() (called by %s()): cannot find panel object", + called_funcname, caller_funcname); + } +} + /* Utility Functions */ /* - * Check the return code from a curses function and return None - * or raise an exception as appropriate. + * Check the return code from a curses function, returning None + * on success and setting an exception on error. */ static PyObject * -PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname) +curses_panel_panel_check_err(PyCursesPanelObject *panel, int code, + const char *curses_funcname, + const char *python_funcname) { if (code != ERR) { Py_RETURN_NONE; } - else { - if (fname == NULL) { - PyErr_SetString(state->PyCursesError, catchall_ERR); - } - else { - PyErr_Format(state->PyCursesError, "%s() returned ERR", fname); - } - return NULL; - } + curses_panel_panel_set_error(panel, curses_funcname, python_funcname); + return NULL; } /***************************************************************************** @@ -95,7 +233,7 @@ PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname) /* Definition of the panel object and panel type */ -typedef struct { +typedef struct PyCursesPanelObject { PyObject_HEAD PANEL *pan; PyCursesWindowObject *wo; /* for reference counts */ @@ -158,8 +296,7 @@ remove_lop(PyCursesPanelObject *po) } while (temp->next == NULL || temp->next->po != po) { if (temp->next == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "remove_lop: can't find Panel Object"); + curses_panel_notfound_error("remove_lop", NULL); return; } temp = temp->next; @@ -172,7 +309,7 @@ remove_lop(PyCursesPanelObject *po) /* Return the panel object that corresponds to pan */ static PyCursesPanelObject * -find_po(PANEL *pan) +find_po_impl(PANEL *pan) { list_of_panels *temp; for (temp = lop; temp->po->pan != pan; temp = temp->next) @@ -180,6 +317,17 @@ find_po(PANEL *pan) return temp->po; } +/* Same as find_po_impl() but with caller context information. */ +static PyCursesPanelObject * +find_po(PANEL *pan, const char *called_funcname, const char *caller_funcname) +{ + PyCursesPanelObject *res = find_po_impl(pan); + if (res == NULL) { + curses_panel_notfound_error(called_funcname, caller_funcname); + } + return res; +} + /*[clinic input] module _curses_panel class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type" @@ -193,67 +341,59 @@ class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type" /*[clinic input] _curses_panel.panel.bottom - cls: defining_class - Push the panel to the bottom of the stack. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=8ec7fbbc08554021 input=6b7d2c0578b5a1c4]*/ +_curses_panel_panel_bottom_impl(PyCursesPanelObject *self) +/*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, bottom_panel(self->pan), "bottom"); + int rtn = bottom_panel(self->pan); + return curses_panel_panel_check_err(self, rtn, "bottom_panel", "bottom"); } /*[clinic input] _curses_panel.panel.hide - cls: defining_class - Hide the panel. This does not delete the object, it just makes the window on screen invisible. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=cc6ab7203cdc1450 input=1bfc741f473e6055]*/ +_curses_panel_panel_hide_impl(PyCursesPanelObject *self) +/*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, hide_panel(self->pan), "hide"); + int rtn = hide_panel(self->pan); + return curses_panel_panel_check_err(self, rtn, "hide_panel", "hide"); } /*[clinic input] _curses_panel.panel.show - cls: defining_class - Display the panel (which might have been hidden). [clinic start generated code]*/ static PyObject * -_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=dc3421de375f0409 input=8122e80151cb4379]*/ +_curses_panel_panel_show_impl(PyCursesPanelObject *self) +/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, show_panel(self->pan), "show"); + int rtn = show_panel(self->pan); + return curses_panel_panel_check_err(self, rtn, "show_panel", "show"); } /*[clinic input] _curses_panel.panel.top - cls: defining_class - Push panel to the top of the stack. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=10a072e511e873f7 input=1f372d597dda3379]*/ +_curses_panel_panel_top_impl(PyCursesPanelObject *self) +/*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, top_panel(self->pan), "top"); + int rtn = top_panel(self->pan); + return curses_panel_panel_check_err(self, rtn, "top_panel", "top"); } /* Allocation and deallocation of Panel Objects */ @@ -315,18 +455,11 @@ _curses_panel_panel_above_impl(PyCursesPanelObject *self) PyCursesPanelObject *po; pan = panel_above(self->pan); - - if (pan == NULL) { /* valid output, it means the calling panel - is on top of the stack */ + if (pan == NULL) { /* valid output: it means no panel exists yet */ Py_RETURN_NONE; } - po = find_po(pan); - if (po == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "panel_above: can't find Panel Object"); - return NULL; - } - return Py_NewRef(po); + po = find_po(pan, "panel_above", "above"); + return Py_XNewRef(po); } /* panel_below(NULL) returns the top panel in the stack. To get @@ -345,18 +478,11 @@ _curses_panel_panel_below_impl(PyCursesPanelObject *self) PyCursesPanelObject *po; pan = panel_below(self->pan); - - if (pan == NULL) { /* valid output, it means the calling panel - is on the bottom of the stack */ + if (pan == NULL) { /* valid output: it means no panel exists yet */ Py_RETURN_NONE; } - po = find_po(pan); - if (po == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "panel_below: can't find Panel Object"); - return NULL; - } - return Py_NewRef(po); + po = find_po(pan, "panel_below", "below"); + return Py_XNewRef(po); } /*[clinic input] @@ -378,7 +504,6 @@ _curses_panel_panel_hidden_impl(PyCursesPanelObject *self) /*[clinic input] _curses_panel.panel.move - cls: defining_class y: int x: int / @@ -387,12 +512,11 @@ Move the panel to the screen coordinates (y, x). [clinic start generated code]*/ static PyObject * -_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, - int y, int x) -/*[clinic end generated code: output=ce546c93e56867da input=60a0e7912ff99849]*/ +_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x) +/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, move_panel(self->pan, y, x), "move_panel"); + int rtn = move_panel(self->pan, y, x); + return curses_panel_panel_check_err(self, rtn, "move_panel", "move"); } /*[clinic input] @@ -411,7 +535,6 @@ _curses_panel_panel_window_impl(PyCursesPanelObject *self) /*[clinic input] _curses_panel.panel.replace - cls: defining_class win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") / @@ -420,22 +543,17 @@ Change the window associated with the panel to the window win. static PyObject * _curses_panel_panel_replace_impl(PyCursesPanelObject *self, - PyTypeObject *cls, PyCursesWindowObject *win) -/*[clinic end generated code: output=c71f95c212d58ae7 input=dbec7180ece41ff5]*/ +/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - - PyCursesPanelObject *po = find_po(self->pan); + PyCursesPanelObject *po = find_po(self->pan, "replace", NULL); if (po == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "replace_panel: can't find Panel Object"); return NULL; } int rtn = replace_panel(self->pan, win->win); if (rtn == ERR) { - PyErr_SetString(state->PyCursesError, "replace_panel() returned ERR"); + curses_panel_panel_set_error(self, "replace_panel", "replace"); return NULL; } Py_SETREF(po->wo, (PyCursesWindowObject*)Py_NewRef(win)); @@ -445,7 +563,6 @@ _curses_panel_panel_replace_impl(PyCursesPanelObject *self, /*[clinic input] _curses_panel.panel.set_userptr - cls: defining_class obj: object / @@ -454,8 +571,8 @@ Set the panel's user pointer to obj. static PyObject * _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, - PyTypeObject *cls, PyObject *obj) -/*[clinic end generated code: output=db74f3db07b28080 input=e3fee2ff7b1b8e48]*/ + PyObject *obj) +/*[clinic end generated code: output=7fa1fd23f69db71e input=d2c6a9dbefabbf39]*/ { PyCursesInitialised; Py_INCREF(obj); @@ -464,34 +581,30 @@ _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, if (rc == ERR) { /* In case of an ncurses error, decref the new object again */ Py_DECREF(obj); + curses_panel_panel_set_error(self, + "set_panel_userptr", "set_userptr"); + return NULL; } - else { - Py_XDECREF(oldobj); - } - - _curses_panel_state *state = PyType_GetModuleState(cls); - return PyCursesCheckERR(state, rc, "set_panel_userptr"); + Py_XDECREF(oldobj); + Py_RETURN_NONE; } /*[clinic input] _curses_panel.panel.userptr - cls: defining_class - Return the user pointer for the panel. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, - PyTypeObject *cls) -/*[clinic end generated code: output=eea6e6f39ffc0179 input=f22ca4f115e30a80]*/ +_curses_panel_panel_userptr_impl(PyCursesPanelObject *self) +/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/ { - _curses_panel_state *state = PyType_GetModuleState(cls); - PyCursesInitialised; PyObject *obj = (PyObject *) panel_userptr(self->pan); if (obj == NULL) { - PyErr_SetString(state->PyCursesError, "no userptr set"); + curses_panel_panel_set_null_error(self, + "panel_userptr", + "userptr"); return NULL; } @@ -552,18 +665,11 @@ _curses_panel_bottom_panel_impl(PyObject *module) PyCursesInitialised; pan = panel_above(NULL); - - if (pan == NULL) { /* valid output, it means - there's no panel at all */ + if (pan == NULL) { /* valid output: it means no panel exists yet */ Py_RETURN_NONE; } - po = find_po(pan); - if (po == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "panel_above: can't find Panel Object"); - return NULL; - } - return Py_NewRef(po); + po = find_po(pan, "panel_above", "bottom_panel"); + return Py_XNewRef(po); } /*[clinic input] @@ -579,14 +685,13 @@ static PyObject * _curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win) /*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/ { - _curses_panel_state *state = get_curses_panel_state(module); - PANEL *pan = new_panel(win->win); if (pan == NULL) { - PyErr_SetString(state->PyCursesError, catchall_NULL); + curses_panel_set_null_error(module, "new_panel", NULL); return NULL; } - return (PyObject *)PyCursesPanel_New(state, pan, win); + _curses_panel_state *state = get_curses_panel_state(module); + return PyCursesPanel_New(state, pan, win); } @@ -610,18 +715,11 @@ _curses_panel_top_panel_impl(PyObject *module) PyCursesInitialised; pan = panel_below(NULL); - - if (pan == NULL) { /* valid output, it means - there's no panel at all */ + if (pan == NULL) { /* valid output: it means no panel exists yet */ Py_RETURN_NONE; } - po = find_po(pan); - if (po == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "panel_below: can't find Panel Object"); - return NULL; - } - return Py_NewRef(po); + po = find_po(pan, "panel_below", "top_panel"); + return Py_XNewRef(po); } /*[clinic input] @@ -673,10 +771,10 @@ _curses_panel_exec(PyObject *mod) } /* For exception _curses_panel.error */ - state->PyCursesError = PyErr_NewException( + state->error = PyErr_NewException( "_curses_panel.error", NULL, NULL); - if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) { + if (PyModule_AddObjectRef(mod, "error", state->error) < 0) { return -1; } diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h index 6f4966825ec4bf..75cf067c8aa822 100644 --- a/Modules/clinic/_curses_panel.c.h +++ b/Modules/clinic/_curses_panel.c.h @@ -2,10 +2,7 @@ preserve [clinic start generated code]*/ -#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -# include "pycore_runtime.h" // _Py_SINGLETON() -#endif -#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_curses_panel_panel_bottom__doc__, "bottom($self, /)\n" @@ -14,19 +11,15 @@ PyDoc_STRVAR(_curses_panel_panel_bottom__doc__, "Push the panel to the bottom of the stack."); #define _CURSES_PANEL_PANEL_BOTTOM_METHODDEF \ - {"bottom", _PyCFunction_CAST(_curses_panel_panel_bottom), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_bottom__doc__}, + {"bottom", (PyCFunction)_curses_panel_panel_bottom, METH_NOARGS, _curses_panel_panel_bottom__doc__}, static PyObject * -_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls); +_curses_panel_panel_bottom_impl(PyCursesPanelObject *self); static PyObject * -_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_bottom(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments"); - return NULL; - } - return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls); + return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self); } PyDoc_STRVAR(_curses_panel_panel_hide__doc__, @@ -38,19 +31,15 @@ PyDoc_STRVAR(_curses_panel_panel_hide__doc__, "This does not delete the object, it just makes the window on screen invisible."); #define _CURSES_PANEL_PANEL_HIDE_METHODDEF \ - {"hide", _PyCFunction_CAST(_curses_panel_panel_hide), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_hide__doc__}, + {"hide", (PyCFunction)_curses_panel_panel_hide, METH_NOARGS, _curses_panel_panel_hide__doc__}, static PyObject * -_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls); +_curses_panel_panel_hide_impl(PyCursesPanelObject *self); static PyObject * -_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_hide(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "hide() takes no arguments"); - return NULL; - } - return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls); + return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self); } PyDoc_STRVAR(_curses_panel_panel_show__doc__, @@ -60,19 +49,15 @@ PyDoc_STRVAR(_curses_panel_panel_show__doc__, "Display the panel (which might have been hidden)."); #define _CURSES_PANEL_PANEL_SHOW_METHODDEF \ - {"show", _PyCFunction_CAST(_curses_panel_panel_show), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_show__doc__}, + {"show", (PyCFunction)_curses_panel_panel_show, METH_NOARGS, _curses_panel_panel_show__doc__}, static PyObject * -_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls); +_curses_panel_panel_show_impl(PyCursesPanelObject *self); static PyObject * -_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_show(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "show() takes no arguments"); - return NULL; - } - return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls); + return _curses_panel_panel_show_impl((PyCursesPanelObject *)self); } PyDoc_STRVAR(_curses_panel_panel_top__doc__, @@ -82,19 +67,15 @@ PyDoc_STRVAR(_curses_panel_panel_top__doc__, "Push panel to the top of the stack."); #define _CURSES_PANEL_PANEL_TOP_METHODDEF \ - {"top", _PyCFunction_CAST(_curses_panel_panel_top), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_top__doc__}, + {"top", (PyCFunction)_curses_panel_panel_top, METH_NOARGS, _curses_panel_panel_top__doc__}, static PyObject * -_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls); +_curses_panel_panel_top_impl(PyCursesPanelObject *self); static PyObject * -_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_top(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "top() takes no arguments"); - return NULL; - } - return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls); + return _curses_panel_panel_top_impl((PyCursesPanelObject *)self); } PyDoc_STRVAR(_curses_panel_panel_above__doc__, @@ -158,36 +139,19 @@ PyDoc_STRVAR(_curses_panel_panel_move__doc__, "Move the panel to the screen coordinates (y, x)."); #define _CURSES_PANEL_PANEL_MOVE_METHODDEF \ - {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_move__doc__}, + {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_FASTCALL, _curses_panel_panel_move__doc__}, static PyObject * -_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, - int y, int x); +_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x); static PyObject * -_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = {"", "", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "move", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; int y; int x; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { + if (!_PyArg_CheckPositional("move", nargs, 2, 2)) { goto exit; } y = PyLong_AsInt(args[0]); @@ -198,7 +162,7 @@ _curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *arg if (x == -1 && PyErr_Occurred()) { goto exit; } - return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x); + return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, y, x); exit: return return_value; @@ -229,44 +193,24 @@ PyDoc_STRVAR(_curses_panel_panel_replace__doc__, "Change the window associated with the panel to the window win."); #define _CURSES_PANEL_PANEL_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(_curses_panel_panel_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_replace__doc__}, + {"replace", (PyCFunction)_curses_panel_panel_replace, METH_O, _curses_panel_panel_replace__doc__}, static PyObject * _curses_panel_panel_replace_impl(PyCursesPanelObject *self, - PyTypeObject *cls, PyCursesWindowObject *win); static PyObject * -_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_replace(PyObject *self, PyObject *arg) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = {"", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "replace", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; PyCursesWindowObject *win; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - if (!PyObject_TypeCheck(args[0], &PyCursesWindow_Type)) { - _PyArg_BadArgument("replace", "argument 1", (&PyCursesWindow_Type)->tp_name, args[0]); + if (!PyObject_TypeCheck(arg, &PyCursesWindow_Type)) { + _PyArg_BadArgument("replace", "argument", (&PyCursesWindow_Type)->tp_name, arg); goto exit; } - win = (PyCursesWindowObject *)args[0]; - return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win); + win = (PyCursesWindowObject *)arg; + return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, win); exit: return return_value; @@ -279,41 +223,19 @@ PyDoc_STRVAR(_curses_panel_panel_set_userptr__doc__, "Set the panel\'s user pointer to obj."); #define _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF \ - {"set_userptr", _PyCFunction_CAST(_curses_panel_panel_set_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_set_userptr__doc__}, + {"set_userptr", (PyCFunction)_curses_panel_panel_set_userptr, METH_O, _curses_panel_panel_set_userptr__doc__}, static PyObject * _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, - PyTypeObject *cls, PyObject *obj); + PyObject *obj); static PyObject * -_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_set_userptr(PyObject *self, PyObject *obj) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) - #else - # define KWTUPLE NULL - #endif - - static const char * const _keywords[] = {"", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "set_userptr", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *obj; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { - goto exit; - } - obj = args[0]; - return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj); -exit: + return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, obj); + return return_value; } @@ -324,20 +246,15 @@ PyDoc_STRVAR(_curses_panel_panel_userptr__doc__, "Return the user pointer for the panel."); #define _CURSES_PANEL_PANEL_USERPTR_METHODDEF \ - {"userptr", _PyCFunction_CAST(_curses_panel_panel_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_userptr__doc__}, + {"userptr", (PyCFunction)_curses_panel_panel_userptr, METH_NOARGS, _curses_panel_panel_userptr__doc__}, static PyObject * -_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, - PyTypeObject *cls); +_curses_panel_panel_userptr_impl(PyCursesPanelObject *self); static PyObject * -_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_curses_panel_panel_userptr(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments"); - return NULL; - } - return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls); + return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self); } PyDoc_STRVAR(_curses_panel_bottom_panel__doc__, @@ -424,4 +341,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _curses_panel_update_panels_impl(module); } -/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=db2fe491582784aa input=a9049054013a1b77]*/ From 81881790ec36f7a5402ad18be847b50aa5a12529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 May 2025 12:26:09 +0200 Subject: [PATCH 21/25] raise `curses.error` in `is_linetouched` instead of TypeError --- Modules/_cursesmodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index e16c95e7f365d1..2c88c59956f464 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2270,8 +2270,7 @@ _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line) int erg; erg = is_linetouched(self->win, line); if (erg == ERR) { - PyErr_SetString(PyExc_TypeError, - "is_linetouched: line number outside of boundaries"); + curses_window_set_error(self, "is_linetouched", NULL); return NULL; } return PyBool_FromLong(erg); From 9e6c83e9e0758a9eb22f51256e4c07fcf0d3af47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 May 2025 12:29:26 +0200 Subject: [PATCH 22/25] Revert "update error messages in `_curses_panel`" This reverts commit 236bea51e25b21c8f8c5b70e19221787f5200b68. --- Modules/_curses_panel.c | 340 +++++++++++-------------------- Modules/clinic/_curses_panel.c.h | 159 +++++++++++---- 2 files changed, 242 insertions(+), 257 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 3b0647fd7d4566..eecf7a1c8a1e56 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -17,7 +17,6 @@ static const char PyCursesVersion[] = "2.1"; #include "Python.h" -#define CURSES_PANEL_MODULE #include "py_curses.h" #if defined(HAVE_NCURSESW_PANEL_H) @@ -29,12 +28,10 @@ static const char PyCursesVersion[] = "2.1"; #endif typedef struct { - PyObject *error; + PyObject *PyCursesError; PyTypeObject *PyCursesPanel_Type; } _curses_panel_state; -typedef struct PyCursesPanelObject PyCursesPanelObject; - static inline _curses_panel_state * get_curses_panel_state(PyObject *module) { @@ -43,30 +40,11 @@ get_curses_panel_state(PyObject *module) return (_curses_panel_state *)state; } -static inline _curses_panel_state * -get_curses_panel_state_by_panel(PyCursesPanelObject *panel) -{ - /* - * Note: 'state' may be NULL if Py_TYPE(panel) is not a heap - * type associated with this module, but the compiler would - * have likely already complained with an "invalid pointer - * type" at compile-time. - * - * To make it more robust, all functions recovering a module's - * state from an object should expect to return NULL with an - * exception set (in contrast to functions recovering a module's - * state from a module itself). - */ - void *state = PyType_GetModuleState(Py_TYPE(panel)); - assert(state != NULL); - return (_curses_panel_state *)state; -} - static int _curses_panel_clear(PyObject *mod) { _curses_panel_state *state = get_curses_panel_state(mod); - Py_CLEAR(state->error); + Py_CLEAR(state->PyCursesError); Py_CLEAR(state->PyCursesPanel_Type); return 0; } @@ -76,7 +54,7 @@ _curses_panel_traverse(PyObject *mod, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(mod)); _curses_panel_state *state = get_curses_panel_state(mod); - Py_VISIT(state->error); + Py_VISIT(state->PyCursesError); Py_VISIT(state->PyCursesPanel_Type); return 0; } @@ -87,144 +65,28 @@ _curses_panel_free(void *mod) (void)_curses_panel_clear((PyObject *)mod); } -/* Utility Error Procedures - * - * The naming and implementations are identical to those in _cursesmodule.c. - * Functions that are not yet needed (for instance, reporting an ERR value - * from a module-wide function, namely curses_panel_set_error()) are - * omitted and should only be added if needed. - */ - -static void -_curses_panel_format_error(_curses_panel_state *state, - const char *curses_funcname, - const char *python_funcname, - const char *return_value, - const char *default_message) -{ - assert(!PyErr_Occurred()); - if (python_funcname == NULL && curses_funcname == NULL) { - PyErr_SetString(state->error, default_message); - } - else if (python_funcname == NULL) { - (void)PyErr_Format(state->error, CURSES_ERROR_FORMAT, - curses_funcname, return_value); - } - else { - assert(python_funcname != NULL); - (void)PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT, - curses_funcname, python_funcname, return_value); - } -} - -/* - * Format a curses error for a function that returned ERR. - * - * Specify a non-NULL 'python_funcname' when the latter differs from - * 'curses_funcname'. If both names are NULL, uses the 'catchall_ERR' - * message instead. - */ -static void -_curses_panel_set_error(_curses_panel_state *state, - const char *curses_funcname, - const char *python_funcname) -{ - _curses_panel_format_error(state, curses_funcname, python_funcname, - "ERR", catchall_ERR); -} - -/* - * Format a curses error for a function that returned NULL. - * - * Specify a non-NULL 'python_funcname' when the latter differs from - * 'curses_funcname'. If both names are NULL, uses the 'catchall_NULL' - * message instead. - */ -static void -_curses_panel_set_null_error(_curses_panel_state *state, - const char *curses_funcname, - const char *python_funcname) -{ - _curses_panel_format_error(state, curses_funcname, python_funcname, - "NULL", catchall_NULL); -} - -/* Same as _curses_panel_set_null_error() for a module object. */ -static void -curses_panel_set_null_error(PyObject *module, - const char *curses_funcname, - const char *python_funcname) -{ - _curses_panel_state *state = get_curses_panel_state(module); - _curses_panel_set_null_error(state, curses_funcname, python_funcname); -} - -/* Same as _curses_panel_set_error() for a panel object. */ -static void -curses_panel_panel_set_error(PyCursesPanelObject *panel, - const char *curses_funcname, - const char *python_funcname) -{ - _curses_panel_state *state = get_curses_panel_state_by_panel(panel); - _curses_panel_set_error(state, curses_funcname, python_funcname); -} - -/* Same as _curses_panel_set_null_error() for a panel object. */ -static void -curses_panel_panel_set_null_error(PyCursesPanelObject *panel, - const char *curses_funcname, - const char *python_funcname) -{ - _curses_panel_state *state = get_curses_panel_state_by_panel(panel); - _curses_panel_set_null_error(state, curses_funcname, python_funcname); -} - -/* - * Indicate that a panel object couldn't be found. - * - * Use it for the following constructions: - * - * PROC caller_funcname: - * pan = called_funcname() - * find_po(panel) - * - * PROC caller_funcname: - * find_po(self->pan) -*/ -static void -curses_panel_notfound_error(const char *called_funcname, - const char *caller_funcname) -{ - assert(!(called_funcname == NULL && caller_funcname == NULL)); - if (caller_funcname == NULL) { - (void)PyErr_Format(PyExc_RuntimeError, - "%s(): cannot find panel object", - called_funcname); - } - else { - (void)PyErr_Format(PyExc_RuntimeError, - "%s() (called by %s()): cannot find panel object", - called_funcname, caller_funcname); - } -} - /* Utility Functions */ /* - * Check the return code from a curses function, returning None - * on success and setting an exception on error. + * Check the return code from a curses function and return None + * or raise an exception as appropriate. */ static PyObject * -curses_panel_panel_check_err(PyCursesPanelObject *panel, int code, - const char *curses_funcname, - const char *python_funcname) +PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname) { if (code != ERR) { Py_RETURN_NONE; } - curses_panel_panel_set_error(panel, curses_funcname, python_funcname); - return NULL; + else { + if (fname == NULL) { + PyErr_SetString(state->PyCursesError, catchall_ERR); + } + else { + PyErr_Format(state->PyCursesError, "%s() returned ERR", fname); + } + return NULL; + } } /***************************************************************************** @@ -233,7 +95,7 @@ curses_panel_panel_check_err(PyCursesPanelObject *panel, int code, /* Definition of the panel object and panel type */ -typedef struct PyCursesPanelObject { +typedef struct { PyObject_HEAD PANEL *pan; PyCursesWindowObject *wo; /* for reference counts */ @@ -296,7 +158,8 @@ remove_lop(PyCursesPanelObject *po) } while (temp->next == NULL || temp->next->po != po) { if (temp->next == NULL) { - curses_panel_notfound_error("remove_lop", NULL); + PyErr_SetString(PyExc_RuntimeError, + "remove_lop: can't find Panel Object"); return; } temp = temp->next; @@ -309,7 +172,7 @@ remove_lop(PyCursesPanelObject *po) /* Return the panel object that corresponds to pan */ static PyCursesPanelObject * -find_po_impl(PANEL *pan) +find_po(PANEL *pan) { list_of_panels *temp; for (temp = lop; temp->po->pan != pan; temp = temp->next) @@ -317,17 +180,6 @@ find_po_impl(PANEL *pan) return temp->po; } -/* Same as find_po_impl() but with caller context information. */ -static PyCursesPanelObject * -find_po(PANEL *pan, const char *called_funcname, const char *caller_funcname) -{ - PyCursesPanelObject *res = find_po_impl(pan); - if (res == NULL) { - curses_panel_notfound_error(called_funcname, caller_funcname); - } - return res; -} - /*[clinic input] module _curses_panel class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type" @@ -341,59 +193,67 @@ class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type" /*[clinic input] _curses_panel.panel.bottom + cls: defining_class + Push the panel to the bottom of the stack. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_bottom_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/ +_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=8ec7fbbc08554021 input=6b7d2c0578b5a1c4]*/ { - int rtn = bottom_panel(self->pan); - return curses_panel_panel_check_err(self, rtn, "bottom_panel", "bottom"); + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, bottom_panel(self->pan), "bottom"); } /*[clinic input] _curses_panel.panel.hide + cls: defining_class + Hide the panel. This does not delete the object, it just makes the window on screen invisible. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_hide_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/ +_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=cc6ab7203cdc1450 input=1bfc741f473e6055]*/ { - int rtn = hide_panel(self->pan); - return curses_panel_panel_check_err(self, rtn, "hide_panel", "hide"); + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, hide_panel(self->pan), "hide"); } /*[clinic input] _curses_panel.panel.show + cls: defining_class + Display the panel (which might have been hidden). [clinic start generated code]*/ static PyObject * -_curses_panel_panel_show_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/ +_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=dc3421de375f0409 input=8122e80151cb4379]*/ { - int rtn = show_panel(self->pan); - return curses_panel_panel_check_err(self, rtn, "show_panel", "show"); + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, show_panel(self->pan), "show"); } /*[clinic input] _curses_panel.panel.top + cls: defining_class + Push panel to the top of the stack. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_top_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/ +_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=10a072e511e873f7 input=1f372d597dda3379]*/ { - int rtn = top_panel(self->pan); - return curses_panel_panel_check_err(self, rtn, "top_panel", "top"); + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, top_panel(self->pan), "top"); } /* Allocation and deallocation of Panel Objects */ @@ -455,11 +315,18 @@ _curses_panel_panel_above_impl(PyCursesPanelObject *self) PyCursesPanelObject *po; pan = panel_above(self->pan); - if (pan == NULL) { /* valid output: it means no panel exists yet */ + + if (pan == NULL) { /* valid output, it means the calling panel + is on top of the stack */ Py_RETURN_NONE; } - po = find_po(pan, "panel_above", "above"); - return Py_XNewRef(po); + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + return Py_NewRef(po); } /* panel_below(NULL) returns the top panel in the stack. To get @@ -478,11 +345,18 @@ _curses_panel_panel_below_impl(PyCursesPanelObject *self) PyCursesPanelObject *po; pan = panel_below(self->pan); - if (pan == NULL) { /* valid output: it means no panel exists yet */ + + if (pan == NULL) { /* valid output, it means the calling panel + is on the bottom of the stack */ Py_RETURN_NONE; } - po = find_po(pan, "panel_below", "below"); - return Py_XNewRef(po); + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + return Py_NewRef(po); } /*[clinic input] @@ -504,6 +378,7 @@ _curses_panel_panel_hidden_impl(PyCursesPanelObject *self) /*[clinic input] _curses_panel.panel.move + cls: defining_class y: int x: int / @@ -512,11 +387,12 @@ Move the panel to the screen coordinates (y, x). [clinic start generated code]*/ static PyObject * -_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x) -/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/ +_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, + int y, int x) +/*[clinic end generated code: output=ce546c93e56867da input=60a0e7912ff99849]*/ { - int rtn = move_panel(self->pan, y, x); - return curses_panel_panel_check_err(self, rtn, "move_panel", "move"); + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, move_panel(self->pan, y, x), "move_panel"); } /*[clinic input] @@ -535,6 +411,7 @@ _curses_panel_panel_window_impl(PyCursesPanelObject *self) /*[clinic input] _curses_panel.panel.replace + cls: defining_class win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") / @@ -543,17 +420,22 @@ Change the window associated with the panel to the window win. static PyObject * _curses_panel_panel_replace_impl(PyCursesPanelObject *self, + PyTypeObject *cls, PyCursesWindowObject *win) -/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/ +/*[clinic end generated code: output=c71f95c212d58ae7 input=dbec7180ece41ff5]*/ { - PyCursesPanelObject *po = find_po(self->pan, "replace", NULL); + _curses_panel_state *state = PyType_GetModuleState(cls); + + PyCursesPanelObject *po = find_po(self->pan); if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "replace_panel: can't find Panel Object"); return NULL; } int rtn = replace_panel(self->pan, win->win); if (rtn == ERR) { - curses_panel_panel_set_error(self, "replace_panel", "replace"); + PyErr_SetString(state->PyCursesError, "replace_panel() returned ERR"); return NULL; } Py_SETREF(po->wo, (PyCursesWindowObject*)Py_NewRef(win)); @@ -563,6 +445,7 @@ _curses_panel_panel_replace_impl(PyCursesPanelObject *self, /*[clinic input] _curses_panel.panel.set_userptr + cls: defining_class obj: object / @@ -571,8 +454,8 @@ Set the panel's user pointer to obj. static PyObject * _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, - PyObject *obj) -/*[clinic end generated code: output=7fa1fd23f69db71e input=d2c6a9dbefabbf39]*/ + PyTypeObject *cls, PyObject *obj) +/*[clinic end generated code: output=db74f3db07b28080 input=e3fee2ff7b1b8e48]*/ { PyCursesInitialised; Py_INCREF(obj); @@ -581,30 +464,34 @@ _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, if (rc == ERR) { /* In case of an ncurses error, decref the new object again */ Py_DECREF(obj); - curses_panel_panel_set_error(self, - "set_panel_userptr", "set_userptr"); - return NULL; } - Py_XDECREF(oldobj); - Py_RETURN_NONE; + else { + Py_XDECREF(oldobj); + } + + _curses_panel_state *state = PyType_GetModuleState(cls); + return PyCursesCheckERR(state, rc, "set_panel_userptr"); } /*[clinic input] _curses_panel.panel.userptr + cls: defining_class + Return the user pointer for the panel. [clinic start generated code]*/ static PyObject * -_curses_panel_panel_userptr_impl(PyCursesPanelObject *self) -/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/ +_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, + PyTypeObject *cls) +/*[clinic end generated code: output=eea6e6f39ffc0179 input=f22ca4f115e30a80]*/ { + _curses_panel_state *state = PyType_GetModuleState(cls); + PyCursesInitialised; PyObject *obj = (PyObject *) panel_userptr(self->pan); if (obj == NULL) { - curses_panel_panel_set_null_error(self, - "panel_userptr", - "userptr"); + PyErr_SetString(state->PyCursesError, "no userptr set"); return NULL; } @@ -665,11 +552,18 @@ _curses_panel_bottom_panel_impl(PyObject *module) PyCursesInitialised; pan = panel_above(NULL); - if (pan == NULL) { /* valid output: it means no panel exists yet */ + + if (pan == NULL) { /* valid output, it means + there's no panel at all */ Py_RETURN_NONE; } - po = find_po(pan, "panel_above", "bottom_panel"); - return Py_XNewRef(po); + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + return Py_NewRef(po); } /*[clinic input] @@ -685,13 +579,14 @@ static PyObject * _curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win) /*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/ { + _curses_panel_state *state = get_curses_panel_state(module); + PANEL *pan = new_panel(win->win); if (pan == NULL) { - curses_panel_set_null_error(module, "new_panel", NULL); + PyErr_SetString(state->PyCursesError, catchall_NULL); return NULL; } - _curses_panel_state *state = get_curses_panel_state(module); - return PyCursesPanel_New(state, pan, win); + return (PyObject *)PyCursesPanel_New(state, pan, win); } @@ -715,11 +610,18 @@ _curses_panel_top_panel_impl(PyObject *module) PyCursesInitialised; pan = panel_below(NULL); - if (pan == NULL) { /* valid output: it means no panel exists yet */ + + if (pan == NULL) { /* valid output, it means + there's no panel at all */ Py_RETURN_NONE; } - po = find_po(pan, "panel_below", "top_panel"); - return Py_XNewRef(po); + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + return Py_NewRef(po); } /*[clinic input] @@ -771,10 +673,10 @@ _curses_panel_exec(PyObject *mod) } /* For exception _curses_panel.error */ - state->error = PyErr_NewException( + state->PyCursesError = PyErr_NewException( "_curses_panel.error", NULL, NULL); - if (PyModule_AddObjectRef(mod, "error", state->error) < 0) { + if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) { return -1; } diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h index 75cf067c8aa822..6f4966825ec4bf 100644 --- a/Modules/clinic/_curses_panel.c.h +++ b/Modules/clinic/_curses_panel.c.h @@ -2,7 +2,10 @@ preserve [clinic start generated code]*/ -#include "pycore_modsupport.h" // _PyArg_CheckPositional() +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_runtime.h" // _Py_SINGLETON() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(_curses_panel_panel_bottom__doc__, "bottom($self, /)\n" @@ -11,15 +14,19 @@ PyDoc_STRVAR(_curses_panel_panel_bottom__doc__, "Push the panel to the bottom of the stack."); #define _CURSES_PANEL_PANEL_BOTTOM_METHODDEF \ - {"bottom", (PyCFunction)_curses_panel_panel_bottom, METH_NOARGS, _curses_panel_panel_bottom__doc__}, + {"bottom", _PyCFunction_CAST(_curses_panel_panel_bottom), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_bottom__doc__}, static PyObject * -_curses_panel_panel_bottom_impl(PyCursesPanelObject *self); +_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls); static PyObject * -_curses_panel_panel_bottom(PyObject *self, PyObject *Py_UNUSED(ignored)) +_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments"); + return NULL; + } + return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls); } PyDoc_STRVAR(_curses_panel_panel_hide__doc__, @@ -31,15 +38,19 @@ PyDoc_STRVAR(_curses_panel_panel_hide__doc__, "This does not delete the object, it just makes the window on screen invisible."); #define _CURSES_PANEL_PANEL_HIDE_METHODDEF \ - {"hide", (PyCFunction)_curses_panel_panel_hide, METH_NOARGS, _curses_panel_panel_hide__doc__}, + {"hide", _PyCFunction_CAST(_curses_panel_panel_hide), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_hide__doc__}, static PyObject * -_curses_panel_panel_hide_impl(PyCursesPanelObject *self); +_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls); static PyObject * -_curses_panel_panel_hide(PyObject *self, PyObject *Py_UNUSED(ignored)) +_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "hide() takes no arguments"); + return NULL; + } + return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls); } PyDoc_STRVAR(_curses_panel_panel_show__doc__, @@ -49,15 +60,19 @@ PyDoc_STRVAR(_curses_panel_panel_show__doc__, "Display the panel (which might have been hidden)."); #define _CURSES_PANEL_PANEL_SHOW_METHODDEF \ - {"show", (PyCFunction)_curses_panel_panel_show, METH_NOARGS, _curses_panel_panel_show__doc__}, + {"show", _PyCFunction_CAST(_curses_panel_panel_show), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_show__doc__}, static PyObject * -_curses_panel_panel_show_impl(PyCursesPanelObject *self); +_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls); static PyObject * -_curses_panel_panel_show(PyObject *self, PyObject *Py_UNUSED(ignored)) +_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _curses_panel_panel_show_impl((PyCursesPanelObject *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "show() takes no arguments"); + return NULL; + } + return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls); } PyDoc_STRVAR(_curses_panel_panel_top__doc__, @@ -67,15 +82,19 @@ PyDoc_STRVAR(_curses_panel_panel_top__doc__, "Push panel to the top of the stack."); #define _CURSES_PANEL_PANEL_TOP_METHODDEF \ - {"top", (PyCFunction)_curses_panel_panel_top, METH_NOARGS, _curses_panel_panel_top__doc__}, + {"top", _PyCFunction_CAST(_curses_panel_panel_top), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_top__doc__}, static PyObject * -_curses_panel_panel_top_impl(PyCursesPanelObject *self); +_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls); static PyObject * -_curses_panel_panel_top(PyObject *self, PyObject *Py_UNUSED(ignored)) +_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _curses_panel_panel_top_impl((PyCursesPanelObject *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "top() takes no arguments"); + return NULL; + } + return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls); } PyDoc_STRVAR(_curses_panel_panel_above__doc__, @@ -139,19 +158,36 @@ PyDoc_STRVAR(_curses_panel_panel_move__doc__, "Move the panel to the screen coordinates (y, x)."); #define _CURSES_PANEL_PANEL_MOVE_METHODDEF \ - {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_FASTCALL, _curses_panel_panel_move__doc__}, + {"move", _PyCFunction_CAST(_curses_panel_panel_move), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_move__doc__}, static PyObject * -_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x); +_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls, + int y, int x); static PyObject * -_curses_panel_panel_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "move", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; int y; int x; - if (!_PyArg_CheckPositional("move", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } y = PyLong_AsInt(args[0]); @@ -162,7 +198,7 @@ _curses_panel_panel_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs if (x == -1 && PyErr_Occurred()) { goto exit; } - return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, y, x); + return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x); exit: return return_value; @@ -193,24 +229,44 @@ PyDoc_STRVAR(_curses_panel_panel_replace__doc__, "Change the window associated with the panel to the window win."); #define _CURSES_PANEL_PANEL_REPLACE_METHODDEF \ - {"replace", (PyCFunction)_curses_panel_panel_replace, METH_O, _curses_panel_panel_replace__doc__}, + {"replace", _PyCFunction_CAST(_curses_panel_panel_replace), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_replace__doc__}, static PyObject * _curses_panel_panel_replace_impl(PyCursesPanelObject *self, + PyTypeObject *cls, PyCursesWindowObject *win); static PyObject * -_curses_panel_panel_replace(PyObject *self, PyObject *arg) +_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "replace", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyCursesWindowObject *win; - if (!PyObject_TypeCheck(arg, &PyCursesWindow_Type)) { - _PyArg_BadArgument("replace", "argument", (&PyCursesWindow_Type)->tp_name, arg); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } - win = (PyCursesWindowObject *)arg; - return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, win); + if (!PyObject_TypeCheck(args[0], &PyCursesWindow_Type)) { + _PyArg_BadArgument("replace", "argument 1", (&PyCursesWindow_Type)->tp_name, args[0]); + goto exit; + } + win = (PyCursesWindowObject *)args[0]; + return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win); exit: return return_value; @@ -223,19 +279,41 @@ PyDoc_STRVAR(_curses_panel_panel_set_userptr__doc__, "Set the panel\'s user pointer to obj."); #define _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF \ - {"set_userptr", (PyCFunction)_curses_panel_panel_set_userptr, METH_O, _curses_panel_panel_set_userptr__doc__}, + {"set_userptr", _PyCFunction_CAST(_curses_panel_panel_set_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_set_userptr__doc__}, static PyObject * _curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self, - PyObject *obj); + PyTypeObject *cls, PyObject *obj); static PyObject * -_curses_panel_panel_set_userptr(PyObject *self, PyObject *obj) +_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_userptr", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *obj; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + obj = args[0]; + return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj); - return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, obj); - +exit: return return_value; } @@ -246,15 +324,20 @@ PyDoc_STRVAR(_curses_panel_panel_userptr__doc__, "Return the user pointer for the panel."); #define _CURSES_PANEL_PANEL_USERPTR_METHODDEF \ - {"userptr", (PyCFunction)_curses_panel_panel_userptr, METH_NOARGS, _curses_panel_panel_userptr__doc__}, + {"userptr", _PyCFunction_CAST(_curses_panel_panel_userptr), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _curses_panel_panel_userptr__doc__}, static PyObject * -_curses_panel_panel_userptr_impl(PyCursesPanelObject *self); +_curses_panel_panel_userptr_impl(PyCursesPanelObject *self, + PyTypeObject *cls); static PyObject * -_curses_panel_panel_userptr(PyObject *self, PyObject *Py_UNUSED(ignored)) +_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments"); + return NULL; + } + return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls); } PyDoc_STRVAR(_curses_panel_bottom_panel__doc__, @@ -341,4 +424,4 @@ _curses_panel_update_panels(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _curses_panel_update_panels_impl(module); } -/*[clinic end generated code: output=db2fe491582784aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/ From 3989ddd2e9b8c172be9b055a63779fcda716ac54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 May 2025 12:39:02 +0200 Subject: [PATCH 23/25] fix typo --- Modules/_cursesmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 2c88c59956f464..03a5cb6383c2ad 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -392,7 +392,7 @@ _PyCursesStatefulCheckFunction(PyObject *module, */ /* - * Return None if 'code' is ERR. Otherwise, set an exception + * Return None if 'code' is OK. Otherwise, set an exception * using curses_set_error() and the remaining arguments, and * return NULL. */ @@ -402,6 +402,7 @@ curses_check_err(PyObject *module, int code, const char *python_funcname) { if (code != ERR) { + assert(code == OK); Py_RETURN_NONE; } curses_set_error(module, curses_funcname, python_funcname); @@ -415,6 +416,7 @@ curses_window_check_err(PyCursesWindowObject *win, int code, const char *python_funcname) { if (code != ERR) { + assert(code == OK); Py_RETURN_NONE; } curses_window_set_error(win, curses_funcname, python_funcname); From bf54774a2c97b6556d1828be43550ac6c21dca83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 May 2025 12:51:07 +0200 Subject: [PATCH 24/25] correctly check `mouseinterval` return value --- Modules/_cursesmodule.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 03a5cb6383c2ad..7a8ccba64b2569 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3993,8 +3993,12 @@ _curses_mouseinterval_impl(PyObject *module, int interval) /*[clinic end generated code: output=c4f5ff04354634c5 input=75aaa3f0db10ac4e]*/ { PyCursesStatefulInitialised(module); - int rtn = mouseinterval(interval); - return curses_check_err(module, rtn, "mouseinterval", NULL); + int value = mouseinterval(interval); + if (value == ERR) { + curses_set_error(module, "mouseinterval", NULL); + return NULL; + } + return PyLong_FromLong(value); } /*[clinic input] From 6be3a15886171518940c03350959094607afe82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 May 2025 15:18:12 +0200 Subject: [PATCH 25/25] reduce overall diff Co-authored-by: Petr Viktorin --- Modules/_cursesmodule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 7d45cd599e71f0..ab63fdbe45de61 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1405,7 +1405,7 @@ _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, return NULL; } } - (void)box(self->win,ch1,ch2); + box(self->win,ch1,ch2); Py_RETURN_NONE; } @@ -1504,12 +1504,12 @@ PyCursesWindow_ChgAt(PyObject *op, PyObject *args) if (use_xy) { rtn = mvwchgat(self->win,y,x,num,attr,color,NULL); - (void)touchline(self->win,y,1); + touchline(self->win,y,1); funcname = "mvwchgat"; } else { getyx(self->win,y,x); rtn = wchgat(self->win,num,attr,color,NULL); - (void)touchline(self->win,y,1); + touchline(self->win,y,1); funcname = "wchgat"; } return curses_window_check_err(self, rtn, funcname, "chgat"); @@ -3593,7 +3593,7 @@ _curses_initscr_impl(PyObject *module) WINDOW *win; if (curses_initscr_called) { - (void)wrefresh(stdscr); // TODO(picnixz): should we report an error? + wrefresh(stdscr); cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, stdscr, NULL, NULL); }