mirror of
https://github.com/python/cpython.git
synced 2025-08-02 08:02:56 +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
|
a.foo = 42
|
||||||
self.assertEqual(a.__dict__, {"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):
|
def test_slots_descriptor(self):
|
||||||
# Issue2115: slot descriptors did not correctly check
|
# Issue2115: slot descriptors did not correctly check
|
||||||
# the type of the given object
|
# the type of the given object
|
||||||
|
|
|
@ -2478,11 +2478,17 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||||
}
|
}
|
||||||
PyList_SET_ITEM(newslots, j, tmp);
|
PyList_SET_ITEM(newslots, j, tmp);
|
||||||
if (PyDict_GetItem(dict, tmp)) {
|
if (PyDict_GetItem(dict, tmp)) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
/* CPython inserts __qualname__ and __classcell__ (when needed)
|
||||||
"%R in __slots__ conflicts with class variable",
|
into the namespace when creating a class. They will be deleted
|
||||||
tmp);
|
below so won't act as class variables. */
|
||||||
Py_DECREF(newslots);
|
if (!_PyUnicode_EqualToASCIIId(tmp, &PyId___qualname__) &&
|
||||||
goto error;
|
!_PyUnicode_EqualToASCIIId(tmp, &PyId___classcell__)) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"%R in __slots__ conflicts with class variable",
|
||||||
|
tmp);
|
||||||
|
Py_DECREF(newslots);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue