mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
bpo-24329: allow __qualname__ and __classcell__ in __slots__ (GH-495)
This commit is contained in:
parent
d5d3249e8a
commit
c393ee8589
2 changed files with 51 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue