https://github.com/python/cpython/commit/ac9715bf1333f91fbea369ea5646e370780eaa08
commit: ac9715bf1333f91fbea369ea5646e370780eaa08
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-01-22T11:26:48Z
summary:

[3.13] gh-77188: Add pickle tests for objects with slots (GH-144116) (GH-144120)

(cherry picked from commit cf71e34940e2314ee7ca00961d86a7172286eeea)

Co-authored-by: Serhiy Storchaka <[email protected]>

files:
M Lib/test/picklecommon.py
M Lib/test/pickletester.py

diff --git a/Lib/test/picklecommon.py b/Lib/test/picklecommon.py
index fece50f17fecca..4c19b6c421fc61 100644
--- a/Lib/test/picklecommon.py
+++ b/Lib/test/picklecommon.py
@@ -26,7 +26,7 @@ def __getinitargs__(self):
 E.__module__ = "__main__"
 
 # Simple mutable object.
-class Object:
+class Object(object):
     pass
 
 # Hashable immutable key object containing unheshable mutable data.
@@ -38,6 +38,43 @@ def __reduce__(self):
         # Shouldn't support the recursion itself
         return K, (self.value,)
 
+class WithSlots(object):
+    __slots__ = ('a', 'b')
+
+class WithSlotsSubclass(WithSlots):
+    __slots__ = ('c',)
+
+class WithSlotsAndDict(object):
+    __slots__ = ('a', '__dict__')
+
+class WithPrivateAttrs(object):
+    def __init__(self, a):
+        self.__private = a
+    def get(self):
+        return self.__private
+
+class WithPrivateAttrsSubclass(WithPrivateAttrs):
+    def __init__(self, a, b):
+        super().__init__(a)
+        self.__private = b
+    def get2(self):
+        return self.__private
+
+class WithPrivateSlots(object):
+    __slots__ = ('__private',)
+    def __init__(self, a):
+        self.__private = a
+    def get(self):
+        return self.__private
+
+class WithPrivateSlotsSubclass(WithPrivateSlots):
+    __slots__ = ('__private',)
+    def __init__(self, a, b):
+        super().__init__(a)
+        self.__private = b
+    def get2(self):
+        return self.__private
+
 # For test_misc
 class myint(int):
     def __init__(self, x):
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 99ae5f9ad64b4f..ae1c8c8aa33015 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -33,6 +33,7 @@
 from test.support.import_helper import forget
 from test.support.os_helper import TESTFN
 from test.support import threading_helper
+from test.support.testcase import ExtraAssertions
 from test.support.warnings_helper import save_restore_warnings_filters
 from test import picklecommon
 from test.picklecommon import *
@@ -2023,7 +2024,7 @@ def check(code, exc):
         check(-2**1000, (OverflowError, struct.error))
 
 
-class AbstractPickleTests:
+class AbstractPickleTests(ExtraAssertions):
     # Subclass must define self.dumps, self.loads.
 
     py_version = sys.version_info  # for test_xpickle
@@ -3617,6 +3618,82 @@ def test_c_methods(self):
                 with self.subTest(proto=proto, descr=descr):
                     self.assertRaises(TypeError, self.dumps, descr, proto)
 
+    def test_object_with_attrs(self):
+        obj = Object()
+        obj.a = 1
+        for proto in protocols:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.a, obj.a)
+
+    def test_object_with_slots(self):
+        obj = WithSlots()
+        obj.a = 1
+        self.assertRaises(TypeError, self.dumps, obj, 0)
+        self.assertRaises(TypeError, self.dumps, obj, 1)
+        for proto in protocols[2:]:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.a, obj.a)
+                self.assertNotHasAttr(unpickled, 'b')
+
+        obj = WithSlotsSubclass()
+        obj.a = 1
+        obj.c = 2
+        self.assertRaises(TypeError, self.dumps, obj, 0)
+        self.assertRaises(TypeError, self.dumps, obj, 1)
+        for proto in protocols[2:]:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.a, obj.a)
+                self.assertEqual(unpickled.c, obj.c)
+                self.assertNotHasAttr(unpickled, 'b')
+
+        obj = WithSlotsAndDict()
+        obj.a = 1
+        obj.c = 2
+        self.assertRaises(TypeError, self.dumps, obj, 0)
+        self.assertRaises(TypeError, self.dumps, obj, 1)
+        for proto in protocols[2:]:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.a, obj.a)
+                self.assertEqual(unpickled.c, obj.c)
+                self.assertEqual(unpickled.__dict__, obj.__dict__)
+                self.assertNotHasAttr(unpickled, 'b')
+
+    def test_object_with_private_attrs(self):
+        obj = WithPrivateAttrs(1)
+        for proto in protocols:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.get(), obj.get())
+
+        obj = WithPrivateAttrsSubclass(1, 2)
+        for proto in protocols:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.get(), obj.get())
+                self.assertEqual(unpickled.get2(), obj.get2())
+
+    def test_object_with_private_slots(self):
+        obj = WithPrivateSlots(1)
+        self.assertRaises(TypeError, self.dumps, obj, 0)
+        self.assertRaises(TypeError, self.dumps, obj, 1)
+        for proto in protocols[2:]:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.get(), obj.get())
+
+        obj = WithPrivateSlotsSubclass(1, 2)
+        self.assertRaises(TypeError, self.dumps, obj, 0)
+        self.assertRaises(TypeError, self.dumps, obj, 1)
+        for proto in protocols[2:]:
+            with self.subTest(proto=proto):
+                unpickled = self.loads(self.dumps(obj, proto))
+                self.assertEqual(unpickled.get(), obj.get())
+                self.assertEqual(unpickled.get2(), obj.get2())
+
     def test_compat_pickle(self):
         if self.py_version < (3, 4):
             self.skipTest("doesn't work in Python < 3.4'")

_______________________________________________
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