https://github.com/python/cpython/commit/86ffaf125f50c56574fe936dd058fb8afc3b68db
commit: 86ffaf125f50c56574fe936dd058fb8afc3b68db
branch: 3.14
author: Hai Zhu <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-05-23T12:01:57Z
summary:

[3.14] gh-148450: abc.register needs to update type_version when tp_flags is 
changed (GH-148623) (#150308)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst
M Lib/test/test_type_cache.py
M Objects/typeobject.c

diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py
index 7469a1047f81d70..0390e6496109ec0 100644
--- a/Lib/test/test_type_cache.py
+++ b/Lib/test/test_type_cache.py
@@ -1,4 +1,5 @@
 """ Tests for the internal type cache in CPython. """
+import collections.abc
 import dis
 import unittest
 import warnings
@@ -114,6 +115,25 @@ class HolderSub(Holder):
             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
 class TypeCacheWithSpecializationTests(unittest.TestCase):
     def tearDown(self):
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst
new file mode 100644
index 000000000000000..2a7d0d9bb3a7f7e
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-15-15-48-04.gh-issue-148450.2MEVqH.rst
@@ -0,0 +1 @@
+Fix ``abc.register()`` so it invalidates type version tags for registered 
classes.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 0db171807aca4ba..0f1660f8f40b217 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -6066,6 +6066,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. In 3.14, invalidate first while holding TYPE_LOCK so 
readers
+       cannot assign a fresh tag from stale flags. Immutable types are skipped 
by
+       set_flags_recursive(). */
+    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();
 }

_______________________________________________
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]

Reply via email to