@@ -1208,6 +1208,161 @@ test_get_type_name(PyObject *self, PyObject *Py_UNUSED(ignored))
12081208}
12091209
12101210
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+
12111366static PyObject *
12121367simple_str (PyObject * self ) {
12131368 return PyUnicode_FromString ("<test>" );
@@ -5952,6 +6107,11 @@ static PyMethodDef TestMethods[] = {
59526107 {"test_get_type_name" , test_get_type_name , METH_NOARGS },
59536108 {"test_get_type_qualname" , test_get_type_qualname , METH_NOARGS },
59546109 {"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 },
59556115 {"get_kwargs" , _PyCFunction_CAST (get_kwargs ),
59566116 METH_VARARGS |METH_KEYWORDS },
59576117 {"getargs_tuple" , getargs_tuple , METH_VARARGS },
0 commit comments