Skip to content

Commit cf71e34

Browse files
gh-77188: Add pickle tests for objects with slots (GH-144116)
1 parent 9eab67d commit cf71e34

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

Lib/test/picklecommon.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __getinitargs__(self):
2626
E.__module__ = "__main__"
2727

2828
# Simple mutable object.
29-
class Object:
29+
class Object(object):
3030
pass
3131

3232
# Hashable immutable key object containing unheshable mutable data.
@@ -38,6 +38,43 @@ def __reduce__(self):
3838
# Shouldn't support the recursion itself
3939
return K, (self.value,)
4040

41+
class WithSlots(object):
42+
__slots__ = ('a', 'b')
43+
44+
class WithSlotsSubclass(WithSlots):
45+
__slots__ = ('c',)
46+
47+
class WithSlotsAndDict(object):
48+
__slots__ = ('a', '__dict__')
49+
50+
class WithPrivateAttrs(object):
51+
def __init__(self, a):
52+
self.__private = a
53+
def get(self):
54+
return self.__private
55+
56+
class WithPrivateAttrsSubclass(WithPrivateAttrs):
57+
def __init__(self, a, b):
58+
super().__init__(a)
59+
self.__private = b
60+
def get2(self):
61+
return self.__private
62+
63+
class WithPrivateSlots(object):
64+
__slots__ = ('__private',)
65+
def __init__(self, a):
66+
self.__private = a
67+
def get(self):
68+
return self.__private
69+
70+
class WithPrivateSlotsSubclass(WithPrivateSlots):
71+
__slots__ = ('__private',)
72+
def __init__(self, a, b):
73+
super().__init__(a)
74+
self.__private = b
75+
def get2(self):
76+
return self.__private
77+
4178
# For test_misc
4279
class myint(int):
4380
def __init__(self, x):

Lib/test/pickletester.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4118,6 +4118,82 @@ def test_c_methods(self):
41184118
with self.subTest(proto=proto, descr=descr):
41194119
self.assertRaises(TypeError, self.dumps, descr, proto)
41204120

4121+
def test_object_with_attrs(self):
4122+
obj = Object()
4123+
obj.a = 1
4124+
for proto in protocols:
4125+
with self.subTest(proto=proto):
4126+
unpickled = self.loads(self.dumps(obj, proto))
4127+
self.assertEqual(unpickled.a, obj.a)
4128+
4129+
def test_object_with_slots(self):
4130+
obj = WithSlots()
4131+
obj.a = 1
4132+
self.assertRaises(TypeError, self.dumps, obj, 0)
4133+
self.assertRaises(TypeError, self.dumps, obj, 1)
4134+
for proto in protocols[2:]:
4135+
with self.subTest(proto=proto):
4136+
unpickled = self.loads(self.dumps(obj, proto))
4137+
self.assertEqual(unpickled.a, obj.a)
4138+
self.assertNotHasAttr(unpickled, 'b')
4139+
4140+
obj = WithSlotsSubclass()
4141+
obj.a = 1
4142+
obj.c = 2
4143+
self.assertRaises(TypeError, self.dumps, obj, 0)
4144+
self.assertRaises(TypeError, self.dumps, obj, 1)
4145+
for proto in protocols[2:]:
4146+
with self.subTest(proto=proto):
4147+
unpickled = self.loads(self.dumps(obj, proto))
4148+
self.assertEqual(unpickled.a, obj.a)
4149+
self.assertEqual(unpickled.c, obj.c)
4150+
self.assertNotHasAttr(unpickled, 'b')
4151+
4152+
obj = WithSlotsAndDict()
4153+
obj.a = 1
4154+
obj.c = 2
4155+
self.assertRaises(TypeError, self.dumps, obj, 0)
4156+
self.assertRaises(TypeError, self.dumps, obj, 1)
4157+
for proto in protocols[2:]:
4158+
with self.subTest(proto=proto):
4159+
unpickled = self.loads(self.dumps(obj, proto))
4160+
self.assertEqual(unpickled.a, obj.a)
4161+
self.assertEqual(unpickled.c, obj.c)
4162+
self.assertEqual(unpickled.__dict__, obj.__dict__)
4163+
self.assertNotHasAttr(unpickled, 'b')
4164+
4165+
def test_object_with_private_attrs(self):
4166+
obj = WithPrivateAttrs(1)
4167+
for proto in protocols:
4168+
with self.subTest(proto=proto):
4169+
unpickled = self.loads(self.dumps(obj, proto))
4170+
self.assertEqual(unpickled.get(), obj.get())
4171+
4172+
obj = WithPrivateAttrsSubclass(1, 2)
4173+
for proto in protocols:
4174+
with self.subTest(proto=proto):
4175+
unpickled = self.loads(self.dumps(obj, proto))
4176+
self.assertEqual(unpickled.get(), obj.get())
4177+
self.assertEqual(unpickled.get2(), obj.get2())
4178+
4179+
def test_object_with_private_slots(self):
4180+
obj = WithPrivateSlots(1)
4181+
self.assertRaises(TypeError, self.dumps, obj, 0)
4182+
self.assertRaises(TypeError, self.dumps, obj, 1)
4183+
for proto in protocols[2:]:
4184+
with self.subTest(proto=proto):
4185+
unpickled = self.loads(self.dumps(obj, proto))
4186+
self.assertEqual(unpickled.get(), obj.get())
4187+
4188+
obj = WithPrivateSlotsSubclass(1, 2)
4189+
self.assertRaises(TypeError, self.dumps, obj, 0)
4190+
self.assertRaises(TypeError, self.dumps, obj, 1)
4191+
for proto in protocols[2:]:
4192+
with self.subTest(proto=proto):
4193+
unpickled = self.loads(self.dumps(obj, proto))
4194+
self.assertEqual(unpickled.get(), obj.get())
4195+
self.assertEqual(unpickled.get2(), obj.get2())
4196+
41214197
def test_compat_pickle(self):
41224198
if self.py_version < (3, 4):
41234199
self.skipTest("doesn't work in Python < 3.4'")

0 commit comments

Comments
 (0)