Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r89754:f6c083857478 Date: 2017-01-25 00:53 +0100 http://bitbucket.org/pypy/pypy/changeset/f6c083857478/
Log: update to cffi/ece6f0f2da93 diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -323,17 +323,28 @@ # return self._add_or_sub(w_other, -1) - def getcfield(self, w_attr): - return self.ctype.getcfield(self.space.str_w(w_attr)) + def getcfield(self, w_attr, mode): + space = self.space + attr = space.str_w(w_attr) + try: + cfield = self.ctype.getcfield(attr) + except KeyError: + raise oefmt(space.w_AttributeError, "cdata '%s' has no field '%s'", + self.ctype.name, attr) + if cfield is None: + raise oefmt(space.w_AttributeError, + "cdata '%s' points to an opaque type: cannot %s fields", + self.ctype.name, mode) + return cfield def getattr(self, w_attr): - cfield = self.getcfield(w_attr) + cfield = self.getcfield(w_attr, mode="read") with self as ptr: w_res = cfield.read(ptr, self) return w_res def setattr(self, w_attr, w_value): - cfield = self.getcfield(w_attr) + cfield = self.getcfield(w_attr, mode="write") with self as ptr: cfield.write(ptr, w_value) diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -345,7 +345,10 @@ return result def getcfield(self, attr): - return self.ctitem.getcfield(attr) + from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion + if isinstance(self.ctitem, W_CTypeStructOrUnion): + return self.ctitem.getcfield(attr) + return W_CType.getcfield(self, attr) def typeoffsetof_field(self, fieldname, following): if following == 0: diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -161,18 +161,18 @@ return self._fields_dict[attr] def getcfield(self, attr): - ready = self._fields_dict is not None - if not ready and self.size >= 0: + # Returns a W_CField. Error cases: returns None if we are an + # opaque struct; or raises KeyError if the particular field + # 'attr' does not exist. The point of not directly building the + # error here is to get the exact ctype in the error message: it + # might be of the kind 'struct foo' or 'struct foo *'. + if self._fields_dict is None: + if self.size < 0: + return None self.force_lazy_struct() - ready = True - if ready: - self = jit.promote(self) - attr = jit.promote_string(attr) - try: - return self._getcfield_const(attr) - except KeyError: - pass - return W_CType.getcfield(self, attr) + self = jit.promote(self) + attr = jit.promote_string(attr) + return self._getcfield_const(attr) # <= KeyError here def cdata_dir(self): if self.size < 0: diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -737,8 +737,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) @@ -749,8 +755,29 @@ 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'" + pp = newp(new_pointer_type(BStructPtr), p) + e = py.test.raises(AttributeError, "pp.a1") + assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'" + e = py.test.raises(AttributeError, "pp.a1 = 42") + assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'" def test_union_instance(): BInt = new_primitive_type("int") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit