diff --git a/py/modbuiltins.c b/py/modbuiltins.c index e45c714e9b..2f35264159 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -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) { qstr attr = mp_obj_str_get_qstr(attr_in); - mp_obj_t dest[2]; - // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr - // 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); - + mp_load_method_protected(object_in, attr, dest, false); return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); diff --git a/tests/basics/builtin_hasattr.py b/tests/basics/builtin_hasattr.py index 118a19e579..c60033b963 100644 --- a/tests/basics/builtin_hasattr.py +++ b/tests/basics/builtin_hasattr.py @@ -21,12 +21,19 @@ class C: def __getattr__(self, attr): if attr == "exists": return attr + elif attr == "raise": + raise Exception(123) raise AttributeError c = C() 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: hasattr(1, b'123')