[Python-checkins] bpo-43908: check_set_special_type_attr() checks Py_TPFLAGS_IMMUTABLETYPE (GH-25743)

vstinner webhook-mailer at python.org
Fri Apr 30 09:25:51 EDT 2021


https://github.com/python/cpython/commit/64141382ecbad665d5738ff26d15505f3427c724
commit: 64141382ecbad665d5738ff26d15505f3427c724
branch: master
author: Erlend Egeberg Aasland <erlend.aasland at innova.no>
committer: vstinner <vstinner at python.org>
date: 2021-04-30T15:25:43+02:00
summary:

bpo-43908: check_set_special_type_attr() checks Py_TPFLAGS_IMMUTABLETYPE (GH-25743)

check_set_special_type_attr() and type_set_annotations()
now check for immutable flag (Py_TPFLAGS_IMMUTABLETYPE).

Co-authored-by: Victor Stinner <vstinner at python.org>

files:
M Lib/test/test_descr.py
M Objects/typeobject.c

diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 79d6c4b5e7232..3cb923ed0520a 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4763,12 +4763,14 @@ class X:
             "elephant"
         X.__doc__ = "banana"
         self.assertEqual(X.__doc__, "banana")
+
         with self.assertRaises(TypeError) as cm:
             type(list).__dict__["__doc__"].__set__(list, "blah")
-        self.assertIn("can't set list.__doc__", str(cm.exception))
+        self.assertIn("cannot set '__doc__' attribute of immutable type 'list'", str(cm.exception))
+
         with self.assertRaises(TypeError) as cm:
             type(X).__dict__["__doc__"].__delete__(X)
-        self.assertIn("can't delete X.__doc__", str(cm.exception))
+        self.assertIn("cannot delete '__doc__' attribute of immutable type 'X'", str(cm.exception))
         self.assertEqual(X.__doc__, "banana")
 
     def test_qualname(self):
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 0f7f280bca0d6..621bb0ca93022 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -466,14 +466,16 @@ static PyMemberDef type_members[] = {
 static int
 check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name)
 {
-    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+    if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) {
         PyErr_Format(PyExc_TypeError,
-                     "can't set %s.%s", type->tp_name, name);
+                     "cannot set '%s' attribute of immutable type '%s'",
+                     name, type->tp_name);
         return 0;
     }
     if (!value) {
         PyErr_Format(PyExc_TypeError,
-                     "can't delete %s.%s", type->tp_name, name);
+                     "cannot delete '%s' attribute of immutable type '%s'",
+                     name, type->tp_name);
         return 0;
     }
 
@@ -978,8 +980,10 @@ type_get_annotations(PyTypeObject *type, void *context)
 static int
 type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
 {
-    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
-        PyErr_Format(PyExc_TypeError, "can't set attributes of built-in/extension type '%s'", type->tp_name);
+    if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) {
+        PyErr_Format(PyExc_TypeError,
+                     "cannot set '__annotations__' attribute of immutable type '%s'",
+                     type->tp_name);
         return -1;
     }
 
@@ -3953,8 +3957,8 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
     if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
         PyErr_Format(
             PyExc_TypeError,
-            "can't set attributes of built-in/extension type '%s'",
-            type->tp_name);
+            "cannot set %R attribute of immutable type '%s'",
+            name, type->tp_name);
         return -1;
     }
     if (PyUnicode_Check(name)) {



More information about the Python-checkins mailing list