Preserve __dict__ and __slots__ state in deque.__reduce__ (#7699)

deque.__reduce__ passed None as the unpickle state, so a deque
subclass's __dict__ and __slots__ values were dropped across a pickle
round-trip. CPython's deque___reduce___impl
(Modules/_collectionsmodule.c::deque___reduce___impl) calls
_PyObject_GetState, which returns the dict (or a (dict, slots) tuple)
so subclass attributes survive.

Replace the placeholder with the result of __getstate__() on the
instance. object.__getstate__ already implements the dict / dict+slots
protocol, matching _PyObject_GetState.
This commit is contained in:
Changjoon authored and GitHub committed 2026-04-27 12:50:23 +00:00
1 parent 9794ab7fdf
commit 1d42ee565f
2 files changed
+5 -2

No files matched your search

-1
View File
@@ -817,7 +817,6 @@ class TestSubclass(unittest.TestCase):
d.clear()
self.assertEqual(len(d), 0)
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: 'Deque' object has no attribute 'x'
def test_copy_pickle(self):
for cls in Deque, DequeWithSlots:
for d in cls('abc'), cls('abcde', maxlen=4):
+5 -1
View File
@@ -388,7 +388,11 @@ mod _collections {
Some(v) => vm.new_pyobj((vm.ctx.empty_tuple.clone(), v)),
None => vm.ctx.empty_tuple.clone().into(),
};
Ok(vm.new_pyobj((cls, value, vm.ctx.none(), PyDequeIterator::new(zelf))))
// Use __getstate__ to capture both __dict__ and __slots__ values so
// subclass attributes survive a pickle round-trip (matches CPython's
// deque___reduce___impl, which calls _PyObject_GetState).
let state = vm.call_method(zelf.as_object(), "__getstate__", ())?;
Ok(vm.new_pyobj((cls, value, state, PyDequeIterator::new(zelf))))
}
#[pyclassmethod]