summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/bltinmodule.c95
1 files changed, 92 insertions, 3 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 23d7aa4..a363211 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -37,6 +37,7 @@ _Py_IDENTIFIER(__builtins__);
_Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__prepare__);
_Py_IDENTIFIER(__round__);
+_Py_IDENTIFIER(__mro_entries__);
_Py_IDENTIFIER(encoding);
_Py_IDENTIFIER(errors);
_Py_IDENTIFIER(fileno);
@@ -49,12 +50,86 @@ _Py_IDENTIFIER(stderr);
#include "clinic/bltinmodule.c.h"
+static PyObject*
+update_bases(PyObject *bases, PyObject *const *args, int nargs)
+{
+ int i, j;
+ PyObject *base, *meth, *new_base, *result, *new_bases = NULL;
+ PyObject *stack[1] = {bases};
+ assert(PyTuple_Check(bases));
+
+ for (i = 0; i < nargs; i++) {
+ base = args[i];
+ if (PyType_Check(base)) {
+ if (new_bases) {
+ /* If we already have made a replacement, then we append every normal base,
+ otherwise just skip it. */
+ if (PyList_Append(new_bases, base) < 0) {
+ goto error;
+ }
+ }
+ continue;
+ }
+ meth = _PyObject_GetAttrId(base, &PyId___mro_entries__);
+ if (!meth) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ goto error;
+ }
+ PyErr_Clear();
+ if (new_bases) {
+ if (PyList_Append(new_bases, base) < 0) {
+ goto error;
+ }
+ }
+ continue;
+ }
+ new_base = _PyObject_FastCall(meth, stack, 1);
+ Py_DECREF(meth);
+ if (!new_base) {
+ goto error;
+ }
+ if (!PyTuple_Check(new_base)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__mro_entries__ must return a tuple");
+ Py_DECREF(new_base);
+ goto error;
+ }
+ if (!new_bases) {
+ /* If this is a first successful replacement, create new_bases list and
+ copy previously encountered bases. */
+ if (!(new_bases = PyList_New(i))) {
+ goto error;
+ }
+ for (j = 0; j < i; j++) {
+ base = args[j];
+ PyList_SET_ITEM(new_bases, j, base);
+ Py_INCREF(base);
+ }
+ }
+ j = PyList_GET_SIZE(new_bases);
+ if (PyList_SetSlice(new_bases, j, j, new_base) < 0) {
+ goto error;
+ }
+ Py_DECREF(new_base);
+ }
+ if (!new_bases) {
+ return bases;
+ }
+ result = PyList_AsTuple(new_bases);
+ Py_DECREF(new_bases);
+ return result;
+
+error:
+ Py_XDECREF(new_bases);
+ return NULL;
+}
+
/* AC: cannot convert yet, waiting for *args support */
static PyObject *
builtin___build_class__(PyObject *self, PyObject **args, Py_ssize_t nargs,
PyObject *kwnames)
{
- PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns;
+ PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns, *orig_bases;
PyObject *cls = NULL, *cell = NULL;
int isclass = 0; /* initialize to prevent gcc warning */
@@ -75,10 +150,16 @@ builtin___build_class__(PyObject *self, PyObject **args, Py_ssize_t nargs,
"__build_class__: name is not a string");
return NULL;
}
- bases = _PyStack_AsTupleSlice(args, nargs, 2, nargs);
- if (bases == NULL)
+ orig_bases = _PyStack_AsTupleSlice(args, nargs, 2, nargs);
+ if (orig_bases == NULL)
return NULL;
+ bases = update_bases(orig_bases, args + 2, nargs - 2);
+ if (bases == NULL) {
+ Py_DECREF(orig_bases);
+ return NULL;
+ }
+
if (kwnames == NULL) {
meta = NULL;
mkw = NULL;
@@ -171,6 +252,11 @@ builtin___build_class__(PyObject *self, PyObject **args, Py_ssize_t nargs,
NULL, 0, NULL, 0, NULL, 0, NULL,
PyFunction_GET_CLOSURE(func));
if (cell != NULL) {
+ if (bases != orig_bases) {
+ if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) {
+ goto error;
+ }
+ }
PyObject *margs[3] = {name, bases, ns};
cls = _PyObject_FastCallDict(meta, margs, 3, mkw);
if (cls != NULL && PyType_Check(cls) && PyCell_Check(cell)) {
@@ -209,6 +295,9 @@ error:
Py_DECREF(meta);
Py_XDECREF(mkw);
Py_DECREF(bases);
+ if (bases != orig_bases) {
+ Py_DECREF(orig_bases);
+ }
return cls;
}