py/modbuiltins: Make built-in hasattr work properly for user types.

It now allows __getattr__ in a user type to raise AttributeError when the
attribute does not exist.
This commit is contained in:
Damien George 2018-05-10 23:03:30 +10:00
parent bc87b862fd
commit 529860643b
2 changed files with 10 additions and 9 deletions

View File

@ -525,14 +525,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr);
STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
qstr attr = mp_obj_str_get_qstr(attr_in); qstr attr = mp_obj_str_get_qstr(attr_in);
mp_obj_t dest[2]; mp_obj_t dest[2];
// TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr mp_load_method_protected(object_in, attr, dest, false);
// explicitly says "This is implemented by calling getattr(object, name) and seeing
// whether it raises an AttributeError or not.", so we should explicitly wrap this
// in nlr_push and handle exception.
mp_load_method_maybe(object_in, attr, dest);
return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); return mp_obj_new_bool(dest[0] != MP_OBJ_NULL);
} }
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);

View File

@ -21,12 +21,19 @@ class C:
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == "exists": if attr == "exists":
return attr return attr
elif attr == "raise":
raise Exception(123)
raise AttributeError raise AttributeError
c = C() c = C()
print(hasattr(c, "exists")) print(hasattr(c, "exists"))
# TODO print(hasattr(c, "doesnt_exist"))
#print(hasattr(c, "doesnt_exist"))
# ensure that non-AttributeError exceptions propagate out of hasattr
try:
hasattr(c, "raise")
except Exception as er:
print(er)
try: try:
hasattr(1, b'123') hasattr(1, b'123')