}
""")
+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
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', "", "", ""),
--- /dev/null
+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)