mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Added bunch af attribute has/get/set/delete tests and fixed getattr and
hasattr handling of exceptions.
This commit is contained in:
84
tests/snippets/attr.py
Normal file
84
tests/snippets/attr.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from testutils import assertRaises
|
||||
|
||||
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
a = A()
|
||||
a.b = 10
|
||||
assert hasattr(a, 'b')
|
||||
assert a.b == 10
|
||||
|
||||
# test override attribute
|
||||
setattr(a, 'b', 12)
|
||||
assert a.b == 12
|
||||
assert getattr(a, 'b') == 12
|
||||
|
||||
# test non-existent attribute
|
||||
with assertRaises(AttributeError):
|
||||
_ = a.c
|
||||
|
||||
with assertRaises(AttributeError):
|
||||
getattr(a, 'c')
|
||||
|
||||
assert getattr(a, 'c', 21) == 21
|
||||
|
||||
# test set attribute
|
||||
setattr(a, 'c', 20)
|
||||
assert hasattr(a, 'c')
|
||||
assert a.c == 20
|
||||
|
||||
# test delete attribute
|
||||
delattr(a, 'c')
|
||||
assert not hasattr(a, 'c')
|
||||
with assertRaises(AttributeError):
|
||||
_ = a.c
|
||||
|
||||
# test setting attribute on builtin
|
||||
with assertRaises(AttributeError):
|
||||
None.a = 1
|
||||
|
||||
with assertRaises(AttributeError):
|
||||
setattr(None, 'a', 2)
|
||||
|
||||
|
||||
attrs = {}
|
||||
|
||||
|
||||
class CustomLookup:
|
||||
def __getattr__(self, item):
|
||||
return "value_{}".format(item)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
attrs[key] = value
|
||||
|
||||
|
||||
custom = CustomLookup()
|
||||
|
||||
assert custom.attr == "value_attr"
|
||||
|
||||
custom.a = 2
|
||||
custom.b = 5
|
||||
assert attrs == {'a': 2, 'b': 5}
|
||||
|
||||
|
||||
class GetRaise:
|
||||
def __init__(self, ex):
|
||||
self.ex = ex
|
||||
|
||||
def __getattr__(self, item):
|
||||
raise self.ex
|
||||
|
||||
|
||||
assert not hasattr(GetRaise(AttributeError()), 'a')
|
||||
with assertRaises(AttributeError):
|
||||
getattr(GetRaise(AttributeError()), 'a')
|
||||
assert getattr(GetRaise(AttributeError()), 'a', 11) == 11
|
||||
|
||||
with assertRaises(KeyError):
|
||||
hasattr(GetRaise(KeyError()), 'a')
|
||||
with assertRaises(KeyError):
|
||||
getattr(GetRaise(KeyError()), 'a')
|
||||
with assertRaises(KeyError):
|
||||
getattr(GetRaise(KeyError()), 'a', 11)
|
||||
@@ -18,7 +18,7 @@ use crate::obj::objstr::{self, PyStringRef};
|
||||
use crate::obj::objtype;
|
||||
|
||||
use crate::frame::Scope;
|
||||
use crate::function::{Args, PyFuncArgs};
|
||||
use crate::function::{Args, OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
AttributeProtocol, IdProtocol, PyContext, PyObjectRef, PyResult, TypeProtocol,
|
||||
};
|
||||
@@ -302,30 +302,38 @@ fn builtin_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
vm.call_method(obj, "__format__", vec![format_spec])
|
||||
}
|
||||
|
||||
fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
|
||||
);
|
||||
vm.get_attribute(obj.clone(), attr.clone())
|
||||
fn catch_attr_exception<T>(ex: PyObjectRef, default: T, vm: &mut VirtualMachine) -> PyResult<T> {
|
||||
if objtype::isinstance(&ex, &vm.ctx.exceptions.attribute_error) {
|
||||
Ok(default)
|
||||
} else {
|
||||
Err(ex)
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_getattr(
|
||||
obj: PyObjectRef,
|
||||
attr: PyStringRef,
|
||||
default: OptionalArg<PyObjectRef>,
|
||||
vm: &mut VirtualMachine,
|
||||
) -> PyResult {
|
||||
let ret = vm.get_attribute(obj.clone(), attr.into_object());
|
||||
if let OptionalArg::Present(default) = default {
|
||||
ret.or_else(|ex| catch_attr_exception(ex, default, vm))
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_globals(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.current_scope().globals.clone())
|
||||
}
|
||||
|
||||
fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(obj, None), (attr, Some(vm.ctx.str_type()))]
|
||||
);
|
||||
let has_attr = match vm.get_attribute(obj.clone(), attr.clone()) {
|
||||
Ok(..) => true,
|
||||
Err(..) => false,
|
||||
};
|
||||
Ok(vm.context().new_bool(has_attr))
|
||||
fn builtin_hasattr(obj: PyObjectRef, attr: PyStringRef, vm: &mut VirtualMachine) -> PyResult<bool> {
|
||||
if let Err(ex) = vm.get_attribute(obj.clone(), attr.into_object()) {
|
||||
catch_attr_exception(ex, false, vm)
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
Reference in New Issue
Block a user