@@ -1208,6 +1208,161 @@ test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
1208
1208
}
1209
1209
1210
1210
1211
+ static PyType_Slot empty_type_slots [] = {
1212
+ {0 , 0 },
1213
+ };
1214
+
1215
+ static PyType_Spec MinimalMetaclass_spec = {
1216
+ .name = "_testcapi.MinimalMetaclass" ,
1217
+ .basicsize = sizeof (PyHeapTypeObject ),
1218
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
1219
+ .slots = empty_type_slots ,
1220
+ };
1221
+
1222
+ static PyType_Spec MinimalType_spec = {
1223
+ .name = "_testcapi.MinimalSpecType" ,
1224
+ .basicsize = sizeof (PyObject ),
1225
+ .flags = Py_TPFLAGS_DEFAULT ,
1226
+ .slots = empty_type_slots ,
1227
+ };
1228
+
1229
+ static PyObject *
1230
+ test_from_spec_metatype_inheritance (PyObject * self , PyObject * Py_UNUSED (ignored ))
1231
+ {
1232
+ PyObject * metaclass = NULL ;
1233
+ PyObject * class = NULL ;
1234
+ PyObject * new = NULL ;
1235
+ PyObject * subclasses = NULL ;
1236
+ PyObject * result = NULL ;
1237
+ int r ;
1238
+
1239
+ metaclass = PyType_FromSpecWithBases (& MinimalMetaclass_spec , (PyObject * )& PyType_Type );
1240
+ if (metaclass == NULL ) {
1241
+ goto finally ;
1242
+ }
1243
+ class = PyObject_CallFunction (metaclass , "s(){}" , "TestClass" );
1244
+ if (class == NULL ) {
1245
+ goto finally ;
1246
+ }
1247
+
1248
+ new = PyType_FromSpecWithBases (& MinimalType_spec , class );
1249
+ if (new == NULL ) {
1250
+ goto finally ;
1251
+ }
1252
+ if (Py_TYPE (new ) != (PyTypeObject * )metaclass ) {
1253
+ PyErr_SetString (PyExc_AssertionError ,
1254
+ "Metaclass not set properly!" );
1255
+ goto finally ;
1256
+ }
1257
+
1258
+ /* Assert that __subclasses__ is updated */
1259
+ subclasses = PyObject_CallMethod (class , "__subclasses__" , "" );
1260
+ if (!subclasses ) {
1261
+ goto finally ;
1262
+ }
1263
+ r = PySequence_Contains (subclasses , new );
1264
+ if (r < 0 ) {
1265
+ goto finally ;
1266
+ }
1267
+ if (r == 0 ) {
1268
+ PyErr_SetString (PyExc_AssertionError ,
1269
+ "subclasses not set properly!" );
1270
+ goto finally ;
1271
+ }
1272
+
1273
+ result = Py_NewRef (Py_None );
1274
+
1275
+ finally :
1276
+ Py_XDECREF (metaclass );
1277
+ Py_XDECREF (class );
1278
+ Py_XDECREF (new );
1279
+ Py_XDECREF (subclasses );
1280
+ return result ;
1281
+ }
1282
+
1283
+
1284
+ static PyObject *
1285
+ test_from_spec_invalid_metatype_inheritance (PyObject * self , PyObject * Py_UNUSED (ignored ))
1286
+ {
1287
+ PyObject * metaclass_a = NULL ;
1288
+ PyObject * metaclass_b = NULL ;
1289
+ PyObject * class_a = NULL ;
1290
+ PyObject * class_b = NULL ;
1291
+ PyObject * bases = NULL ;
1292
+ PyObject * new = NULL ;
1293
+ PyObject * meta_error_string = NULL ;
1294
+ PyObject * exc_type = NULL ;
1295
+ PyObject * exc_value = NULL ;
1296
+ PyObject * exc_traceback = NULL ;
1297
+ PyObject * result = NULL ;
1298
+
1299
+ metaclass_a = PyType_FromSpecWithBases (& MinimalMetaclass_spec , (PyObject * )& PyType_Type );
1300
+ if (metaclass_a == NULL ) {
1301
+ goto finally ;
1302
+ }
1303
+ metaclass_b = PyType_FromSpecWithBases (& MinimalMetaclass_spec , (PyObject * )& PyType_Type );
1304
+ if (metaclass_b == NULL ) {
1305
+ goto finally ;
1306
+ }
1307
+ class_a = PyObject_CallFunction (metaclass_a , "s(){}" , "TestClassA" );
1308
+ if (class_a == NULL ) {
1309
+ goto finally ;
1310
+ }
1311
+
1312
+ class_b = PyObject_CallFunction (metaclass_b , "s(){}" , "TestClassB" );
1313
+ if (class_b == NULL ) {
1314
+ goto finally ;
1315
+ }
1316
+
1317
+ bases = PyTuple_Pack (2 , class_a , class_b );
1318
+ if (bases == NULL ) {
1319
+ goto finally ;
1320
+ }
1321
+
1322
+ /*
1323
+ * The following should raise a TypeError due to a MetaClass conflict.
1324
+ */
1325
+ new = PyType_FromSpecWithBases (& MinimalType_spec , bases );
1326
+ if (new != NULL ) {
1327
+ PyErr_SetString (PyExc_AssertionError ,
1328
+ "MetaType conflict not recognized by PyType_FromSpecWithBases" );
1329
+ goto finally ;
1330
+ }
1331
+
1332
+ // Assert that the correct exception was raised
1333
+ if (PyErr_ExceptionMatches (PyExc_TypeError )) {
1334
+ PyErr_Fetch (& exc_type , & exc_value , & exc_traceback );
1335
+
1336
+ meta_error_string = PyUnicode_FromString ("metaclass conflict:" );
1337
+ if (meta_error_string == NULL ) {
1338
+ goto finally ;
1339
+ }
1340
+ int res = PyUnicode_Contains (exc_value , meta_error_string );
1341
+ if (res < 0 ) {
1342
+ goto finally ;
1343
+ }
1344
+ if (res == 0 ) {
1345
+ PyErr_SetString (PyExc_AssertionError ,
1346
+ "TypeError did not inlclude expected message." );
1347
+ goto finally ;
1348
+ }
1349
+ result = Py_NewRef (Py_None );
1350
+ }
1351
+ finally :
1352
+ Py_XDECREF (metaclass_a );
1353
+ Py_XDECREF (metaclass_b );
1354
+ Py_XDECREF (bases );
1355
+ Py_XDECREF (new );
1356
+ Py_XDECREF (meta_error_string );
1357
+ Py_XDECREF (exc_type );
1358
+ Py_XDECREF (exc_value );
1359
+ Py_XDECREF (exc_traceback );
1360
+ Py_XDECREF (class_a );
1361
+ Py_XDECREF (class_b );
1362
+ return result ;
1363
+ }
1364
+
1365
+
1211
1366
static PyObject *
1212
1367
simple_str (PyObject * self ) {
1213
1368
return PyUnicode_FromString ("<test>" );
@@ -5952,6 +6107,11 @@ static PyMethodDef TestMethods[] = {
5952
6107
{"test_get_type_name" , test_get_type_name , METH_NOARGS },
5953
6108
{"test_get_type_qualname" , test_get_type_qualname , METH_NOARGS },
5954
6109
{"test_type_from_ephemeral_spec" , test_type_from_ephemeral_spec , METH_NOARGS },
6110
+ {"test_from_spec_metatype_inheritance" , test_from_spec_metatype_inheritance ,
6111
+ METH_NOARGS },
6112
+ {"test_from_spec_invalid_metatype_inheritance" ,
6113
+ test_from_spec_invalid_metatype_inheritance ,
6114
+ METH_NOARGS },
5955
6115
{"get_kwargs" , _PyCFunction_CAST (get_kwargs ),
5956
6116
METH_VARARGS |METH_KEYWORDS },
5957
6117
{"getargs_tuple" , getargs_tuple , METH_VARARGS },
0 commit comments