Skip to content

Commit 3a3964b

Browse files
committed
simplify logic
1 parent 758dfe5 commit 3a3964b

File tree

3 files changed

+37
-236
lines changed

3 files changed

+37
-236
lines changed

Lib/test/test_curses.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -132,38 +132,6 @@ def test_use_env(self):
132132
def test_error(self):
133133
self.assertTrue(issubclass(curses.error, Exception))
134134

135-
def raise_curses_error(*args):
136-
raise curses.error(*args)
137-
138-
with self.assertRaisesRegex(curses.error, "test") as cm:
139-
raise_curses_error('test')
140-
self.assertSequenceEqual(cm.exception.args, ('test',))
141-
142-
with self.assertRaisesRegex(curses.error, "test") as cm:
143-
raise_curses_error('test', '1', '2')
144-
self.assertSequenceEqual(cm.exception.args, ('test', '1', '2'))
145-
146-
def test_error_attributes(self):
147-
error = curses.error()
148-
self.assertSequenceEqual(error.args, ())
149-
self.assertIsNone(error.funcname)
150-
151-
error = curses.error('test')
152-
self.assertSequenceEqual(error.args, ('test',))
153-
self.assertIsNone(error.funcname)
154-
155-
error = curses.error('test with curses function')
156-
error.funcname = 'curses function'
157-
self.assertSequenceEqual(error.args, ('test with curses function',))
158-
self.assertEqual(error.funcname, 'curses function')
159-
160-
error = curses.error('unset attributes')
161-
error.funcname = 'a'
162-
error.funcname = None
163-
self.assertIsNone(error.funcname)
164-
165-
self.assertRaises(TypeError, setattr, error, 'funcname', 1)
166-
167135
def test_create_windows(self):
168136
win = curses.newwin(5, 10)
169137
self.assertEqual(win.getbegyx(), (0, 0))

Modules/_cursesmodule.c

Lines changed: 36 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,8 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *win)
194194
/*[clinic input]
195195
module _curses
196196
class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type"
197-
class _curses.error "PyCursesErrorObject *" "clinic_state()->error"
198197
[clinic start generated code]*/
199-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a6b4ac3824e7c5c3]*/
198+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/
200199

201200
/* Indicate whether the module has already been loaded or not. */
202201
static int curses_module_loaded = 0;
@@ -214,110 +213,14 @@ static const char *curses_screen_encoding = NULL;
214213

215214
/* Error type */
216215

217-
#define CURSES_ERROR_FORMAT "%s() returned ERR"
218-
#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL"
219-
#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first"
220-
221-
typedef struct {
222-
PyException_HEAD
223-
/* The name of the curses function that triggered the error. */
224-
PyObject *funcname;
225-
} PyCursesErrorObject;
226-
227-
#define _PyCursesErrorObject_CAST(PTR) ((PyCursesErrorObject *)(PTR))
228-
229-
static int
230-
PyCursesError_clear(PyObject *self)
231-
{
232-
PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self);
233-
Py_CLEAR(exc->funcname);
234-
return _PyType_CAST(PyExc_Exception)->tp_clear(self);
235-
}
236-
237-
static void
238-
PyCursesError_dealloc(PyObject *self)
239-
{
240-
PyTypeObject *tp = Py_TYPE(self);
241-
PyObject_GC_UnTrack(self);
242-
(void)PyCursesError_clear(self);
243-
tp->tp_free(self);
244-
Py_DECREF(tp);
245-
}
246-
247-
static int
248-
PyCursesError_traverse(PyObject *self, visitproc visit, void *arg)
249-
{
250-
Py_VISIT(Py_TYPE(self));
251-
PyCursesErrorObject *exc = _PyCursesErrorObject_CAST(self);
252-
Py_VISIT(exc->funcname);
253-
return _PyType_CAST(PyExc_Exception)->tp_traverse(self, visit, arg);
254-
}
255-
256-
/*[clinic input]
257-
@getter
258-
_curses.error.funcname
259-
[clinic start generated code]*/
260-
261-
static PyObject *
262-
_curses_error_funcname_get_impl(PyCursesErrorObject *self)
263-
/*[clinic end generated code: output=bddac78d045d9e92 input=a0ed7b814bba25e9]*/
264-
{
265-
PyObject *res = self->funcname;
266-
return res == NULL ? Py_None : Py_NewRef(res);
267-
}
268-
269-
/*[clinic input]
270-
@setter
271-
_curses.error.funcname
272-
[clinic start generated code]*/
273-
274-
static int
275-
_curses_error_funcname_set_impl(PyCursesErrorObject *self, PyObject *value)
276-
/*[clinic end generated code: output=1320e03bf8c27ca8 input=e7ad8f11456a402e]*/
277-
{
278-
if (PyUnicode_Check(value) || Py_IsNone(value)) {
279-
Py_XSETREF(self->funcname, Py_NewRef(value));
280-
return 0;
281-
}
282-
PyErr_Format(PyExc_TypeError, "expecting a str or None, got %T", value);
283-
return -1;
284-
}
216+
#define CURSES_ERROR_FORMAT "%s() returned ERR"
217+
#define CURSES_ERROR_VERBOSE_FORMAT "%s() (called by %s()) returned ERR"
218+
#define CURSES_ERROR_NULL_FORMAT "%s() returned NULL"
219+
#define CURSES_ERROR_NULL_VERBOSE_FORMAT "%s() (called by %s()) returned NULL"
220+
#define CURSES_ERROR_MUST_CALL_FORMAT "must call %s() first"
285221

286222
/* Utility Error Procedures */
287223

288-
static inline void
289-
PyCursesError_SetImplementation(
290-
#ifndef NDEBUG
291-
cursesmodule_state *state,
292-
#else
293-
cursesmodule_state *Py_UNUSED(state),
294-
#endif
295-
const char *funcname)
296-
{
297-
assert(funcname != NULL);
298-
PyObject *exc = PyErr_GetRaisedException();
299-
assert(PyErr_GivenExceptionMatches(exc, state->error));
300-
PyObject *p_funcname = PyUnicode_FromString(funcname);
301-
if (p_funcname == NULL) {
302-
goto error;
303-
}
304-
int rc = PyObject_SetAttrString(exc, "funcname", p_funcname);
305-
Py_DECREF(p_funcname);
306-
if (rc < 0) {
307-
goto error;
308-
}
309-
310-
restore:
311-
PyErr_SetRaisedException(exc);
312-
return;
313-
314-
error:
315-
// The curses exception is likely more important than the
316-
// exceptions that we get if we fail to set the attribute.
317-
PyErr_Clear();
318-
goto restore;
319-
}
320-
321224
/*
322225
* Format a curses error.
323226
*
@@ -335,10 +238,18 @@ _PyCursesSetError(cursesmodule_state *state,
335238
return;
336239
}
337240
if (simple_funcname == NULL) {
338-
simple_funcname = curses_funcname;
241+
PyErr_Format(state->error, CURSES_ERROR_FORMAT, curses_funcname);
242+
}
243+
else if (curses_funcname == NULL) {
244+
PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname);
245+
}
246+
else if (strcmp(simple_funcname, curses_funcname) == 0) {
247+
PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname);
248+
}
249+
else {
250+
PyErr_Format(state->error, CURSES_ERROR_VERBOSE_FORMAT,
251+
curses_funcname, simple_funcname);
339252
}
340-
PyErr_Format(state->error, CURSES_ERROR_FORMAT, simple_funcname);
341-
PyCursesError_SetImplementation(state, curses_funcname);
342253
}
343254

344255
static void
@@ -1673,7 +1584,6 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
16731584
if (win == NULL) {
16741585
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
16751586
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "derwin");
1676-
PyCursesError_SetImplementation(state, "derwin");
16771587
return NULL;
16781588
}
16791589

@@ -1830,9 +1740,8 @@ _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1,
18301740
PyErr_CheckSignals();
18311741
if (!PyErr_Occurred()) {
18321742
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
1833-
PyErr_SetString(state->error, "no input");
18341743
const char *funcname = group_right_1 ? "mvwgetch" : "wgetch";
1835-
PyCursesError_SetImplementation(state, funcname);
1744+
PyErr_Format(state->error, "getkey(): %s(): no input", funcname);
18361745
}
18371746
return NULL;
18381747
} else if (rtn <= 255) {
@@ -1894,7 +1803,7 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1,
18941803
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
18951804
PyErr_SetString(state->error, "no input");
18961805
const char *funcname = group_right_1 ? "mvwget_wch" : "wget_wch";
1897-
PyCursesError_SetImplementation(state, funcname);
1806+
PyErr_Format(state->error, "get_wch(): %s(): no input", funcname);
18981807
return NULL;
18991808
}
19001809
if (ct == KEY_CODE_YES)
@@ -2752,8 +2661,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
27522661

27532662
if (win == NULL) {
27542663
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
2755-
PyErr_SetString(state->error, catchall_NULL);
2756-
PyCursesError_SetImplementation(state, curses_funcname);
2664+
PyErr_Format(state->error, CURSES_ERROR_NULL_VERBOSE_FORMAT,
2665+
curses_funcname, "subwin");
27572666
return NULL;
27582667
}
27592668

@@ -2916,29 +2825,6 @@ PyCursesWindow_set_encoding(PyObject *op, PyObject *value, void *Py_UNUSED(ignor
29162825
#include "clinic/_cursesmodule.c.h"
29172826
#undef clinic_state
29182827

2919-
static PyGetSetDef PyCursesError_Type_getsets[] = {
2920-
_CURSES_ERROR_FUNCNAME_GETSETDEF
2921-
{NULL}
2922-
};
2923-
2924-
static PyType_Slot PyCursesError_Type_slots[] = {
2925-
{Py_tp_getset, PyCursesError_Type_getsets},
2926-
{Py_tp_dealloc, PyCursesError_dealloc},
2927-
{Py_tp_traverse, PyCursesError_traverse},
2928-
{Py_tp_clear, PyCursesError_clear},
2929-
{0, NULL},
2930-
};
2931-
2932-
static PyType_Spec PyCursesError_Type_spec = {
2933-
.name = "_curses.error",
2934-
.basicsize = sizeof(PyCursesErrorObject),
2935-
.flags = Py_TPFLAGS_DEFAULT
2936-
| Py_TPFLAGS_BASETYPE
2937-
| Py_TPFLAGS_IMMUTABLETYPE
2938-
| Py_TPFLAGS_HAVE_GC,
2939-
.slots = PyCursesError_Type_slots,
2940-
};
2941-
29422828
static PyMethodDef PyCursesWindow_methods[] = {
29432829
_CURSES_WINDOW_ADDCH_METHODDEF
29442830
_CURSES_WINDOW_ADDNSTR_METHODDEF
@@ -3547,8 +3433,7 @@ _curses_getwin(PyObject *module, PyObject *file)
35473433
win = getwin(fp);
35483434
if (win == NULL) {
35493435
cursesmodule_state *state = get_cursesmodule_state(module);
3550-
PyErr_SetString(state->error, catchall_NULL);
3551-
PyCursesError_SetImplementation(state, "getwin");
3436+
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "getwin");
35523437
goto error;
35533438
}
35543439
cursesmodule_state *state = get_cursesmodule_state(module);
@@ -3730,8 +3615,7 @@ _curses_initscr_impl(PyObject *module)
37303615

37313616
if (win == NULL) {
37323617
cursesmodule_state *state = get_cursesmodule_state(module);
3733-
PyErr_SetString(state->error, catchall_NULL);
3734-
PyCursesError_SetImplementation(state, "initscr");
3618+
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "initscr");
37353619
return NULL;
37363620
}
37373621

@@ -3891,7 +3775,6 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd)
38913775

38923776
cursesmodule_state *state = get_cursesmodule_state(module);
38933777
PyErr_SetString(state->error, s);
3894-
PyCursesError_SetImplementation(state, "setupterm");
38953778
return NULL;
38963779
}
38973780

@@ -4212,8 +4095,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
42124095

42134096
if (win == NULL) {
42144097
cursesmodule_state *state = get_cursesmodule_state(module);
4215-
PyErr_SetString(state->error, catchall_NULL);
4216-
PyCursesError_SetImplementation(state, "newpad");
4098+
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newpad");
42174099
return NULL;
42184100
}
42194101

@@ -4254,8 +4136,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
42544136
win = newwin(nlines,ncols,begin_y,begin_x);
42554137
if (win == NULL) {
42564138
cursesmodule_state *state = get_cursesmodule_state(module);
4257-
PyErr_SetString(state->error, catchall_NULL);
4258-
PyCursesError_SetImplementation(state, "newwin");
4139+
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "newwin");
42594140
return NULL;
42604141
}
42614142

@@ -4857,7 +4738,6 @@ _curses_tparm_impl(PyObject *module, const char *str, int i1, int i2, int i3,
48574738
if (!result) {
48584739
cursesmodule_state *state = get_cursesmodule_state(module);
48594740
PyErr_Format(state->error, CURSES_ERROR_NULL_FORMAT, "tparm");
4860-
PyCursesError_SetImplementation(state, "tparm");
48614741
return NULL;
48624742
}
48634743

@@ -5348,22 +5228,7 @@ cursesmodule_exec(PyObject *module)
53485228
curses_module_loaded = 1;
53495229

53505230
cursesmodule_state *state = get_cursesmodule_state(module);
5351-
/* Initialize error type */
5352-
PyObject *bases = PyTuple_Pack(1, PyExc_Exception);
5353-
if (bases == NULL) {
5354-
return -1;
5355-
}
5356-
state->error = PyType_FromModuleAndSpec(module, &PyCursesError_Type_spec,
5357-
bases);
5358-
Py_DECREF(bases);
5359-
if (state->error == NULL) {
5360-
return -1;
5361-
}
5362-
if (PyModule_AddType(module, _PyType_CAST(state->error)) < 0) {
5363-
return -1;
5364-
}
5365-
5366-
/* Initialize window type */
5231+
/* Initialize object type */
53675232
state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec(
53685233
module, &PyCursesWindow_Type_spec, NULL);
53695234
if (state->window_type == NULL) {
@@ -5396,6 +5261,16 @@ cursesmodule_exec(PyObject *module)
53965261
return -1;
53975262
}
53985263

5264+
/* For exception curses.error */
5265+
state->error = PyErr_NewException("_curses.error", NULL, NULL);
5266+
if (state->error == NULL) {
5267+
return -1;
5268+
}
5269+
rc = PyDict_SetItemString(module_dict, "error", state->error);
5270+
if (rc < 0) {
5271+
return -1;
5272+
}
5273+
53995274
/* Make the version available */
54005275
PyObject *curses_version = PyBytes_FromString(PyCursesVersion);
54015276
if (curses_version == NULL) {

0 commit comments

Comments
 (0)