diff -r 784fea019cab Lib/test/test_descr.py --- a/Lib/test/test_descr.py Wed Nov 09 18:57:00 2016 -0500 +++ b/Lib/test/test_descr.py Fri Nov 11 21:16:08 2016 +0800 @@ -1321,6 +1321,42 @@ a.foo = 42 self.assertEqual(a.__dict__, {"foo": 42}) + def test_slots_special2(self): + # Testing __qualname__ and __classcell__ in __slots__ + from types import MemberDescriptorType as Member + class Meta(type): + def __new__(cls, name, bases, namespace, attr): + self.assertIn(attr, namespace) + return super().__new__(cls, name, bases, namespace) + + class C1: + def __init__(self): + self.b = 42 + class C2(C1, metaclass=Meta, attr="__classcell__"): + __slots__ = ["__classcell__"] + def __init__(self): + super().__init__() + self.assertIsInstance(C2.__dict__["__classcell__"], Member) + c = C2() + self.assertEqual(c.b, 42) + self.assertNotHasAttr(c, "__classcell__") + c.__classcell__ = 42 + self.assertEqual(c.__classcell__, 42) + + with self.assertRaises(ValueError): + class C3: + __classcell__ = 42 + __slots__ = ["__classcell__"] + + class Q(metaclass=Meta, attr="__qualname__"): + __slots__ = ["__qualname__"] + self.assertEqual(Q.__qualname__, C1.__qualname__[:-2] + "Q") + self.assertIsInstance(Q.__dict__["__qualname__"], Member) + q = Q() + self.assertNotHasAttr(q, "__qualname__") + q.__qualname__ = "q" + self.assertEqual(q.__qualname__, "q") + def test_slots_descriptor(self): # Issue2115: slot descriptors did not correctly check # the type of the given object diff -r 784fea019cab Objects/typeobject.c --- a/Objects/typeobject.c Wed Nov 09 18:57:00 2016 -0500 +++ b/Objects/typeobject.c Fri Nov 11 21:16:08 2016 +0800 @@ -2445,11 +2445,27 @@ } PyList_SET_ITEM(newslots, j, tmp); if (PyDict_GetItem(dict, tmp)) { - PyErr_Format(PyExc_ValueError, - "%R in __slots__ conflicts with class variable", - tmp); - Py_DECREF(newslots); - goto error; + int err = 1; + /* CPython inserts __qualname__ and __classcell__ (when needed) + into the namespace when creating a class. They will be deleted + below so won't act as a class variable. */ + if (_PyUnicode_CompareWithId(tmp, &PyId___qualname__) == 0) + err = 0; + if (_PyUnicode_CompareWithId(tmp, &PyId___classcell__) == 0) { + cell = PyDict_GetItem(dict, tmp); + if (cell != NULL && PyCell_Check(cell)) + err = 0; + else + err = 1; + } + + if (err) { + PyErr_Format(PyExc_ValueError, + "%R in __slots__ conflicts with class variable", + tmp); + Py_DECREF(newslots); + goto error; + } } j++; }