From dcb8fb44762d6f79ea4201392a7260c742527ffe Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 24 Jun 2025 16:04:25 +0900 Subject: [PATCH] classmethod copy attrs --- Lib/test/test_descr.py | 2 -- vm/src/builtins/classmethod.rs | 33 ++++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 10f11414a8..af0c3acb61 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1558,8 +1558,6 @@ class B(A1, A2): else: self.fail("finding the most derived metaclass should have failed") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_classmethods(self): # Testing class methods... class C(object): diff --git a/vm/src/builtins/classmethod.rs b/vm/src/builtins/classmethod.rs index 94b6e0ca9f..42ca28a24d 100644 --- a/vm/src/builtins/classmethod.rs +++ b/vm/src/builtins/classmethod.rs @@ -67,19 +67,34 @@ impl Constructor for PyClassMethod { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { - let doc = callable.get_attr("__doc__", vm); + // Create a dictionary to hold copied attributes + let dict = vm.ctx.new_dict(); - let result = PyClassMethod { - callable: PyMutex::new(callable), + // Copy attributes from the callable to the dict + // This is similar to functools.wraps in CPython + if let Ok(doc) = callable.get_attr("__doc__", vm) { + dict.set_item(identifier!(vm.ctx, __doc__), doc, vm)?; } - .into_ref_with_type(vm, cls)?; - let obj = PyObjectRef::from(result); - - if let Ok(doc) = doc { - obj.set_attr("__doc__", doc, vm)?; + if let Ok(name) = callable.get_attr("__name__", vm) { + dict.set_item(identifier!(vm.ctx, __name__), name, vm)?; + } + if let Ok(qualname) = callable.get_attr("__qualname__", vm) { + dict.set_item(identifier!(vm.ctx, __qualname__), qualname, vm)?; + } + if let Ok(module) = callable.get_attr("__module__", vm) { + dict.set_item(identifier!(vm.ctx, __module__), module, vm)?; } + if let Ok(annotations) = callable.get_attr("__annotations__", vm) { + dict.set_item(identifier!(vm.ctx, __annotations__), annotations, vm)?; + } + + // Create PyClassMethod instance with the pre-populated dict + let classmethod = PyClassMethod { + callable: PyMutex::new(callable), + }; - Ok(obj) + let result = PyRef::new_ref(classmethod, cls, Some(dict)); + Ok(PyObjectRef::from(result)) } }