]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-148450: abc.register needs to update type_version when tp_flags is changed...
authorHai Zhu <haiizhu@outlook.com>
Sat, 23 May 2026 11:50:16 +0000 (19:50 +0800)
committerGitHub <noreply@github.com>
Sat, 23 May 2026 11:50:16 +0000 (17:20 +0530)
Lib/test/test_type_cache.py
Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-09-55-50.gh-issue-148450.2MEVqH.rst [new file with mode: 0644]
Objects/typeobject.c

index 8e2bb0c238257b33d1e090f280dc87e2fded3d04..a6a6e8cbdc1053bbb91c56f436d3e32f17620a3e 100644 (file)
@@ -1,4 +1,5 @@
 """ Tests for the internal type cache in CPython. """
+import collections.abc
 import unittest
 import dis
 from test import support
@@ -108,6 +109,25 @@ class TypeCacheTests(unittest.TestCase):
             Holder.set_value()
             HolderSub.value
 
+    def test_abc_register_invalidates_subclass_versions(self):
+        class Parent:
+            pass
+
+        class Child(Parent):
+            pass
+
+        type_assign_version(Parent)
+        type_assign_version(Child)
+        parent_version = type_get_version(Parent)
+        child_version = type_get_version(Child)
+        if parent_version == 0 or child_version == 0:
+            self.skipTest("Could not assign valid type versions")
+
+        collections.abc.Mapping.register(Parent)
+
+        self.assertEqual(type_get_version(Parent), 0)
+        self.assertEqual(type_get_version(Child), 0)
+
 @support.cpython_only
 @requires_specialization
 class TypeCacheWithSpecializationTests(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-09-55-50.gh-issue-148450.2MEVqH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-23-09-55-50.gh-issue-148450.2MEVqH.rst
new file mode 100644 (file)
index 0000000..2a7d0d9
--- /dev/null
@@ -0,0 +1 @@
+Fix ``abc.register()`` so it invalidates type version tags for registered classes.
index 51d1ce573d12e13b257ee69c986a152b15a27821..7ae4cce02cf6834710f3cdaca06096e04d7df749 100644 (file)
@@ -5398,6 +5398,15 @@ void
 _PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
 {
     BEGIN_TYPE_LOCK();
+    /* Ideally, changing flags and invalidating the old version tag would
+       happen in one step. For this backport, keep it simple and invalidate
+       first while holding TYPE_LOCK. Immutable types are skipped because
+       set_flags_recursive() does not modify them. */
+    if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) &&
+        (self->tp_flags & mask) != flags)
+    {
+        type_modified_unlocked(self);
+    }
     set_flags_recursive(self, mask, flags);
     END_TYPE_LOCK();
 }