@@ -1173,6 +1173,143 @@ test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
1173
1173
}
1174
1174
1175
1175
1176
+ /*
1177
+ * Small helper to import abc.ABC and ctypes.Array for testing. Both
1178
+ * are (incompatible) MetaClass instances. If Array is NULL it is not filled.
1179
+ */
1180
+ static int
1181
+ import_abc_and_array (PyObject * * ABC , PyObject * * Array )
1182
+ {
1183
+ PyObject * abc_mod = PyImport_ImportModule ("abc" );
1184
+ if (abc_mod == NULL ) {
1185
+ return -1 ;
1186
+ }
1187
+ * ABC = PyObject_GetAttrString (abc_mod , "ABC" );
1188
+ Py_DECREF (abc_mod );
1189
+ if (* ABC == NULL ) {
1190
+ return -1 ;
1191
+ }
1192
+ if (Array == NULL ) {
1193
+ return 0 ;
1194
+ }
1195
+
1196
+ PyObject * ctypes_mod = PyImport_ImportModule ("ctypes" );
1197
+ if (ctypes_mod == NULL ) {
1198
+ Py_CLEAR (* ABC );
1199
+ return -1 ;
1200
+ }
1201
+ * Array = PyObject_GetAttrString (ctypes_mod , "Array" );
1202
+ Py_DECREF (ctypes_mod );
1203
+ if (* Array == NULL ) {
1204
+ Py_CLEAR (* ABC );
1205
+ return -1 ;
1206
+ }
1207
+ return 0 ;
1208
+ }
1209
+
1210
+
1211
+ static PyType_Slot MinimalType_slots [] = {
1212
+ {0 , 0 },
1213
+ };
1214
+
1215
+ static PyType_Spec MinimalType_spec = {
1216
+ "_testcapi.MinimalSpecType" ,
1217
+ 0 ,
1218
+ 0 ,
1219
+ Py_TPFLAGS_DEFAULT ,
1220
+ MinimalType_slots
1221
+ };
1222
+
1223
+
1224
+ static PyObject *
1225
+ test_from_spec_metatype_inheritance (PyObject * self , PyObject * Py_UNUSED (ignored ))
1226
+ {
1227
+ /* Get two (incompatible) MetaTypes */
1228
+ PyObject * ABC ;
1229
+ if (import_abc_and_array (& ABC , NULL ) < 0 ) {
1230
+ return NULL ;
1231
+ }
1232
+
1233
+ PyObject * bases = PyTuple_Pack (1 , ABC );
1234
+ if (bases == NULL ) {
1235
+ Py_DECREF (ABC );
1236
+ return NULL ;
1237
+ }
1238
+ PyObject * new = PyType_FromSpecWithBases (& MinimalType_spec , bases );
1239
+ Py_DECREF (bases );
1240
+ if (new == NULL ) {
1241
+ Py_DECREF (ABC );
1242
+ return NULL ;
1243
+ }
1244
+ if (Py_TYPE (new ) != Py_TYPE (ABC )) {
1245
+ PyErr_SetString (PyExc_AssertionError ,
1246
+ "MetaType appears not correctly inherited from ABC!" );
1247
+ Py_DECREF (ABC );
1248
+ Py_DECREF (new );
1249
+ return NULL ;
1250
+ }
1251
+ Py_DECREF (ABC );
1252
+ Py_DECREF (new );
1253
+ Py_RETURN_NONE ;
1254
+ }
1255
+
1256
+
1257
+ static PyObject *
1258
+ test_from_spec_invalid_metatype_inheritance (PyObject * self , PyObject * Py_UNUSED (ignored ))
1259
+ {
1260
+ /* Get two (incompatible) MetaTypes */
1261
+ PyObject * ABC , * Array ;
1262
+
1263
+ if (import_abc_and_array (& ABC , & Array ) < 0 ) {
1264
+ return NULL ;
1265
+ }
1266
+
1267
+ PyObject * bases = PyTuple_Pack (2 , ABC , Array );
1268
+ Py_DECREF (ABC );
1269
+ Py_DECREF (Array );
1270
+ if (bases == NULL ) {
1271
+ return NULL ;
1272
+ }
1273
+ /*
1274
+ * The following should raise a TypeError due to a MetaClass conflict.
1275
+ */
1276
+ PyObject * new = PyType_FromSpecWithBases (& MinimalType_spec , bases );
1277
+ Py_DECREF (bases );
1278
+ if (new != NULL ) {
1279
+ Py_DECREF (new );
1280
+ PyErr_SetString (PyExc_AssertionError ,
1281
+ "MetaType conflict not recognized by PyType_FromSpecWithBases" );
1282
+ return NULL ;
1283
+ }
1284
+ if (PyErr_ExceptionMatches (PyExc_TypeError )) {
1285
+ PyObject * type , * value , * traceback , * meta_error_string ;
1286
+
1287
+ PyErr_Fetch (& type , & value , & traceback );
1288
+ Py_DECREF (type );
1289
+ Py_XDECREF (traceback );
1290
+
1291
+ meta_error_string = PyUnicode_FromString ("metaclass conflict:" );
1292
+ if (meta_error_string == NULL ) {
1293
+ Py_DECREF (value );
1294
+ return NULL ;
1295
+ }
1296
+ int res = PyUnicode_Contains (value , meta_error_string );
1297
+ Py_DECREF (value );
1298
+ Py_DECREF (meta_error_string );
1299
+ if (res < 0 ) {
1300
+ return NULL ;
1301
+ }
1302
+ if (res == 0 ) {
1303
+ PyErr_SetString (PyExc_AssertionError ,
1304
+ "TypeError did not inlclude expected message." );
1305
+ return NULL ;
1306
+ }
1307
+ Py_RETURN_NONE ;
1308
+ }
1309
+ return NULL ;
1310
+ }
1311
+
1312
+
1176
1313
static PyObject *
1177
1314
test_get_type_qualname (PyObject * self , PyObject * Py_UNUSED (ignored ))
1178
1315
{
@@ -5722,6 +5859,11 @@ static PyMethodDef TestMethods[] = {
5722
5859
{"get_args" , get_args , METH_VARARGS },
5723
5860
{"test_get_statictype_slots" , test_get_statictype_slots , METH_NOARGS },
5724
5861
{"test_get_type_name" , test_get_type_name , METH_NOARGS },
5862
+ {"test_from_spec_metatype_inheritance" , test_from_spec_metatype_inheritance ,
5863
+ METH_NOARGS },
5864
+ {"test_from_spec_invalid_metatype_inheritance" ,
5865
+ test_from_spec_invalid_metatype_inheritance ,
5866
+ METH_NOARGS },
5725
5867
{"test_get_type_qualname" , test_get_type_qualname , METH_NOARGS },
5726
5868
{"get_kwargs" , (PyCFunction )(void (* )(void ))get_kwargs ,
5727
5869
METH_VARARGS |METH_KEYWORDS },
0 commit comments