Skip to content

Commit 5298606

Browse files
committed
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.
1 parent bc87b86 commit 5298606

2 files changed

Lines changed: 10 additions & 9 deletions

File tree

‎py/modbuiltins.c‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -525,14 +525,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr);
525525

526526
STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
527527
qstr attr = mp_obj_str_get_qstr(attr_in);
528-
529528
mp_obj_t dest[2];
530-
// TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr
531-
// explicitly says "This is implemented by calling getattr(object, name) and seeing
532-
// whether it raises an AttributeError or not.", so we should explicitly wrap this
533-
// in nlr_push and handle exception.
534-
mp_load_method_maybe(object_in, attr, dest);
535-
529+
mp_load_method_protected(object_in, attr, dest, false);
536530
return mp_obj_new_bool(dest[0] != MP_OBJ_NULL);
537531
}
538532
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);

‎tests/basics/builtin_hasattr.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,19 @@ class C:
2121
def __getattr__(self, attr):
2222
if attr == "exists":
2323
return attr
24+
elif attr == "raise":
25+
raise Exception(123)
2426
raise AttributeError
2527

2628
c = C()
2729
print(hasattr(c, "exists"))
28-
# TODO
29-
#print(hasattr(c, "doesnt_exist"))
30+
print(hasattr(c, "doesnt_exist"))
31+
32+
# ensure that non-AttributeError exceptions propagate out of hasattr
33+
try:
34+
hasattr(c, "raise")
35+
except Exception as er:
36+
print(er)
3037

3138
try:
3239
hasattr(1, b'123')

0 commit comments

Comments
 (0)