]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-77188: Add pickle tests for objects with slots (GH-144116) (GH-144119)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 21 Jan 2026 17:47:27 +0000 (18:47 +0100)
committerGitHub <noreply@github.com>
Wed, 21 Jan 2026 17:47:27 +0000 (17:47 +0000)
(cherry picked from commit cf71e34940e2314ee7ca00961d86a7172286eeea)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Lib/test/picklecommon.py
Lib/test/pickletester.py

index fece50f17feccad73512dccc130e95c8283b3582..4c19b6c421fc612ea1173b85ade2e4031d5f43ec 100644 (file)
@@ -26,7 +26,7 @@ __main__.E = E
 E.__module__ = "__main__"
 
 # Simple mutable object.
-class Object:
+class Object(object):
     pass
 
 # Hashable immutable key object containing unheshable mutable data.
@@ -38,6 +38,43 @@ class K:
         # 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):
index 570233f7ec516aaa31236fef1f76911ec4e9b262..9a5df6371cd0ba1beba953a2f4364789a6073fe1 100644 (file)
@@ -3947,6 +3947,82 @@ class AbstractPickleTests:
                 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'")