diff --git a/Include/object.h b/Include/object.h
index 695f015642..66e48cb0be 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -320,6 +320,9 @@ Code can use PyType_HasFeature(type_ob, flag_value) to test whether the
given type object has a specified feature.
*/
+/* Set if the type object if immutable */
+#define Py_TPFLAGS_IMMUTABLE (1UL << 8)
+
/* Set if the type object is dynamically allocated */
#define Py_TPFLAGS_HEAPTYPE (1UL << 9)
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index bdcd1254b3..d419d59ad2 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -50,6 +50,10 @@ def test_empty(self):
a += a
self.assertEqual(len(a), 0)
+ def test_immutable(self):
+ with self.assertRaises(TypeError):
+ array.array.foo = 1
+
# Machine format codes.
#
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index fb9ebbe9f4..6c1fcf26aa 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -2846,7 +2846,7 @@ static PyType_Slot array_slots[] = {
static PyType_Spec array_spec = {
.name = "array.array",
.basicsize = sizeof(arrayobject),
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLE,
.slots = array_slots,
};
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index a957c832b9..32498d8e57 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3859,7 +3859,9 @@ static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
int res;
- if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
+ type->tp_flags & Py_TPFLAGS_IMMUTABLE)
+ {
PyErr_Format(
PyExc_TypeError,
"can't set attributes of built-in/extension type '%s'",