From e3374c8a24282968ff40598d7fc3ea8054c872af Mon Sep 17 00:00:00 2001 From: youknowdot Date: Sat, 10 Oct 2026 03:32:52 -0700 Subject: [PATCH] Support pickling slot wrapper descriptors (#9037) Extract wrapper descriptor reduction from #8954 for Python 3.14. Reduce to getattr on the defining class and cover direct reduction plus one roundtrip in the existing pickle snippet. Preserve canonical expected failures for unrelated staticmethod descriptor behavior. Assisted-by: OpenAI Codex:model identifier unavailable --- crates/vm/src/builtins/descriptor.rs | 10 ++++++++++ extra_tests/snippets/stdlib_pickle.py | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index 55c2275f5..e8329fbb5 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -2062,6 +2062,16 @@ impl Callable for PyWrapper { flags(DISALLOW_INSTANTIATION) )] impl Py { + #[pymethod] + fn __reduce__(&self, vm: &VirtualMachine) -> PyResult { + let getattr = vm.builtins.get_attr("getattr", vm)?; + let args = vm.ctx.new_tuple(vec![ + self.typ.to_owned().into(), + self.name.to_owned().into(), + ]); + Ok(vm.ctx.new_tuple(vec![getattr, args.into()]).into()) + } + #[pygetset] fn __qualname__(&self) -> String { format!("{}.{}", self.typ.name(), self.name) diff --git a/extra_tests/snippets/stdlib_pickle.py b/extra_tests/snippets/stdlib_pickle.py index 23d137df4..855bd7969 100644 --- a/extra_tests/snippets/stdlib_pickle.py +++ b/extra_tests/snippets/stdlib_pickle.py @@ -9,3 +9,7 @@ memo = unpickler.memo.copy() assert list(memo) == [1, 7] assert memo[1] is left assert memo[7] is left + +# Slot wrapper descriptors reduce to lookup on their defining class. +assert object.__str__.__reduce__() == (getattr, (object, "__str__")) +assert _pickle.loads(_pickle.dumps(object.__str__)) is object.__str__