Skip to content

Commit a8c9703

Browse files
authored
classmethod copy attrs (#5831)
1 parent 9c2a469 commit a8c9703

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

Lib/test/test_descr.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,8 +1558,6 @@ class B(A1, A2):
15581558
else:
15591559
self.fail("finding the most derived metaclass should have failed")
15601560

1561-
# TODO: RUSTPYTHON
1562-
@unittest.expectedFailure
15631561
def test_classmethods(self):
15641562
# Testing class methods...
15651563
class C(object):

vm/src/builtins/classmethod.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,34 @@ impl Constructor for PyClassMethod {
6767
type Args = PyObjectRef;
6868

6969
fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult {
70-
let doc = callable.get_attr("__doc__", vm);
70+
// Create a dictionary to hold copied attributes
71+
let dict = vm.ctx.new_dict();
7172

72-
let result = PyClassMethod {
73-
callable: PyMutex::new(callable),
73+
// Copy attributes from the callable to the dict
74+
// This is similar to functools.wraps in CPython
75+
if let Ok(doc) = callable.get_attr("__doc__", vm) {
76+
dict.set_item(identifier!(vm.ctx, __doc__), doc, vm)?;
7477
}
75-
.into_ref_with_type(vm, cls)?;
76-
let obj = PyObjectRef::from(result);
77-
78-
if let Ok(doc) = doc {
79-
obj.set_attr("__doc__", doc, vm)?;
78+
if let Ok(name) = callable.get_attr("__name__", vm) {
79+
dict.set_item(identifier!(vm.ctx, __name__), name, vm)?;
80+
}
81+
if let Ok(qualname) = callable.get_attr("__qualname__", vm) {
82+
dict.set_item(identifier!(vm.ctx, __qualname__), qualname, vm)?;
83+
}
84+
if let Ok(module) = callable.get_attr("__module__", vm) {
85+
dict.set_item(identifier!(vm.ctx, __module__), module, vm)?;
8086
}
87+
if let Ok(annotations) = callable.get_attr("__annotations__", vm) {
88+
dict.set_item(identifier!(vm.ctx, __annotations__), annotations, vm)?;
89+
}
90+
91+
// Create PyClassMethod instance with the pre-populated dict
92+
let classmethod = PyClassMethod {
93+
callable: PyMutex::new(callable),
94+
};
8195

82-
Ok(obj)
96+
let result = PyRef::new_ref(classmethod, cls, Some(dict));
97+
Ok(PyObjectRef::from(result))
8398
}
8499
}
85100

0 commit comments

Comments
 (0)