mirror of
https://github.com/python/cpython.git
synced 2025-07-12 13:55:34 +00:00
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.
This commit is contained in:
parent
15a8728415
commit
2b5fd1e9ca
7 changed files with 492 additions and 5 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue