mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Improve CPython compatibility related with PyBoundMethod (#7476)
* Add GetDescriptor for PyBoundMethod (return self) CPython's method_descr_get always returns the bound method unchanged. This preserves the original binding when __get__ is called on an already-bound method (e.g. a.meth.__get__(b, B) still returns a). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add constructor validation for PyBoundMethod Reject non-callable functions and None instances, matching CPython's method_new which checks PyCallable_Check(func) and instance != Py_None. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix PyBoundMethod __reduce__ to propagate errors Previously swallowed errors from get_attr with .ok(), silently returning None. Now propagates errors matching CPython's method_reduce. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fb0d5faf3f
commit
4d99a4e541
2 files changed
+31
-7
No files matched your search
Vendored
-1
@@ -5130,7 +5130,6 @@ class ClassPropertiesAndMethods(unittest.TestCase):
|
||||
gc.collect()
|
||||
self.assertEqual(Parent.__subclasses__(), [])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_instance_method_get_behavior(self):
|
||||
# test case for gh-113157
|
||||
|
||||
|
||||
@@ -1216,6 +1216,17 @@ impl GetAttr for PyBoundMethod {
|
||||
}
|
||||
}
|
||||
|
||||
impl GetDescriptor for PyBoundMethod {
|
||||
fn descr_get(
|
||||
zelf: PyObjectRef,
|
||||
_obj: Option<PyObjectRef>,
|
||||
_cls: Option<PyObjectRef>,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
Ok(zelf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
pub struct PyBoundMethodNewArgs {
|
||||
#[pyarg(positional)]
|
||||
@@ -1230,8 +1241,14 @@ impl Constructor for PyBoundMethod {
|
||||
fn py_new(
|
||||
_cls: &Py<PyType>,
|
||||
Self::Args { function, object }: Self::Args,
|
||||
_vm: &VirtualMachine,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Self> {
|
||||
if !function.is_callable() {
|
||||
return Err(vm.new_type_error("first argument must be callable".to_owned()));
|
||||
}
|
||||
if vm.is_none(&object) {
|
||||
return Err(vm.new_type_error("instance must not be None".to_owned()));
|
||||
}
|
||||
Ok(Self::new(object, function))
|
||||
}
|
||||
}
|
||||
@@ -1258,7 +1275,15 @@ impl PyBoundMethod {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
with(Callable, Comparable, Hashable, GetAttr, Constructor, Representable),
|
||||
with(
|
||||
Callable,
|
||||
Comparable,
|
||||
Hashable,
|
||||
GetAttr,
|
||||
GetDescriptor,
|
||||
Constructor,
|
||||
Representable
|
||||
),
|
||||
flags(IMMUTABLETYPE, HAS_WEAKREF)
|
||||
)]
|
||||
impl PyBoundMethod {
|
||||
@@ -1266,11 +1291,11 @@ impl PyBoundMethod {
|
||||
fn __reduce__(
|
||||
&self,
|
||||
vm: &VirtualMachine,
|
||||
) -> (Option<PyObjectRef>, (PyObjectRef, Option<PyObjectRef>)) {
|
||||
let builtins_getattr = vm.builtins.get_attr("getattr", vm).ok();
|
||||
) -> PyResult<(PyObjectRef, (PyObjectRef, PyObjectRef))> {
|
||||
let builtins_getattr = vm.builtins.get_attr("getattr", vm)?;
|
||||
let func_self = self.object.clone();
|
||||
let func_name = self.function.get_attr("__name__", vm).ok();
|
||||
(builtins_getattr, (func_self, func_name))
|
||||
let func_name = self.function.get_attr("__name__", vm)?;
|
||||
Ok((builtins_getattr, (func_self, func_name)))
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
|
||||
Reference in new issue
Block a user