diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index db7a7741621979..67150a8d24cb12 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -133,6 +133,34 @@ def test_exc_info(self): else: self.assertTrue(False) + def test_set_object(self): + # new exception as obj is not an exception + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, 42) + self.assertEqual(e.exception.args, (42,)) + + # wraps the exception because unrelated types + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, TypeError(1,2,3)) + wrapped = e.exception.args[0] + self.assertIsInstance(wrapped, TypeError) + self.assertEqual(wrapped.args, (1, 2, 3)) + + # is superclass, so does not wrap + with self.assertRaises(PermissionError) as e: + _testcapi.exc_set_object(OSError, PermissionError(24)) + self.assertEqual(e.exception.args, (24,)) + + class Meta(type): + def __subclasscheck__(cls, sub): + 1/0 + + class Broken(Exception, metaclass=Meta): + pass + + with self.assertRaises(ZeroDivisionError) as e: + _testcapi.exc_set_object(Broken, Broken()) + @unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.') def test_seq_bytes_to_charp_array(self): # Issue #15732: crash in _PySequence_BytesToCharpArray() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 71501b97a8c51a..6a38cc17bcc7cb 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2523,6 +2523,20 @@ pyobject_bytes_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) return PyObject_Bytes(NULL); } +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) { @@ -6379,6 +6393,7 @@ static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*); static PyObject *gh_99240_clear_args(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { + {"exc_set_object", exc_set_object, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS},