// Forward declarations
static struct PyModuleDef _testcapimodule;
-static PyObject *TestError; /* set to exception object in init */
+// Module state
+typedef struct {
+ PyObject *error; // _testcapi.error object
+} testcapistate_t;
+
+static testcapistate_t*
+get_testcapi_state(PyObject *module)
+{
+ void *state = PyModule_GetState(module);
+ assert(state != NULL);
+ return (testcapistate_t *)state;
+}
-/* Raise TestError with test_name + ": " + msg, and return NULL. */
+static PyObject *
+get_testerror(PyObject *self) {
+ testcapistate_t *state = get_testcapi_state((PyObject *)Py_TYPE(self));
+ return state->error;
+}
+
+/* Raise _testcapi.error with test_name + ": " + msg, and return NULL. */
static PyObject *
-raiseTestError(const char* test_name, const char* msg)
+raiseTestError(PyObject *self, const char* test_name, const char* msg)
{
- PyErr_Format(TestError, "%s: %s", test_name, msg);
+ PyErr_Format(get_testerror(self), "%s: %s", test_name, msg);
return NULL;
}
platforms have these hardcoded. Better safe than sorry.
*/
static PyObject*
-sizeof_error(const char* fatname, const char* typname,
+sizeof_error(PyObject *self, const char* fatname, const char* typname,
int expected, int got)
{
- PyErr_Format(TestError,
+ PyErr_Format(get_testerror(self),
"%s #define == %d but sizeof(%s) == %d",
fatname, expected, typname, got);
return (PyObject*)NULL;
{
#define CHECK_SIZEOF(FATNAME, TYPE) \
if (FATNAME != sizeof(TYPE)) \
- return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE))
+ return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE))
CHECK_SIZEOF(SIZEOF_SHORT, short);
CHECK_SIZEOF(SIZEOF_INT, int);
#endif
#define CHECK_SIZEOF(TYPE, EXPECTED) \
if (EXPECTED != sizeof(TYPE)) { \
- PyErr_Format(TestError, \
+ PyErr_Format(get_testerror(self), \
"sizeof(%s) = %u instead of %u", \
#TYPE, sizeof(TYPE), EXPECTED); \
return (PyObject*)NULL; \
#define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0)
#define CHECK_SIGNNESS(TYPE, SIGNED) \
if (IS_SIGNED(TYPE) != SIGNED) { \
- PyErr_Format(TestError, \
+ PyErr_Format(get_testerror(self), \
"%s signness is, instead of %i", \
#TYPE, IS_SIGNED(TYPE), SIGNED); \
return (PyObject*)NULL; \
for (i = 0; i < NLIST; ++i) {
PyObject* anint = PyList_GET_ITEM(list, i);
if (PyLong_AS_LONG(anint) != NLIST-1-i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_list_api: reverse screwed up");
Py_DECREF(list);
return (PyObject*)NULL;
}
static int
-test_dict_inner(int count)
+test_dict_inner(PyObject *self, int count)
{
Py_ssize_t pos = 0, iterations = 0;
int i;
if (iterations != count) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_dict_iteration: dict iteration went wrong ");
return -1;
} else {
int i;
for (i = 0; i < 200; i++) {
- if (test_dict_inner(i) < 0) {
+ if (test_dict_inner(self, i) < 0) {
return NULL;
}
}
if (obj == NULL) {
PyErr_Clear();
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: failed to create object");
return NULL;
}
if (type->tp_dict != NULL) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: type initialised too soon");
Py_DECREF(obj);
return NULL;
if ((hash == -1) && PyErr_Occurred()) {
PyErr_Clear();
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: could not hash object");
Py_DECREF(obj);
return NULL;
if (type->tp_dict == NULL) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: type not initialised by hash()");
Py_DECREF(obj);
return NULL;
if (type->tp_hash != PyType_Type.tp_hash) {
PyErr_SetString(
- TestError,
+ get_testerror(self),
"test_lazy_hash_inheritance: unexpected hash function");
Py_DECREF(obj);
return NULL;
}
static int
-test_buildvalue_N_error(const char *fmt)
+test_buildvalue_N_error(PyObject *self, const char *fmt)
{
PyObject *arg, *res;
}
Py_DECREF(res);
if (Py_REFCNT(arg) != 1) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in successful "
"Py_BuildValue(\"%s\")", fmt);
return -1;
Py_INCREF(arg);
res = Py_BuildValue(fmt, raise_error, NULL, arg);
if (res != NULL || !PyErr_Occurred()) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"Py_BuildValue(\"%s\") didn't complain", fmt);
return -1;
}
PyErr_Clear();
if (Py_REFCNT(arg) != 1) {
- PyErr_Format(TestError, "test_buildvalue_N: "
+ PyErr_Format(get_testerror(self), "test_buildvalue_N: "
"arg was not decrefed in failed "
"Py_BuildValue(\"%s\")", fmt);
return -1;
return NULL;
}
if (res != arg) {
- return raiseTestError("test_buildvalue_N",
+ return raiseTestError(self, "test_buildvalue_N",
"Py_BuildValue(\"N\") returned wrong result");
}
if (Py_REFCNT(arg) != 2) {
- return raiseTestError("test_buildvalue_N",
+ return raiseTestError(self, "test_buildvalue_N",
"arg was not decrefed in Py_BuildValue(\"N\")");
}
Py_DECREF(res);
Py_DECREF(arg);
- if (test_buildvalue_N_error("O&N") < 0)
+ if (test_buildvalue_N_error(self, "O&N") < 0)
return NULL;
- if (test_buildvalue_N_error("(O&N)") < 0)
+ if (test_buildvalue_N_error(self, "(O&N)") < 0)
return NULL;
- if (test_buildvalue_N_error("[O&N]") < 0)
+ if (test_buildvalue_N_error(self, "[O&N]") < 0)
return NULL;
- if (test_buildvalue_N_error("{O&N}") < 0)
+ if (test_buildvalue_N_error(self, "{O&N}") < 0)
return NULL;
- if (test_buildvalue_N_error("{()O&(())N}") < 0)
+ if (test_buildvalue_N_error(self, "{()O&(())N}") < 0)
return NULL;
Py_RETURN_NONE;
Py_RETURN_NONE;
fail:
- return raiseTestError("test_string_to_double", msg);
+ return raiseTestError(self, "test_string_to_double", msg);
#undef CHECK_STRING
#undef CHECK_INVALID
}
exit:
if (error) {
- return raiseTestError("test_capsule", error);
+ return raiseTestError(self, "test_capsule", error);
}
Py_RETURN_NONE;
#undef FAIL
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (ptr[2*i] != i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
ptr = view.buf;
for (i = 0; i < 5; i++) {
if (*(ptr-2*i) != i) {
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_from_contiguous: incorrect result");
return NULL;
}
Py_RETURN_NONE;
error:
- PyErr_SetString(TestError,
+ PyErr_SetString(get_testerror(self),
"test_pep3118_obsolete_write_locks: failure");
return NULL;
}
{
Py_tss_t tss_key = Py_tss_NEEDS_INIT;
if (PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"creation time");
}
return NULL;
}
if (!PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_create succeeded, "
"but with TSS key in an uninitialized state");
}
if (PyThread_tss_create(&tss_key) != 0) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_create unsuccessful with "
"an already initialized key");
}
#define CHECK_TSS_API(expr) \
(void)(expr); \
if (!PyThread_tss_is_created(&tss_key)) { \
- return raiseTestError("test_pythread_tss_key_state", \
+ return raiseTestError(self, "test_pythread_tss_key_state", \
"TSS key initialization state was not " \
"preserved after calling " #expr); }
CHECK_TSS_API(PyThread_tss_set(&tss_key, NULL));
#undef CHECK_TSS_API
PyThread_tss_delete(&tss_key);
if (PyThread_tss_is_created(&tss_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"PyThread_tss_delete called, but did not "
"set the key state to uninitialized");
}
return NULL;
}
if (PyThread_tss_is_created(ptr_key)) {
- return raiseTestError("test_pythread_tss_key_state",
+ return raiseTestError(self, "test_pythread_tss_key_state",
"TSS key not in an uninitialized state at "
"allocation time");
}
static struct PyModuleDef _testcapimodule = {
PyModuleDef_HEAD_INIT,
- "_testcapi",
- NULL,
- -1,
- TestMethods,
- NULL,
- NULL,
- NULL,
- NULL
+ .m_name = "_testcapi",
+ .m_size = sizeof(testcapistate_t),
+ .m_methods = TestMethods,
};
/* Per PEP 489, this module will not be converted to multi-phase initialization
PyModule_AddIntConstant(m, "the_number_three", 3);
PyModule_AddIntMacro(m, Py_C_RECURSION_LIMIT);
- TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
- Py_INCREF(TestError);
- PyModule_AddObject(m, "error", TestError);
+ testcapistate_t *state = get_testcapi_state(m);
+ state->error = PyErr_NewException("_testcapi.error", NULL, NULL);
+ Py_INCREF(state->error);
+ PyModule_AddObject(m, "error", state->error);
if (PyType_Ready(&ContainerNoGC_type) < 0) {
return NULL;