From b6e061b652bbc2b08255d7755bc7477a459ca72b Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Tue, 13 Aug 2019 21:12:05 -0500 Subject: [PATCH] Add nice message for no attribute on module --- vm/src/obj/objmodule.rs | 26 +++++++++++++++++++++----- vm/src/obj/objobject.rs | 38 +++++--------------------------------- vm/src/vm.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/vm/src/obj/objmodule.rs b/vm/src/obj/objmodule.rs index b768b454a..cc3f3a596 100644 --- a/vm/src/obj/objmodule.rs +++ b/vm/src/obj/objmodule.rs @@ -18,14 +18,30 @@ impl PyValue for PyModule { } impl PyModuleRef { - fn init(self, name: PyStringRef, vm: &VirtualMachine) -> PyResult { - vm.set_attr(&self.into_object(), "__name__", name)?; - Ok(vm.get_none()) + fn new(cls: PyClassRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult { + let zelf = PyModule { + name: name.as_str().to_owned(), + } + .into_ref_with_type(vm, cls)?; + vm.set_attr(zelf.as_object(), "__name__", name)?; + Ok(zelf) + } + + fn getattribute(self, name: PyStringRef, vm: &VirtualMachine) -> PyResult { + match vm.generic_getattribute(self.as_object().clone(), name.clone()) { + Ok(Some(val)) => Ok(val), + Ok(None) => Err(vm.new_attribute_error(format!( + "module '{}' has no attribute '{}'", + self.name, name, + ))), + Err(err) => Err(err), + } } } pub fn init(context: &PyContext) { - extend_class!(&context, &context.types.module_type, { - "__init__" => context.new_rustfunc(PyModuleRef::init), + extend_class!(&context, &context.module_type, { + "__new__" => context.new_rustfunc(PyModuleRef::new), + "__getattribute__" => context.new_rustfunc(PyModuleRef::getattribute), }); } diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 876c4d778..107f69bb5 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -223,39 +223,11 @@ fn object_dict_setter( )) } -fn object_getattribute(obj: PyObjectRef, name_str: PyStringRef, vm: &VirtualMachine) -> PyResult { - let name = &name_str.value; +fn object_getattribute(obj: PyObjectRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult { vm_trace!("object.__getattribute__({:?}, {:?})", obj, name); - let cls = obj.class(); - - if let Some(attr) = objtype::class_get_attr(&cls, &name) { - let attr_class = attr.class(); - if objtype::class_has_attr(&attr_class, "__set__") { - if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") { - return vm.invoke(&descriptor, vec![attr, obj, cls.into_object()]); - } - } - } - - if let Some(obj_attr) = object_getattr(&obj, &name, &vm)? { - Ok(obj_attr) - } else if let Some(attr) = objtype::class_get_attr(&cls, &name) { - vm.call_get_descriptor(attr, obj) - } else if let Some(ref getter) = objtype::class_get_attr(&cls, "__getattr__") { - vm.invoke(getter, vec![obj, name_str.into_object()]) - } else { - Err(vm.new_attribute_error(format!("{} has no attribute '{}'", obj, name))) - } -} - -fn object_getattr( - obj: &PyObjectRef, - attr_name: &str, - vm: &VirtualMachine, -) -> PyResult> { - if let Some(ref dict) = obj.dict { - dict.get_item_option(attr_name, vm) - } else { - Ok(None) + match vm.generic_getattribute(obj.clone(), name.clone()) { + Ok(Some(val)) => Ok(val), + Ok(None) => Err(vm.new_attribute_error(format!("{} has no attribute '{}'", obj, name))), + Err(err) => Err(err), } } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index bbc066c3f..ed4f3ebeb 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -863,6 +863,43 @@ impl VirtualMachine { }) } + pub fn generic_getattribute( + &self, + obj: PyObjectRef, + name_str: PyStringRef, + ) -> PyResult> { + let name = name_str.as_str(); + let cls = obj.class(); + + if let Some(attr) = objtype::class_get_attr(&cls, &name) { + let attr_class = attr.class(); + if objtype::class_has_attr(&attr_class, "__set__") { + if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") { + return self + .invoke(&descriptor, vec![attr, obj, cls.into_object()]) + .map(Some); + } + } + } + + let attr = if let Some(ref dict) = obj.dict { + dict.get_item_option(name_str.clone(), self)? + } else { + None + }; + + if let Some(obj_attr) = attr { + Ok(Some(obj_attr)) + } else if let Some(attr) = objtype::class_get_attr(&cls, &name) { + self.call_get_descriptor(attr, obj).map(Some) + } else if let Some(getter) = objtype::class_get_attr(&cls, "__getattr__") { + self.invoke(&getter, vec![obj, name_str.into_object()]) + .map(Some) + } else { + Ok(None) + } + } + pub fn is_callable(&self, obj: &PyObjectRef) -> bool { match_class!(obj, PyFunction => true,