diff options
author | Ivan Levkivskyi <levkivskyi@gmail.com> | 2017-12-14 22:32:56 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-14 22:32:56 (GMT) |
commit | 2b5fd1e9ca9318673989e6ccac2c8acadc3809cd (patch) | |
tree | 5aa372f821be82c0d17265700364a5c4643d1cd4 /Python/bltinmodule.c | |
parent | 15a8728415e765f57e37f431f09e5c5821a04063 (diff) | |
download | cpython-2b5fd1e9ca9318673989e6ccac2c8acadc3809cd.zip cpython-2b5fd1e9ca9318673989e6ccac2c8acadc3809cd.tar.gz cpython-2b5fd1e9ca9318673989e6ccac2c8acadc3809cd.tar.bz2 |
bpo-32226: Implementation of PEP 560 (core components) (#4732)
This part of the PEP implementation adds support for
__mro_entries__ and __class_getitem__ by updating
__build_class__ and PyObject_GetItem.
Diffstat (limited to 'Python/bltinmodule.c')
-rw-r--r-- | Python/bltinmodule.c | 95 |
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; } |