summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_descr.py40
-rw-r--r--Objects/typeobject.c16
2 files changed, 51 insertions, 5 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 5da7ae5..92553e3 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1322,6 +1322,46 @@ order (MRO) for bases """
a.foo = 42
self.assertEqual(a.__dict__, {"foo": 42})
+ def test_slots_special2(self):
+ # Testing __qualname__ and __classcell__ in __slots__
+ 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__"],
+ types.MemberDescriptorType)
+ c = C2()
+ self.assertEqual(c.b, 42)
+ self.assertNotHasAttr(c, "__classcell__")
+ c.__classcell__ = 42
+ self.assertEqual(c.__classcell__, 42)
+ with self.assertRaises(TypeError):
+ class C3:
+ __classcell__ = 42
+ __slots__ = ["__classcell__"]
+
+ class Q1(metaclass=Meta, attr="__qualname__"):
+ __slots__ = ["__qualname__"]
+ self.assertEqual(Q1.__qualname__, C1.__qualname__[:-2] + "Q1")
+ self.assertIsInstance(Q1.__dict__["__qualname__"],
+ types.MemberDescriptorType)
+ q = Q1()
+ self.assertNotHasAttr(q, "__qualname__")
+ q.__qualname__ = "q"
+ self.assertEqual(q.__qualname__, "q")
+ with self.assertRaises(TypeError):
+ class Q2:
+ __qualname__ = object()
+ __slots__ = ["__qualname__"]
+
def test_slots_descriptor(self):
# Issue2115: slot descriptors did not correctly check
# the type of the given object
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 18b67c8..d70ced0 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2478,11 +2478,17 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
}
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;
+ /* CPython inserts __qualname__ and __classcell__ (when needed)
+ into the namespace when creating a class. They will be deleted
+ below so won't act as class variables. */
+ if (!_PyUnicode_EqualToASCIIId(tmp, &PyId___qualname__) &&
+ !_PyUnicode_EqualToASCIIId(tmp, &PyId___classcell__)) {
+ PyErr_Format(PyExc_ValueError,
+ "%R in __slots__ conflicts with class variable",
+ tmp);
+ Py_DECREF(newslots);
+ goto error;
+ }
}
j++;
}