gh-155358: Add test.support.check_immutable_type() (#155510)

vstinner <[email protected]> Mon, 10 Aug 2026 15:45:06 -0400 (EDT)
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/219768ff531fc0686de623139562ee9f9537df98
commit: 219768ff531fc0686de623139562ee9f9537df98
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-08-10T21:44:50+02:00
summary:

gh-155358: Add test.support.check_immutable_type() (#155510)

Check that sys types are immutable:

* type(sys.flags)
* type(sys.get_asyncgen_hooks())
* type(sys.getwindowsversion())
* type(sys.hash_info)
* type(sys.version_info)

files:
M Lib/test/support/__init__.py
M Lib/test/test_decimal.py
M Lib/test/test_itertools.py
M Lib/test/test_sys.py
M Lib/test/test_xml_etree_c.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 897c210f4767e1..c1460b806806f8 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -3465,3 +3465,9 @@ def skip_on_low_desktop_heap_memory_subprocess(returncode):
     if returncode == STATUS_DLL_INIT_FAILED:
         raise unittest.SkipTest('gh-150436: DLL init failed, likely because '
                                 'of low desktop heap memory')
+
+
+def check_immutable_type(testcase, type):
+    regex = r'cannot set .* attribute of immutable type'
+    with testcase.assertRaisesRegex(TypeError, regex):
+        setattr(type, 'custom_attr', 123)
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index b8c09c7f43e3e3..a0ba5a8351aebd 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -32,6 +32,7 @@
 import unittest
 import numbers
 import locale
+from test import support
 from test.support import (is_resource_enabled,
                           requires_IEEE_754, requires_docstrings,
                           check_disallow_instantiation)
@@ -5806,8 +5807,7 @@ def test_c_immutable_types(self):
         )
         for tp in types:
             with self.subTest(tp=tp):
-                with self.assertRaisesRegex(TypeError, "immutable"):
-                    tp.foo = 1
+                support.check_immutable_type(self, tp)
 
     def test_c_disallow_instantiation(self):
         ContextManager = type(C.localcontext())
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index cf579d4da4e0df..d47f9acf019dca 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1541,8 +1541,7 @@ def test_immutable_types(self):
         )
         for tp in dataset:
             with self.subTest(tp=tp):
-                with self.assertRaisesRegex(TypeError, "immutable"):
-                    tp.foobar = 1
+                support.check_immutable_type(self, tp)
 
 
 class TestExamples(unittest.TestCase):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index dab03ef06a8b8e..f2adce532595e7 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -425,6 +425,7 @@ def test_getwindowsversion(self):
         self.assertEqual(v[2], v.build)
         self.assertEqual(v[3], v.platform)
         self.assertEqual(v[4], v.service_pack)
+        support.check_immutable_type(self, type(v))
 
         # This is how platform.py calls it. Make sure tuple
         #  still has 5 elements
@@ -690,6 +691,7 @@ def test_attributes(self):
             self.assertEqual(algo, 0)
         self.assertGreaterEqual(sys.hash_info.cutoff, 0)
         self.assertLess(sys.hash_info.cutoff, 8)
+        support.check_immutable_type(self, type(sys.hash_info))
 
         self.assertIsInstance(sys.maxsize, int)
         self.assertIsInstance(sys.maxunicode, int)
@@ -893,11 +895,13 @@ def assert_raise_on_new_sys_type(self, sys_attr):
         # sys.flags, sys.version_info, and sys.getwindowsversion.
         support.check_disallow_instantiation(self, type(sys_attr), sys_attr)
 
-    def test_sys_flags_no_instantiation(self):
+    def test_sys_flags_type(self):
         self.assert_raise_on_new_sys_type(sys.flags)
+        support.check_immutable_type(self, type(sys.flags))
 
-    def test_sys_version_info_no_instantiation(self):
+    def test_sys_version_info_type(self):
         self.assert_raise_on_new_sys_type(sys.version_info)
+        support.check_immutable_type(self, type(sys.version_info))
 
     def test_sys_getwindowsversion_no_instantiation(self):
         # Skip if not being run on Windows.
@@ -1954,6 +1958,7 @@ def test_asyncgen_hooks(self):
         cur = sys.get_asyncgen_hooks()
         self.assertIsNone(cur.firstiter)
         self.assertIsNone(cur.finalizer)
+        support.check_immutable_type(self, type(cur))
 
         # gh-118473
         with self.assertRaises(TypeError):
@@ -1997,6 +2002,7 @@ def write(self, s):
         self.assertEqual(out, b"")
         self.assertEqual(err, b"")
 
+
 @test.support.support_remote_exec_only
 @test.support.cpython_only
 class TestRemoteExec(unittest.TestCase):
diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py
index 270b9d6da8e7b9..2a18396afb6088 100644
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -194,8 +194,7 @@ def test_immutable_types(self):
         )
         for tp in dataset:
             with self.subTest(tp=tp):
-                with self.assertRaisesRegex(TypeError, "immutable"):
-                    tp.foo = 1
+                support.check_immutable_type(self, tp)
 
     @support.cpython_only
     def test_disallow_instantiation(self):

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]