[pypy-commit] cffi default: Improve the error message for getattr/setattr
arigo
pypy.commits at gmail.com
Tue Jan 24 18:25:40 EST 2017
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r2873:8f9136ac88e6
Date: 2017-01-25 00:25 +0100
http://bitbucket.org/cffi/cffi/changeset/8f9136ac88e6/
Log: Improve the error message for getattr/setattr
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -455,6 +455,8 @@
static PyObject *
get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */
+/* returns 0 if the struct ctype is opaque, 1 if it is not, or -1 if
+ an exception occurs */
#define force_lazy_struct(ct) \
((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct))
@@ -2452,11 +2454,26 @@
return _cdata_add_or_sub(v, w, -1);
}
+static void
+_cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr)
+{
+ char *text;
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ return;
+ PyErr_Clear();
+ text = PyText_AsUTF8(attr);
+ if (text == NULL)
+ return;
+ PyErr_Format(PyExc_AttributeError, errmsg, cd->c_type->ct_name, text);
+}
+
static PyObject *
cdata_getattro(CDataObject *cd, PyObject *attr)
{
CFieldObject *cf;
CTypeDescrObject *ct = cd->c_type;
+ char *errmsg = "cdata '%s' has no attribute '%s'";
+ PyObject *x;
if (ct->ct_flags & CT_POINTER)
ct = ct->ct_itemdescr;
@@ -2488,14 +2505,19 @@
return new_simple_cdata(data,
(CTypeDescrObject *)cf->cf_type->ct_stuff);
}
+ errmsg = "cdata '%s' has no field '%s'";
break;
case -1:
return NULL;
default:
+ errmsg = "cdata '%s' points to an opaque type: cannot read fields";
break;
}
}
- return PyObject_GenericGetAttr((PyObject *)cd, attr);
+ x = PyObject_GenericGetAttr((PyObject *)cd, attr);
+ if (x == NULL)
+ _cdata_attr_errmsg(errmsg, cd, attr);
+ return x;
}
static int
@@ -2503,6 +2525,8 @@
{
CFieldObject *cf;
CTypeDescrObject *ct = cd->c_type;
+ char *errmsg = "cdata '%s' has no attribute '%s'";
+ int x;
if (ct->ct_flags & CT_POINTER)
ct = ct->ct_itemdescr;
@@ -2522,14 +2546,19 @@
return -1;
}
}
+ errmsg = "cdata '%s' has no field '%s'";
break;
case -1:
return -1;
default:
+ errmsg = "cdata '%s' points to an opaque type: cannot write fields";
break;
}
}
- return PyObject_GenericSetAttr((PyObject *)cd, attr, value);
+ x = PyObject_GenericSetAttr((PyObject *)cd, attr, value);
+ if (x < 0)
+ _cdata_attr_errmsg(errmsg, cd, attr);
+ return x;
}
static PyObject *
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -748,8 +748,14 @@
BInt = new_primitive_type("int")
BStruct = new_struct_type("struct foo")
BStructPtr = new_pointer_type(BStruct)
- p = cast(BStructPtr, 0)
- py.test.raises(AttributeError, "p.a1") # opaque
+ p = cast(BStructPtr, 42)
+ e = py.test.raises(AttributeError, "p.a1") # opaque
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+ "cannot read fields")
+ e = py.test.raises(AttributeError, "p.a1 = 10") # opaque
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+ "cannot write fields")
+
complete_struct_or_union(BStruct, [('a1', BInt, -1),
('a2', BInt, -1)])
p = newp(BStructPtr, None)
@@ -760,8 +766,24 @@
assert s.a2 == 123
py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
assert s.a1 == 0
- py.test.raises(AttributeError, "p.foobar")
- py.test.raises(AttributeError, "s.foobar")
+ e = py.test.raises(AttributeError, "p.foobar")
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "p.foobar = 42")
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "s.foobar")
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "s.foobar = 42")
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ j = cast(BInt, 42)
+ e = py.test.raises(AttributeError, "j.foobar")
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ e = py.test.raises(AttributeError, "j.foobar = 42")
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ j = cast(new_pointer_type(BInt), 42)
+ e = py.test.raises(AttributeError, "j.foobar")
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
+ e = py.test.raises(AttributeError, "j.foobar = 42")
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
def test_union_instance():
BInt = new_primitive_type("int")
More information about the pypy-commit
mailing list