summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_capi/test_exceptions.py145
-rw-r--r--Lib/test/test_capi/test_misc.py131
-rw-r--r--Modules/Setup.stdlib.in2
-rw-r--r--Modules/_testcapi/exceptions.c277
-rw-r--r--Modules/_testcapi/parts.h1
-rw-r--r--Modules/_testcapimodule.c290
-rw-r--r--PCbuild/_testcapi.vcxproj1
-rw-r--r--PCbuild/_testcapi.vcxproj.filters3
8 files changed, 434 insertions, 416 deletions
diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py
new file mode 100644
index 0000000..b543a1a
--- /dev/null
+++ b/Lib/test/test_capi/test_exceptions.py
@@ -0,0 +1,145 @@
+import re
+import sys
+import unittest
+
+from test import support
+from test.support import import_helper
+from test.support.script_helper import assert_python_failure
+
+from .test_misc import decode_stderr
+
+# Skip this test if the _testcapi module isn't available.
+_testcapi = import_helper.import_module('_testcapi')
+
+class Test_Exceptions(unittest.TestCase):
+
+ def test_exception(self):
+ raised_exception = ValueError("5")
+ new_exc = TypeError("TEST")
+ try:
+ raise raised_exception
+ except ValueError as e:
+ orig_sys_exception = sys.exception()
+ orig_exception = _testcapi.set_exception(new_exc)
+ new_sys_exception = sys.exception()
+ new_exception = _testcapi.set_exception(orig_exception)
+ reset_sys_exception = sys.exception()
+
+ self.assertEqual(orig_exception, e)
+
+ self.assertEqual(orig_exception, raised_exception)
+ self.assertEqual(orig_sys_exception, orig_exception)
+ self.assertEqual(reset_sys_exception, orig_exception)
+ self.assertEqual(new_exception, new_exc)
+ self.assertEqual(new_sys_exception, new_exception)
+ else:
+ self.fail("Exception not raised")
+
+ def test_exc_info(self):
+ raised_exception = ValueError("5")
+ new_exc = TypeError("TEST")
+ try:
+ raise raised_exception
+ except ValueError as e:
+ tb = e.__traceback__
+ orig_sys_exc_info = sys.exc_info()
+ orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
+ new_sys_exc_info = sys.exc_info()
+ new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
+ reset_sys_exc_info = sys.exc_info()
+
+ self.assertEqual(orig_exc_info[1], e)
+
+ self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
+ self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
+ self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
+ else:
+ self.assertTrue(False)
+
+
+class Test_FatalError(unittest.TestCase):
+
+ def check_fatal_error(self, code, expected, not_expected=()):
+ with support.SuppressCrashReport():
+ rc, out, err = assert_python_failure('-sSI', '-c', code)
+
+ err = decode_stderr(err)
+ self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n',
+ err)
+
+ match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$',
+ err, re.MULTILINE)
+ if not match:
+ self.fail(f"Cannot find 'Extension modules:' in {err!r}")
+ modules = set(match.group(1).strip().split(', '))
+ total = int(match.group(2))
+
+ for name in expected:
+ self.assertIn(name, modules)
+ for name in not_expected:
+ self.assertNotIn(name, modules)
+ self.assertEqual(len(modules), total)
+
+ @support.requires_subprocess()
+ def test_fatal_error(self):
+ # By default, stdlib extension modules are ignored,
+ # but not test modules.
+ expected = ('_testcapi',)
+ not_expected = ('sys',)
+ code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
+ self.check_fatal_error(code, expected, not_expected)
+
+ # Mark _testcapi as stdlib module, but not sys
+ expected = ('sys',)
+ not_expected = ('_testcapi',)
+ code = """if True:
+ import _testcapi, sys
+ sys.stdlib_module_names = frozenset({"_testcapi"})
+ _testcapi.fatal_error(b"MESSAGE")
+ """
+ self.check_fatal_error(code, expected)
+
+
+class Test_ErrSetAndRestore(unittest.TestCase):
+
+ def test_err_set_raised(self):
+ with self.assertRaises(ValueError):
+ _testcapi.err_set_raised(ValueError())
+ v = ValueError()
+ try:
+ _testcapi.err_set_raised(v)
+ except ValueError as ex:
+ self.assertIs(v, ex)
+
+ def test_err_restore(self):
+ with self.assertRaises(ValueError):
+ _testcapi.err_restore(ValueError)
+ with self.assertRaises(ValueError):
+ _testcapi.err_restore(ValueError, 1)
+ with self.assertRaises(ValueError):
+ _testcapi.err_restore(ValueError, 1, None)
+ with self.assertRaises(ValueError):
+ _testcapi.err_restore(ValueError, ValueError())
+ try:
+ _testcapi.err_restore(KeyError, "hi")
+ except KeyError as k:
+ self.assertEqual("hi", k.args[0])
+ try:
+ 1/0
+ except Exception as e:
+ tb = e.__traceback__
+ with self.assertRaises(ValueError):
+ _testcapi.err_restore(ValueError, 1, tb)
+ with self.assertRaises(TypeError):
+ _testcapi.err_restore(ValueError, 1, 0)
+ try:
+ _testcapi.err_restore(ValueError, 1, tb)
+ except ValueError as v:
+ self.assertEqual(1, v.args[0])
+ self.assertIs(tb, v.__traceback__.tb_next)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index f4569fb..c34ee57 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -8,7 +8,6 @@ import importlib.util
import os
import pickle
import random
-import re
import subprocess
import sys
import textwrap
@@ -91,51 +90,6 @@ class CAPITest(unittest.TestCase):
def test_memoryview_from_NULL_pointer(self):
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)
- def test_exception(self):
- raised_exception = ValueError("5")
- new_exc = TypeError("TEST")
- try:
- raise raised_exception
- except ValueError as e:
- orig_sys_exception = sys.exception()
- orig_exception = _testcapi.set_exception(new_exc)
- new_sys_exception = sys.exception()
- new_exception = _testcapi.set_exception(orig_exception)
- reset_sys_exception = sys.exception()
-
- self.assertEqual(orig_exception, e)
-
- self.assertEqual(orig_exception, raised_exception)
- self.assertEqual(orig_sys_exception, orig_exception)
- self.assertEqual(reset_sys_exception, orig_exception)
- self.assertEqual(new_exception, new_exc)
- self.assertEqual(new_sys_exception, new_exception)
- else:
- self.fail("Exception not raised")
-
- def test_exc_info(self):
- raised_exception = ValueError("5")
- new_exc = TypeError("TEST")
- try:
- raise raised_exception
- except ValueError as e:
- tb = e.__traceback__
- orig_sys_exc_info = sys.exc_info()
- orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
- new_sys_exc_info = sys.exc_info()
- new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
- reset_sys_exc_info = sys.exc_info()
-
- self.assertEqual(orig_exc_info[1], e)
-
- self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
- self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
- self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
- self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
- self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
- else:
- self.assertTrue(False)
-
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
def test_seq_bytes_to_charp_array(self):
# Issue #15732: crash in _PySequence_BytesToCharpArray()
@@ -837,46 +791,6 @@ class CAPITest(unittest.TestCase):
self.assertRaises(TypeError, pynumber_tobase, '123', 10)
self.assertRaises(SystemError, pynumber_tobase, 123, 0)
- def check_fatal_error(self, code, expected, not_expected=()):
- with support.SuppressCrashReport():
- rc, out, err = assert_python_failure('-sSI', '-c', code)
-
- err = decode_stderr(err)
- self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n',
- err)
-
- match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$',
- err, re.MULTILINE)
- if not match:
- self.fail(f"Cannot find 'Extension modules:' in {err!r}")
- modules = set(match.group(1).strip().split(', '))
- total = int(match.group(2))
-
- for name in expected:
- self.assertIn(name, modules)
- for name in not_expected:
- self.assertNotIn(name, modules)
- self.assertEqual(len(modules), total)
-
- @support.requires_subprocess()
- def test_fatal_error(self):
- # By default, stdlib extension modules are ignored,
- # but not test modules.
- expected = ('_testcapi',)
- not_expected = ('sys',)
- code = 'import _testcapi, sys; _testcapi.fatal_error(b"MESSAGE")'
- self.check_fatal_error(code, expected, not_expected)
-
- # Mark _testcapi as stdlib module, but not sys
- expected = ('sys',)
- not_expected = ('_testcapi',)
- code = textwrap.dedent('''
- import _testcapi, sys
- sys.stdlib_module_names = frozenset({"_testcapi"})
- _testcapi.fatal_error(b"MESSAGE")
- ''')
- self.check_fatal_error(code, expected)
-
def test_pyobject_repr_from_null(self):
s = _testcapi.pyobject_repr_from_null()
self.assertEqual(s, '<NULL>')
@@ -1214,9 +1128,9 @@ class TestPendingCalls(unittest.TestCase):
self.pendingcalls_wait(l, n)
def test_gen_get_code(self):
- def genf(): yield
- gen = genf()
- self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code)
+ def genf(): yield
+ gen = genf()
+ self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code)
class SubinterpreterTest(unittest.TestCase):
@@ -1641,44 +1555,5 @@ class Test_Pep523API(unittest.TestCase):
self.do_test(func2)
-class Test_ErrSetAndRestore(unittest.TestCase):
-
- def test_err_set_raised(self):
- with self.assertRaises(ValueError):
- _testcapi.err_set_raised(ValueError())
- v = ValueError()
- try:
- _testcapi.err_set_raised(v)
- except ValueError as ex:
- self.assertIs(v, ex)
-
- def test_err_restore(self):
- with self.assertRaises(ValueError):
- _testcapi.err_restore(ValueError)
- with self.assertRaises(ValueError):
- _testcapi.err_restore(ValueError, 1)
- with self.assertRaises(ValueError):
- _testcapi.err_restore(ValueError, 1, None)
- with self.assertRaises(ValueError):
- _testcapi.err_restore(ValueError, ValueError())
- try:
- _testcapi.err_restore(KeyError, "hi")
- except KeyError as k:
- self.assertEqual("hi", k.args[0])
- try:
- 1/0
- except Exception as e:
- tb = e.__traceback__
- with self.assertRaises(ValueError):
- _testcapi.err_restore(ValueError, 1, tb)
- with self.assertRaises(TypeError):
- _testcapi.err_restore(ValueError, 1, 0)
- try:
- _testcapi.err_restore(ValueError, 1, tb)
- except ValueError as v:
- self.assertEqual(1, v.args[0])
- self.assertIs(tb, v.__traceback__.tb_next)
-
-
if __name__ == "__main__":
unittest.main()
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index d33cd82..7551e5b 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -169,7 +169,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
# Some testing modules MUST be built as shared libraries.
diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c
new file mode 100644
index 0000000..43b88cc
--- /dev/null
+++ b/Modules/_testcapi/exceptions.c
@@ -0,0 +1,277 @@
+#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 *
+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},
+ {"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;
+}
diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h
index 7ba3c4e..1689f18 100644
--- a/Modules/_testcapi/parts.h
+++ b/Modules/_testcapi/parts.h
@@ -36,6 +36,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module);
int _PyTestCapi_Init_Long(PyObject *module);
int _PyTestCapi_Init_Float(PyObject *module);
int _PyTestCapi_Init_Structmember(PyObject *module);
+int _PyTestCapi_Init_Exceptions(PyObject *module);
#ifdef LIMITED_API_AVAILABLE
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index e2237d2..6bb4242 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -721,33 +721,6 @@ pyobject_bytes_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
}
static PyObject *
-raise_exception(PyObject *self, PyObject *args)
-{
- PyObject *exc;
- PyObject *exc_args, *v;
- int num_args, i;
-
- if (!PyArg_ParseTuple(args, "Oi:raise_exception",
- &exc, &num_args))
- return NULL;
-
- exc_args = PyTuple_New(num_args);
- if (exc_args == NULL)
- return NULL;
- for (i = 0; i < num_args; ++i) {
- 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;
-}
-
-static PyObject *
set_errno(PyObject *self, PyObject *args)
{
int new_errno;
@@ -759,40 +732,6 @@ set_errno(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-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_set_exc_info(PyObject *self, PyObject *args)
-{
- PyObject *orig_exc;
- 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);
-
- 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;
-}
-
/* test_thread_state spawns a thread of its own, and that thread releases
* `thread_done` when it's finished. The driver code has to know when the
* thread finishes, because the thread uses a PyObject (the callable) that
@@ -1272,57 +1211,6 @@ profile_int(PyObject *self, PyObject* args)
}
#endif
-/* To test the format of tracebacks as printed out. */
-static PyObject *
-traceback_print(PyObject *self, PyObject *args)
-{
- PyObject *file;
- PyObject *traceback;
- int result;
-
- if (!PyArg_ParseTuple(args, "OO:traceback_print",
- &traceback, &file))
- return NULL;
-
- result = PyTraceBack_Print(traceback, file);
- if (result < 0)
- return NULL;
- Py_RETURN_NONE;
-}
-
-/* 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;
-}
-
-
-
-
-/* reliably raise a MemoryError */
-static PyObject *
-raise_memoryerror(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
- PyErr_NoMemory();
- return NULL;
-}
-
/* Issue 6012 */
static PyObject *str1, *str2;
static int
@@ -1368,26 +1256,6 @@ code_newempty(PyObject *self, PyObject *args)
return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno);
}
-/* 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 *
make_memoryview_from_NULL_pointer(PyObject *self, PyObject *Py_UNUSED(ignored))
{
@@ -2491,31 +2359,6 @@ negative_refcount(PyObject *self, PyObject *Py_UNUSED(args))
#endif
-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;
-}
-
-
static PyObject *
sequence_getitem(PyObject *self, PyObject *args)
{
@@ -2874,25 +2717,6 @@ test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored))
}
-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;
-}
-
// type->tp_version_tag
static PyObject *
type_get_version(PyObject *self, PyObject *type)
@@ -3492,46 +3316,9 @@ function_set_kw_defaults(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-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;
-}
-
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
static PyMethodDef TestMethods[] = {
- {"raise_exception", raise_exception, METH_VARARGS},
- {"raise_memoryerror", raise_memoryerror, METH_NOARGS},
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
{"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS},
@@ -3574,15 +3361,9 @@ static PyMethodDef TestMethods[] = {
#ifdef HAVE_GETTIMEOFDAY
{"profile_int", profile_int, METH_NOARGS},
#endif
- {"traceback_print", traceback_print, METH_VARARGS},
- {"exception_print", exception_print, METH_VARARGS},
- {"set_exception", test_set_exception, METH_O},
- {"set_exc_info", test_set_exc_info, METH_VARARGS},
{"argparsing", argparsing, METH_VARARGS},
{"code_newempty", code_newempty, METH_VARARGS},
{"eval_code_ex", eval_eval_code_ex, METH_VARARGS},
- {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc),
- METH_VARARGS | METH_KEYWORDS},
{"make_memoryview_from_NULL_pointer", make_memoryview_from_NULL_pointer,
METH_NOARGS},
{"crash_no_current_thread", crash_no_current_thread, METH_NOARGS},
@@ -3633,7 +3414,6 @@ static PyMethodDef TestMethods[] = {
#ifdef Py_REF_DEBUG
{"negative_refcount", negative_refcount, METH_NOARGS},
#endif
- {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS},
{"sequence_getitem", sequence_getitem, METH_VARARGS},
{"sequence_setitem", sequence_setitem, METH_VARARGS},
{"sequence_delitem", sequence_delitem, METH_VARARGS},
@@ -3653,8 +3433,6 @@ static PyMethodDef TestMethods[] = {
{"test_refcount_funcs", test_refcount_funcs, METH_NOARGS},
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
- {"fatal_error", test_fatal_error, METH_VARARGS,
- PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")},
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"frame_getlocals", frame_getlocals, METH_O, NULL},
@@ -3680,8 +3458,6 @@ static PyMethodDef TestMethods[] = {
{"function_set_defaults", function_set_defaults, METH_VARARGS, NULL},
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
- {"err_set_raised", err_set_raised, METH_O, NULL},
- {"err_restore", err_restore, METH_VARARGS, NULL},
{NULL, NULL} /* sentinel */
};
@@ -3902,61 +3678,6 @@ static PyTypeObject awaitType = {
};
-static int recurse_infinitely_error_init(PyObject *, PyObject *, PyObject *);
-
-static PyTypeObject PyRecursingInfinitelyError_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "RecursingInfinitelyError", /* tp_name */
- sizeof(PyBaseExceptionObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- PyDoc_STR("Instantiating this exception starts infinite recursion."), /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)recurse_infinitely_error_init, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-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;
-}
-
-
/* Test bpo-35983: create a subclass of "list" which checks that instances
* are not deallocated twice */
@@ -4283,14 +4004,6 @@ PyInit__testcapi(void)
Py_INCREF(&MethStatic_Type);
PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type);
- PyRecursingInfinitelyError_Type.tp_base = (PyTypeObject *)PyExc_Exception;
- if (PyType_Ready(&PyRecursingInfinitelyError_Type) < 0) {
- return NULL;
- }
- Py_INCREF(&PyRecursingInfinitelyError_Type);
- PyModule_AddObject(m, "RecursingInfinitelyError",
- (PyObject *)&PyRecursingInfinitelyError_Type);
-
PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX));
PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN));
PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX));
@@ -4368,6 +4081,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_Structmember(m) < 0) {
return NULL;
}
+ if (_PyTestCapi_Init_Exceptions(m) < 0) {
+ return NULL;
+ }
#ifndef LIMITED_API_AVAILABLE
PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);
diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj
index 58bf4e1..742eb3e 100644
--- a/PCbuild/_testcapi.vcxproj
+++ b/PCbuild/_testcapi.vcxproj
@@ -107,6 +107,7 @@
<ClCompile Include="..\Modules\_testcapi\float.c" />
<ClCompile Include="..\Modules\_testcapi\long.c" />
<ClCompile Include="..\Modules\_testcapi\structmember.c" />
+ <ClCompile Include="..\Modules\_testcapi\exceptions.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc" />
diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters
index 101c532..ab5afc1 100644
--- a/PCbuild/_testcapi.vcxproj.filters
+++ b/PCbuild/_testcapi.vcxproj.filters
@@ -51,6 +51,9 @@
<ClCompile Include="..\Modules\_testcapi\structmember.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Modules\_testcapi\exceptions.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc">