| #include "parts.h" |
| |
| static PyObject * |
| err_set_raised(PyObject *self, PyObject *exc) |
| { |
| Py_INCREF(exc); |
| PyErr_SetRaisedException(exc); |
| assert(PyErr_Occurred()); |
| return NULL; |
| } |
| |
| static PyObject * |
| err_restore(PyObject *self, PyObject *args) { |
| PyObject *type = NULL, *value = NULL, *traceback = NULL; |
| switch(PyTuple_Size(args)) { |
| case 3: |
| traceback = PyTuple_GetItem(args, 2); |
| Py_INCREF(traceback); |
| /* fall through */ |
| case 2: |
| value = PyTuple_GetItem(args, 1); |
| Py_INCREF(value); |
| /* fall through */ |
| case 1: |
| type = PyTuple_GetItem(args, 0); |
| Py_INCREF(type); |
| break; |
| default: |
| PyErr_SetString(PyExc_TypeError, |
| "wrong number of arguments"); |
| return NULL; |
| } |
| PyErr_Restore(type, value, traceback); |
| assert(PyErr_Occurred()); |
| return NULL; |
| } |
| |
| /* To test the format of exceptions as printed out. */ |
| static PyObject * |
| exception_print(PyObject *self, PyObject *args) |
| { |
| PyObject *value; |
| PyObject *tb = NULL; |
| |
| if (!PyArg_ParseTuple(args, "O:exception_print", &value)) { |
| return NULL; |
| } |
| |
| if (PyExceptionInstance_Check(value)) { |
| tb = PyException_GetTraceback(value); |
| } |
| |
| PyErr_Display((PyObject *) Py_TYPE(value), value, tb); |
| Py_XDECREF(tb); |
| |
| Py_RETURN_NONE; |
| } |
| |
| /* Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException). |
| Run via Lib/test/test_exceptions.py */ |
| static PyObject * |
| make_exception_with_doc(PyObject *self, PyObject *args, PyObject *kwargs) |
| { |
| const char *name; |
| const char *doc = NULL; |
| PyObject *base = NULL; |
| PyObject *dict = NULL; |
| |
| static char *kwlist[] = {"name", "doc", "base", "dict", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, |
| "s|sOO:make_exception_with_doc", kwlist, |
| &name, &doc, &base, &dict)) |
| { |
| return NULL; |
| } |
| |
| return PyErr_NewExceptionWithDoc(name, doc, base, dict); |
| } |
| |
| static PyObject * |
| exc_set_object(PyObject *self, PyObject *args) |
| { |
| PyObject *exc; |
| PyObject *obj; |
| |
| if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { |
| return NULL; |
| } |
| |
| PyErr_SetObject(exc, obj); |
| return NULL; |
| } |
| |
| static PyObject * |
| raise_exception(PyObject *self, PyObject *args) |
| { |
| PyObject *exc; |
| int num_args; |
| |
| if (!PyArg_ParseTuple(args, "Oi:raise_exception", &exc, &num_args)) { |
| return NULL; |
| } |
| |
| PyObject *exc_args = PyTuple_New(num_args); |
| if (exc_args == NULL) { |
| return NULL; |
| } |
| for (int i = 0; i < num_args; ++i) { |
| PyObject *v = PyLong_FromLong(i); |
| if (v == NULL) { |
| Py_DECREF(exc_args); |
| return NULL; |
| } |
| PyTuple_SET_ITEM(exc_args, i, v); |
| } |
| PyErr_SetObject(exc, exc_args); |
| Py_DECREF(exc_args); |
| return NULL; |
| } |
| |
| /* reliably raise a MemoryError */ |
| static PyObject * |
| raise_memoryerror(PyObject *self, PyObject *Py_UNUSED(ignored)) |
| { |
| return PyErr_NoMemory(); |
| } |
| |
| static PyObject * |
| test_fatal_error(PyObject *self, PyObject *args) |
| { |
| char *message; |
| int release_gil = 0; |
| if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil)) { |
| return NULL; |
| } |
| if (release_gil) { |
| Py_BEGIN_ALLOW_THREADS |
| Py_FatalError(message); |
| Py_END_ALLOW_THREADS |
| } |
| else { |
| Py_FatalError(message); |
| } |
| // Py_FatalError() does not return, but exits the process. |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject * |
| test_set_exc_info(PyObject *self, PyObject *args) |
| { |
| PyObject *new_type, *new_value, *new_tb; |
| PyObject *type, *value, *tb; |
| if (!PyArg_ParseTuple(args, "OOO:test_set_exc_info", |
| &new_type, &new_value, &new_tb)) |
| { |
| return NULL; |
| } |
| |
| PyErr_GetExcInfo(&type, &value, &tb); |
| |
| Py_INCREF(new_type); |
| Py_INCREF(new_value); |
| Py_INCREF(new_tb); |
| PyErr_SetExcInfo(new_type, new_value, new_tb); |
| |
| PyObject *orig_exc = PyTuple_Pack(3, |
| type ? type : Py_None, |
| value ? value : Py_None, |
| tb ? tb : Py_None); |
| Py_XDECREF(type); |
| Py_XDECREF(value); |
| Py_XDECREF(tb); |
| return orig_exc; |
| } |
| |
| static PyObject * |
| test_set_exception(PyObject *self, PyObject *new_exc) |
| { |
| PyObject *exc = PyErr_GetHandledException(); |
| assert(PyExceptionInstance_Check(exc) || exc == NULL); |
| |
| PyErr_SetHandledException(new_exc); |
| return exc; |
| } |
| |
| static PyObject * |
| test_write_unraisable_exc(PyObject *self, PyObject *args) |
| { |
| PyObject *exc, *err_msg, *obj; |
| if (!PyArg_ParseTuple(args, "OOO", &exc, &err_msg, &obj)) { |
| return NULL; |
| } |
| |
| const char *err_msg_utf8; |
| if (err_msg != Py_None) { |
| err_msg_utf8 = PyUnicode_AsUTF8(err_msg); |
| if (err_msg_utf8 == NULL) { |
| return NULL; |
| } |
| } |
| else { |
| err_msg_utf8 = NULL; |
| } |
| |
| PyErr_SetObject((PyObject *)Py_TYPE(exc), exc); |
| _PyErr_WriteUnraisableMsg(err_msg_utf8, obj); |
| Py_RETURN_NONE; |
| } |
| |
| /* To test the format of tracebacks as printed out. */ |
| static PyObject * |
| traceback_print(PyObject *self, PyObject *args) |
| { |
| PyObject *file; |
| PyObject *traceback; |
| |
| if (!PyArg_ParseTuple(args, "OO:traceback_print", |
| &traceback, &file)) |
| { |
| return NULL; |
| } |
| |
| if (PyTraceBack_Print(traceback, file) < 0) { |
| return NULL; |
| } |
| Py_RETURN_NONE; |
| } |
| |
| |
| /* |
| * Define the PyRecurdingInfinitelyError_Type |
| */ |
| |
| static PyTypeObject PyRecursingInfinitelyError_Type; |
| |
| static int |
| recurse_infinitely_error_init(PyObject *self, PyObject *args, PyObject *kwds) |
| { |
| PyObject *type = (PyObject *)&PyRecursingInfinitelyError_Type; |
| |
| /* Instantiating this exception starts infinite recursion. */ |
| Py_INCREF(type); |
| PyErr_SetObject(type, NULL); |
| return -1; |
| } |
| |
| static PyTypeObject PyRecursingInfinitelyError_Type = { |
| .tp_name = "RecursingInfinitelyError", |
| .tp_basicsize = sizeof(PyBaseExceptionObject), |
| .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |
| .tp_doc = PyDoc_STR("Instantiating this exception starts infinite recursion."), |
| .tp_init = (initproc)recurse_infinitely_error_init, |
| }; |
| |
| static PyMethodDef test_methods[] = { |
| {"err_restore", err_restore, METH_VARARGS}, |
| {"err_set_raised", err_set_raised, METH_O}, |
| {"exception_print", exception_print, METH_VARARGS}, |
| {"fatal_error", test_fatal_error, METH_VARARGS, |
| PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")}, |
| {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), |
| METH_VARARGS | METH_KEYWORDS}, |
| {"exc_set_object", exc_set_object, METH_VARARGS}, |
| {"raise_exception", raise_exception, METH_VARARGS}, |
| {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, |
| {"set_exc_info", test_set_exc_info, METH_VARARGS}, |
| {"set_exception", test_set_exception, METH_O}, |
| {"traceback_print", traceback_print, METH_VARARGS}, |
| {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS}, |
| {NULL}, |
| }; |
| |
| int |
| _PyTestCapi_Init_Exceptions(PyObject *mod) |
| { |
| PyRecursingInfinitelyError_Type.tp_base = (PyTypeObject *)PyExc_Exception; |
| if (PyType_Ready(&PyRecursingInfinitelyError_Type) < 0) { |
| return -1; |
| } |
| if (PyModule_AddObjectRef(mod, "RecursingInfinitelyError", |
| (PyObject *)&PyRecursingInfinitelyError_Type) < 0) |
| { |
| return -1; |
| } |
| |
| if (PyModule_AddFunctions(mod, test_methods) < 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |