mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
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:
1 parent
9794ab7fdf
commit
1d42ee565f
2 files changed
+5
-2
No files matched your search
Vendored
-1
@@ -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):
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user