From ff30666c69161e30ec5c44446b60042eb932619a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 11 May 2014 19:05:42 +0300 Subject: [PATCH] py: Add basic implementation of hasattr() function. --- py/builtin.c | 15 +++++++++++++++ py/builtin.h | 1 + py/builtintables.c | 1 + py/qstrdefs.h | 1 + tests/basics/hasattr1.py | 29 +++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 tests/basics/hasattr1.py diff --git a/py/builtin.c b/py/builtin.c index 8d5779e42c..7f0d2a4d9f 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -462,6 +462,21 @@ STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr); +STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { + assert(MP_OBJ_IS_QSTR(attr_in)); + + mp_obj_t dest[2]; + // TODO: https://docs.python.org/3.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, MP_OBJ_QSTR_VALUE(attr_in), dest); + + return MP_BOOL(dest[0] != MP_OBJ_NULL); +} + +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); + // These two are defined in terms of MicroPython API functions right away MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get); MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get); diff --git a/py/builtin.h b/py/builtin.h index baf444a208..2929c1018a 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -41,6 +41,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_eval_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_exec_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_getattr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_globals_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hasattr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hash_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hex_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_id_obj); diff --git a/py/builtintables.c b/py/builtintables.c index a1888a6e97..133c14a269 100644 --- a/py/builtintables.c +++ b/py/builtintables.c @@ -90,6 +90,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_exec), (mp_obj_t)&mp_builtin_exec_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_getattr), (mp_obj_t)&mp_builtin_getattr_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_globals), (mp_obj_t)&mp_builtin_globals_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hasattr), (mp_obj_t)&mp_builtin_hasattr_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_hash), (mp_obj_t)&mp_builtin_hash_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_hex), (mp_obj_t)&mp_builtin_hex_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_id), (mp_obj_t)&mp_builtin_id_obj }, diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 13476b3be8..1679d8b39c 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -142,6 +142,7 @@ Q(float) Q(from_bytes) Q(getattr) Q(globals) +Q(hasattr) Q(hash) Q(hex) Q(%#x) diff --git a/tests/basics/hasattr1.py b/tests/basics/hasattr1.py new file mode 100644 index 0000000000..b1c4b5ceb6 --- /dev/null +++ b/tests/basics/hasattr1.py @@ -0,0 +1,29 @@ +class A: + + var = 132 + + def __init__(self): + self.var2 = 34 + + def meth(self, i): + return 42 + i + + +a = A() +print(hasattr(a, "var")) +print(hasattr(a, "var2")) +print(hasattr(a, "meth")) +print(hasattr(a, "_none_such")) +print(hasattr(list, "foo")) + +class C: + + def __getattr__(self, attr): + if attr == "exists": + return attr + raise AttributeError + +c = C() +print(hasattr(c, "exists")) +# TODO +#print(hasattr(c, "doesnt_exist"))