diff --git a/tests/snippets/class.py b/tests/snippets/class.py index ffb8335886..d35f9b36b6 100644 --- a/tests/snippets/class.py +++ b/tests/snippets/class.py @@ -33,6 +33,10 @@ def get_x(self): assert __class__ is Bar return self.x + def doc_func(self): + "doc string" + pass + @classmethod def fubar(cls, x): assert __class__ is cls @@ -48,6 +52,8 @@ def kungfu(x): assert Bar.__doc__ == " W00t " bar = Bar(42) +assert bar.get_x.__doc__ == None +assert bar.doc_func.__doc__ == "doc string" bar.fubar(2) Bar.fubar(2) diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 2af9f0362f..5742a95536 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,5 +1,6 @@ use super::objcode::PyCodeRef; use super::objdict::PyDictRef; +use super::objstr::PyStringRef; use super::objtuple::PyTupleRef; use super::objtype::PyClassRef; use crate::function::PyFuncArgs; @@ -69,6 +70,10 @@ impl PyMethod { pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self { PyMethod { object, function } } + + fn getattribute(&self, name: PyStringRef, vm: &VirtualMachine) -> PyResult { + vm.get_attribute(self.function.clone(), name.clone()) + } } impl PyValue for PyMethod { @@ -92,6 +97,11 @@ pub fn init(context: &PyContext) { "__get__" => context.new_rustfunc(bind_method), "__call__" => context.new_rustfunc(PyFunctionRef::call), }); + + let method_type = &context.types.bound_method_type; + extend_class!(context, method_type, { + "__getattribute__" => context.new_rustfunc(PyMethod::getattribute), + }); } fn bind_method( diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index ccf5ce4f73..a3f781284e 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -321,12 +321,7 @@ fn type_new_slot(metatype: PyClassRef, args: PyFuncArgs, vm: &VirtualMachine) -> bases }; - let mut attributes = dict.to_attributes(); - - // insert __doc__ as None if it is not included in attributes - if !attributes.contains_key("__doc__") { - attributes.insert("__doc__".to_string(), vm.ctx.none()); - } + let attributes = dict.to_attributes(); let mut winner = metatype.clone(); for base in &bases {