mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Read cached __slotnames__ and propagate slot name errors (#8895)
type_slot_names reads __slotnames__ from the type's own dict before
calling copyreg._slotnames, and rejects a cached value that is not a
list or None. object_getstate_default no longer replaces errors from
type_slot_names with TypeError("cannot pickle object"), so a
RecursionError raised there propagates.
Assisted-by: Claude:claude-opus-5-5
This commit is contained in:
1 parent
b499e70e12
commit
63b80efc9f
1 file changed
+16
-15
@@ -164,21 +164,23 @@ impl Initializer for PyBaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement _PyType_GetSlotNames properly
|
||||
// _PyType_GetSlotNames
|
||||
fn type_slot_names(typ: &Py<PyType>, vm: &VirtualMachine) -> PyResult<Option<super::PyListRef>> {
|
||||
// let attributes = typ.attributes.read();
|
||||
// if let Some(slot_names) = attributes.get(identifier!(vm.ctx, __slotnames__)) {
|
||||
// return match_class!(match slot_names.clone() {
|
||||
// l @ super::PyList => Ok(Some(l)),
|
||||
// _n @ super::PyNone => Ok(None),
|
||||
// _ => Err(vm.new_type_error(format!(
|
||||
// "{:.200}.__slotnames__ should be a list or None, not {:.200}",
|
||||
// typ.name(),
|
||||
// slot_names.class().name()
|
||||
// ))),
|
||||
// });
|
||||
// }
|
||||
// The class caches its slot names in `__slotnames__`.
|
||||
if let Some(slot_names) = typ.get_direct_attr(identifier!(vm.ctx, __slotnames__)) {
|
||||
return match_class!(match slot_names {
|
||||
l @ super::PyList => Ok(Some(l)),
|
||||
_n @ super::PyNone => Ok(None),
|
||||
other => Err(vm.new_type_error(format!(
|
||||
"{:.200}.__slotnames__ should be a list or None, not {:.200}",
|
||||
typ.name(),
|
||||
other.class().name()
|
||||
))),
|
||||
});
|
||||
}
|
||||
|
||||
// copyreg._slotnames collects the slots of the class and its bases and
|
||||
// caches them in `__slotnames__`.
|
||||
let copyreg = vm.import("copyreg", 0)?;
|
||||
let copyreg_slotnames = copyreg.get_attr("_slotnames", vm)?;
|
||||
let slot_names = copyreg_slotnames.call((typ.to_owned(),), vm)?;
|
||||
@@ -207,8 +209,7 @@ fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine)
|
||||
state.into()
|
||||
};
|
||||
|
||||
let slot_names =
|
||||
type_slot_names(obj.class(), vm).map_err(|_| vm.new_type_error("cannot pickle object"))?;
|
||||
let slot_names = type_slot_names(obj.class(), vm)?;
|
||||
|
||||
if required {
|
||||
// Dict, weakref list, and slot cells sit in the prefix in front of
|
||||
|
||||
Reference in new issue
Block a user