From aa1650046e6035f6ac158cfa6d8c0fce804903e6 Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Fri, 13 Mar 2026 22:45:16 +0900 Subject: [PATCH] Fix classmethod descr_get to match CPython behavior Simplify classmethod.__get__ to always create a PyBoundMethod binding the callable to the class, matching CPython's cm_descr_get which simply calls PyMethod_New(cm->cm_callable, type). The previous implementation incorrectly tried to call __get__ on the wrapped callable, which broke when a bound method was passed to classmethod() (e.g. classmethod(A().foo)). --- Lib/test/test_decorators.py | 1 - crates/vm/src/builtins/classmethod.rs | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Lib/test/test_decorators.py b/Lib/test/test_decorators.py index 4da2c13a608..3a4fc959f6f 100644 --- a/Lib/test/test_decorators.py +++ b/Lib/test/test_decorators.py @@ -291,7 +291,6 @@ def bar(): return 42 self.assertEqual(bar(), 42) self.assertEqual(actions, expected_actions) - @unittest.expectedFailure # TODO: RUSTPYTHON def test_bound_function_inside_classmethod(self): class A: def foo(self, cls): diff --git a/crates/vm/src/builtins/classmethod.rs b/crates/vm/src/builtins/classmethod.rs index 3ec1085abc4..9efa12ea0bf 100644 --- a/crates/vm/src/builtins/classmethod.rs +++ b/crates/vm/src/builtins/classmethod.rs @@ -57,13 +57,8 @@ impl GetDescriptor for PyClassMethod { ) -> PyResult { let (zelf, _obj) = Self::_unwrap(&zelf, obj, vm)?; let cls = cls.unwrap_or_else(|| _obj.class().to_owned().into()); - // Clone and release lock before calling Python code to prevent deadlock let callable = zelf.callable.lock().clone(); - let call_descr_get: PyResult = callable.get_attr("__get__", vm); - match call_descr_get { - Err(_) => Ok(PyBoundMethod::new(cls, callable).into_ref(&vm.ctx).into()), - Ok(call_descr_get) => call_descr_get.call((cls.clone(), cls), vm), - } + Ok(PyBoundMethod::new(cls, callable).into_ref(&vm.ctx).into()) } }