cpython/Modules/_testcapi/exceptions.c

314 lines
8.1 KiB
C

#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 *
exc_set_object_fetch(PyObject *self, PyObject *args)
{
PyObject *exc;
PyObject *obj;
PyObject *type;
PyObject *value;
PyObject *tb;
if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) {
return NULL;
}
PyErr_SetObject(exc, obj);
PyErr_Fetch(&type, &value, &tb);
Py_XDECREF(type);
Py_XDECREF(tb);
return value;
}
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},
{"exc_set_object_fetch", exc_set_object_fetch, 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;
}