diff Python/bltinmodule.c @ 73062:c72063032a7a

Merge issue 1294232 patch from 3.2
author Nick Coghlan <ncoghlan@gmail.com>
date Sun, 23 Oct 2011 22:36:42 +1000
parents 7109f31300fb c2a89b509be4
children b9bb9340eb0c
line wrap: on
line diff
--- a/Python/bltinmodule.c	Sat Oct 22 23:41:52 2011 +0200
+++ b/Python/bltinmodule.c	Sun Oct 23 22:36:42 2011 +1000
@@ -38,9 +38,10 @@
 static PyObject *
 builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    PyObject *func, *name, *bases, *mkw, *meta, *prep, *ns, *cell;
+    PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns, *cell;
     PyObject *cls = NULL;
-    Py_ssize_t nargs;
+    Py_ssize_t nargs, nbases;
+    int isclass;
     _Py_IDENTIFIER(__prepare__);
 
     assert(args != NULL);
@@ -85,17 +86,43 @@
                 Py_DECREF(bases);
                 return NULL;
             }
+            /* metaclass is explicitly given, check if it's indeed a class */
+            isclass = PyType_Check(meta);
         }
     }
     if (meta == NULL) {
-        if (PyTuple_GET_SIZE(bases) == 0)
+        /* if there are no bases, use type: */
+        if (PyTuple_GET_SIZE(bases) == 0) {
             meta = (PyObject *) (&PyType_Type);
+        }
+        /* else get the type of the first base */
         else {
             PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
             meta = (PyObject *) (base0->ob_type);
         }
         Py_INCREF(meta);
+        isclass = 1;  /* meta is really a class */
     }
+
+    if (isclass) {
+        /* meta is really a class, so check for a more derived
+           metaclass, or possible metaclass conflicts: */
+        winner = (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)meta,
+                                                        bases);
+        if (winner == NULL) {
+            Py_DECREF(meta);
+            Py_XDECREF(mkw);
+            Py_DECREF(bases);
+            return NULL;
+        }
+        if (winner != meta) {
+            Py_DECREF(meta);
+            meta = winner;
+            Py_INCREF(meta);
+        }
+    }
+    /* else: meta is not a class, so we cannot do the metaclass
+       calculation, so we will use the explicitly given object as it is */
     prep = _PyObject_GetAttrId(meta, &PyId___prepare__);
     if (prep == NULL) {
         if (PyErr_ExceptionMatches(PyExc_AttributeError)) {