diff -r 59a189a15933 Include/object.h --- a/Include/object.h Thu Oct 25 17:23:54 2012 -0700 +++ b/Include/object.h Thu Oct 25 23:39:02 2012 -0700 @@ -446,17 +446,17 @@ typedef struct _heaptypeobject { PyNumberMethods as_number; PyMappingMethods as_mapping; PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, so that the mapping wins when both the mapping and the sequence define a given operator (e.g. __getitem__). see add_operators() in typeobject.c . */ PyBufferProcs as_buffer; - PyObject *ht_name, *ht_slots, *ht_qualname; + PyObject *ht_name, *ht_slots; struct _dictkeysobject *ht_cached_keys; /* here are optional user slots, followed by the members. */ } PyHeapTypeObject; /* access macro to the members which are floating "behind" the object */ #define PyHeapType_GET_MEMBERS(etype) \ ((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize)) #endif diff -r 59a189a15933 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu Oct 25 17:23:54 2012 -0700 +++ b/Lib/test/test_sys.py Thu Oct 25 23:39:02 2012 -0700 @@ -833,17 +833,17 @@ class SizeofTest(unittest.TestCase): check((), vsize('')) check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject s = vsize('P2n15Pl4Pn9Pn11PI') check(int, s) # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs + 4P) - s = vsize('P2n15Pl4Pn9Pn11PI') + struct.calcsize('34P 3P 10P 2P 4P') + s = vsize('P2n15Pl4Pn9Pn11PI') + struct.calcsize('34P 2P 10P 2P 4P') # Separate block for PyDictKeysObject with 4 entries s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P") # class class newstyleclass(object): pass check(newstyleclass, s) # dict with shared keys check(newstyleclass().__dict__, size('n2P' + '2nPn')) # unicode diff -r 59a189a15933 Objects/typeobject.c --- a/Objects/typeobject.c Thu Oct 25 17:23:54 2012 -0700 +++ b/Objects/typeobject.c Thu Oct 25 23:39:02 2012 -0700 @@ -39,16 +39,17 @@ static unsigned int next_version_tag = 0 _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__getitem__); _Py_IDENTIFIER(__getattribute__); _Py_IDENTIFIER(__hash__); _Py_IDENTIFIER(__module__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__new__); +_Py_IDENTIFIER(__qualname__); static PyObject * _PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name); static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); unsigned int @@ -248,19 +249,23 @@ type_name(PyTypeObject *type, void *cont return PyUnicode_FromString(s); } } static PyObject * type_qualname(PyTypeObject *type, void *context) { if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - PyHeapTypeObject* et = (PyHeapTypeObject*)type; - Py_INCREF(et->ht_qualname); - return et->ht_qualname; + PyObject *qual = _PyDict_GetItemId(type->tp_dict, &PyId___qualname__); + if (!qual) { + PyErr_Format(PyExc_AttributeError, "__qualname__"); + return 0; + } + Py_INCREF(qual); + return qual; } else { return type_name(type, context); } } static int type_set_name(PyTypeObject *type, PyObject *value, void *context) @@ -304,30 +309,22 @@ type_set_name(PyTypeObject *type, PyObje type->tp_name = tp_name; return 0; } static int type_set_qualname(PyTypeObject *type, PyObject *value, void *context) { - PyHeapTypeObject* et; - - if (!PyUnicode_Check(value)) { - PyErr_Format(PyExc_TypeError, - "can only assign string to %s.__qualname__, not '%s'", - type->tp_name, Py_TYPE(value)->tp_name); + if (!check_set_special_type_attr(type, value, "__qualname__")) return -1; - } - - et = (PyHeapTypeObject*)type; - Py_INCREF(value); - Py_DECREF(et->ht_qualname); - et->ht_qualname = value; - return 0; + + PyType_Modified(type); + + return _PyDict_SetItemId(type->tp_dict, &PyId___qualname__, value); } static PyObject * type_module(PyTypeObject *type, void *context) { PyObject *mod; char *s; @@ -1979,17 +1976,16 @@ type_new(PyTypeObject *metatype, PyObjec PyObject *name, *bases = NULL, *orig_dict, *dict = NULL; static char *kwlist[] = {"name", "bases", "dict", 0}; PyObject *qualname, *slots = NULL, *tmp, *newslots; PyTypeObject *type = NULL, *base, *tmptype, *winner; PyHeapTypeObject *et; PyMemberDef *mp; Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; int j, may_add_dict, may_add_weak; - _Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__slots__); assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); /* Special case: type(x) should return x->ob_type */ { const Py_ssize_t nargs = PyTuple_GET_SIZE(args); @@ -2247,19 +2243,19 @@ type_new(PyTypeObject *metatype, PyObjec PyErr_Format(PyExc_TypeError, "type __qualname__ must be a str, not %s", Py_TYPE(qualname)->tp_name); goto error; } } else { qualname = et->ht_name; - } - Py_INCREF(qualname); - et->ht_qualname = qualname; + if (_PyDict_SetItemId(dict, &PyId___qualname__, qualname) < 0) + goto error; + } /* Set tp_doc to a copy of dict['__doc__'], if the latter is there and is a string. The __doc__ accessor will first look for tp_doc; if that fails, it will still look into __dict__. */ { PyObject *doc = _PyDict_GetItemId(dict, &PyId___doc__); if (doc != NULL && PyUnicode_Check(doc)) { @@ -2405,18 +2401,16 @@ PyType_FromSpecWithBases(PyType_Spec *sp if (res == NULL) return NULL; type = &res->ht_type; /* The flags must be initialized early, before the GC traverses us */ type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; res->ht_name = PyUnicode_FromString(s); if (!res->ht_name) goto fail; - res->ht_qualname = res->ht_name; - Py_INCREF(res->ht_qualname); type->tp_name = spec->name; if (!type->tp_name) goto fail; /* Adjust for empty tuple bases */ if (!bases) { base = &PyBaseObject_Type; /* See whether Py_tp_base(s) was specified */ @@ -2498,16 +2492,20 @@ PyType_FromSpecWithBases(PyType_Spec *sp /* Set type.__module__ */ s = strrchr(spec->name, '.'); if (s != NULL) _PyDict_SetItemId(type->tp_dict, &PyId___module__, PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name))); + /* Set type.__qualname__ */ + if (_PyDict_SetItemId(type->tp_dict, &PyId___qualname__, res->ht_name) < 0) + goto fail; + return (PyObject*)res; fail: Py_DECREF(res); return NULL; } PyObject * @@ -2700,17 +2698,16 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); Py_XDECREF(type->tp_subclasses); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. */ PyObject_Free((char *)type->tp_doc); Py_XDECREF(et->ht_name); - Py_XDECREF(et->ht_qualname); Py_XDECREF(et->ht_slots); if (et->ht_cached_keys) _PyDictKeys_DecRef(et->ht_cached_keys); Py_TYPE(type)->tp_free((PyObject *)type); } static PyObject * type_subclasses(PyTypeObject *type, PyObject *args_ignored)