mirror of
https://github.com/python/cpython.git
synced 2024-12-12 11:23:56 +08:00
317 lines
8.3 KiB
C
317 lines
8.3 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 *exc;
|
|
int legacy = 0;
|
|
|
|
if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) {
|
|
return NULL;
|
|
}
|
|
if (legacy) {
|
|
PyObject *tb = NULL;
|
|
if (PyExceptionInstance_Check(exc)) {
|
|
tb = PyException_GetTraceback(exc);
|
|
}
|
|
PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb);
|
|
Py_XDECREF(tb);
|
|
}
|
|
else {
|
|
PyErr_DisplayException(exc);
|
|
}
|
|
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;
|
|
}
|