From 90120314bcc8bd5a4f71f2629e1065f5c943071c Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Tue, 22 Feb 2011 21:57:11 -0300 Subject: [PATCH] fix builtin hasattr() to suppress only AttributeError exceptions --- Cython/Compiler/Builtin.py | 22 +++++++++++++++++++++- tests/run/hasattr.pyx | 29 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/run/hasattr.pyx diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index 7c882724..d9c4207e 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -76,6 +76,25 @@ bad: } """) +hasattr_utility_code = UtilityCode( +proto = """ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); /*proto*/ +""", +impl = """ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *v = PyObject_GetAttr(o, n); + if (v) { + Py_DECREF(v); + return 1; + } + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + return 0; + } + return -1; +} +""") + pyexec_utility_code = UtilityCode( proto = """ #if PY_VERSION_HEX < 0x02040000 @@ -365,7 +384,8 @@ builtin_function_table = [ utility_code = getattr3_utility_code), BuiltinFunction('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr", utility_code = getattr3_utility_code), # Pyrex compatibility - BuiltinFunction('hasattr', "OO", "b", "PyObject_HasAttr"), + BuiltinFunction('hasattr', "OO", "b", "__Pyx_HasAttr", + utility_code = hasattr_utility_code), BuiltinFunction('hash', "O", "h", "PyObject_Hash"), #('hex', "", "", ""), #('id', "", "", ""), diff --git a/tests/run/hasattr.pyx b/tests/run/hasattr.pyx new file mode 100644 index 00000000..de130ab9 --- /dev/null +++ b/tests/run/hasattr.pyx @@ -0,0 +1,29 @@ +class Foo: + @property + def foo(self): + return None + @property + def bar(self): + raise AttributeError + @property + def baz(self): + return int(1)/int(0) + +def wrap_hasattr(obj, name): + """ + >>> wrap_hasattr(None, "abc") + False + >>> wrap_hasattr(list, "append") + True + >>> wrap_hasattr(Foo(), "foo") + True + >>> wrap_hasattr(Foo(), "spam") + False + >>> wrap_hasattr(Foo(), "bar") + False + >>> wrap_hasattr(Foo(), "baz") #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ZeroDivisionError: ... + """ + return hasattr(obj, name) -- 2.26.2