diff --git a/Include/odictobject.h b/Include/odictobject.h --- a/Include/odictobject.h +++ b/Include/odictobject.h @@ -28,6 +28,8 @@ PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item); PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key); +PyAPI_FUNC(PyObject *) _PyODict_KeysAsList(PyObject *od); + /* wrappers around PyDict* functions */ #define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key) #define PyODict_Contains(od, key) PyDict_Contains((PyObject *)od, key) diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py --- a/Lib/test/test_metaclass.py +++ b/Lib/test/test_metaclass.py @@ -180,7 +180,7 @@ meta: C () ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] kw: [] - >>> type(C) is dict + >>> type(C) is OrderedDict True >>> print(sorted(C.items())) [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] @@ -212,7 +212,7 @@ The default metaclass must define a __prepare__() method. >>> type.__prepare__() - {} + OrderedDict() >>> Make sure it works with subclassing. @@ -248,6 +248,7 @@ """ +from collections import OrderedDict import sys # Trace function introduces __locals__ which causes various tests to fail. diff --git a/Objects/odictobject.c b/Objects/odictobject.c --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1770,6 +1770,21 @@ return res; }; +PyObject * +_PyODict_KeysAsList(PyObject *od) { +// return PyObject_CallFunctionObjArgs((PyObject *)&PyList_Type, od, NULL); + Py_ssize_t i = 0; + _ODictNode *node; + PyObject *keys = PyList_New(PyODict_Size(od)); + if (keys == NULL) + return NULL; + _odict_FOREACH((PyODictObject *)od, node) { + Py_INCREF(_odictnode_KEY(node)); + PyList_SET_ITEM(keys, i, _odictnode_KEY(node)); + i++; + } + return keys; +} /* ------------------------------------------- * The OrderedDict views (keys/values/items) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2310,6 +2310,7 @@ } } + /* XXX Does PyDict_Type have to be exact? */ /* Check arguments: (name, bases, dict) */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "UO!O!:type", kwlist, &name, @@ -2352,10 +2353,24 @@ goto error; } + /* Copy the definition namespace into a new dict. */ + /* XXX Is OrderedDict compatible with the split-keys mechanism? */ dict = PyDict_Copy(orig_dict); if (dict == NULL) goto error; + /* Record the definition order of the class's namespace. */ + if (PyODict_Check(orig_dict)) { + int res; + PyObject *names = _PyODict_KeysAsList(orig_dict); + if (names == NULL) + goto error; + res = PyDict_SetItemString(dict, "__definition_order__", names); + Py_DECREF(names); + if (res != 0) + goto error; + } + /* Check for a __slots__ sequence variable in dict, and count it */ slots = _PyDict_GetItemId(dict, &PyId___slots__); nslots = 0; @@ -3085,7 +3100,7 @@ static PyObject * type_prepare(PyObject *self, PyObject *args, PyObject *kwds) { - return PyDict_New(); + return PyODict_New(); } /* diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -145,7 +145,7 @@ if (prep == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); - ns = PyDict_New(); + ns = PyODict_New(); } else { Py_DECREF(meta);