summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_dataclasses.py
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2023-05-01 15:19:06 (GMT)
committerGitHub <noreply@github.com>2023-05-01 15:19:06 (GMT)
commit99aab610622fc4b4c4fe56b77c0760cf77066a53 (patch)
tree39013f1f2980f70b1c0e0de2eb3abc12e9b6ba31 /Lib/test/test_dataclasses.py
parente1476942525ae847875dab55541bef4a8a99dd3d (diff)
downloadcpython-99aab610622fc4b4c4fe56b77c0760cf77066a53.zip
cpython-99aab610622fc4b4c4fe56b77c0760cf77066a53.tar.gz
cpython-99aab610622fc4b4c4fe56b77c0760cf77066a53.tar.bz2
gh-104035: Do not ignore user-defined `__{get,set}state__` in slotted frozen dataclasses (#104041)
Diffstat (limited to 'Lib/test/test_dataclasses.py')
-rw-r--r--Lib/test/test_dataclasses.py68
1 files changed, 68 insertions, 0 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 7b48b26..6669f1c 100644
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -3184,6 +3184,74 @@ class TestSlots(unittest.TestCase):
self.assertIsNot(obj, p)
self.assertEqual(obj, p)
+ @dataclass(frozen=True, slots=True)
+ class FrozenSlotsGetStateClass:
+ foo: str
+ bar: int
+
+ getstate_called: bool = field(default=False, compare=False)
+
+ def __getstate__(self):
+ object.__setattr__(self, 'getstate_called', True)
+ return [self.foo, self.bar]
+
+ @dataclass(frozen=True, slots=True)
+ class FrozenSlotsSetStateClass:
+ foo: str
+ bar: int
+
+ setstate_called: bool = field(default=False, compare=False)
+
+ def __setstate__(self, state):
+ object.__setattr__(self, 'setstate_called', True)
+ object.__setattr__(self, 'foo', state[0])
+ object.__setattr__(self, 'bar', state[1])
+
+ @dataclass(frozen=True, slots=True)
+ class FrozenSlotsAllStateClass:
+ foo: str
+ bar: int
+
+ getstate_called: bool = field(default=False, compare=False)
+ setstate_called: bool = field(default=False, compare=False)
+
+ def __getstate__(self):
+ object.__setattr__(self, 'getstate_called', True)
+ return [self.foo, self.bar]
+
+ def __setstate__(self, state):
+ object.__setattr__(self, 'setstate_called', True)
+ object.__setattr__(self, 'foo', state[0])
+ object.__setattr__(self, 'bar', state[1])
+
+ def test_frozen_slots_pickle_custom_state(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(proto=proto):
+ obj = self.FrozenSlotsGetStateClass('a', 1)
+ dumped = pickle.dumps(obj, protocol=proto)
+
+ self.assertTrue(obj.getstate_called)
+ self.assertEqual(obj, pickle.loads(dumped))
+
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(proto=proto):
+ obj = self.FrozenSlotsSetStateClass('a', 1)
+ obj2 = pickle.loads(pickle.dumps(obj, protocol=proto))
+
+ self.assertTrue(obj2.setstate_called)
+ self.assertEqual(obj, obj2)
+
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(proto=proto):
+ obj = self.FrozenSlotsAllStateClass('a', 1)
+ dumped = pickle.dumps(obj, protocol=proto)
+
+ self.assertTrue(obj.getstate_called)
+
+ obj2 = pickle.loads(dumped)
+ self.assertTrue(obj2.setstate_called)
+ self.assertEqual(obj, obj2)
+
def test_slots_with_default_no_init(self):
# Originally reported in bpo-44649.
@dataclass(slots=True)