Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r89731:b07132257e83 Date: 2017-01-24 13:32 +0100 http://bitbucket.org/pypy/pypy/changeset/b07132257e83/
Log: cffi issue300: return _Bool as Python booleans; related fixes diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -370,6 +370,19 @@ # bypass the method 'string' implemented in W_CTypePrimitive return W_CType.string(self, cdataobj, maxlen) + def convert_to_object(self, cdata): + space = self.space + value = ord(cdata[0]) + if value < 2: + return space.newbool(value != 0) + else: + raise oefmt(space.w_ValueError, + "got a _Bool of value %d, expected 0 or 1", + value) + + def unpack_list_of_int_items(self, ptr, length): + return None + class W_CTypePrimitiveFloat(W_CTypePrimitive): _attrs_ = [] 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 @@ -82,6 +82,8 @@ raise oefmt(space.w_IndexError, "initializer string is too long for '%s' (got %d " "characters)", self.name, n) + if isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveBool): + self._must_be_string_of_zero_or_one(s) copy_string_to_raw(llstr(s), cdata, 0, n) if n != self.length: cdata[n] = '\x00' @@ -101,9 +103,16 @@ else: raise self._convert_error("list or tuple", w_ob) + def _must_be_string_of_zero_or_one(self, s): + for c in s: + if ord(c) > 1: + raise oefmt(self.space.w_ValueError, + "an array of _Bool can only contain \\x00 or \\x01") + def string(self, cdataobj, maxlen): space = self.space - if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive): + if (isinstance(self.ctitem, ctypeprim.W_CTypePrimitive) and + not isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveBool)): with cdataobj as ptr: if not ptr: raise oefmt(space.w_RuntimeError, @@ -283,6 +292,8 @@ if self.accept_str and space.isinstance_w(w_init, space.w_str): # special case to optimize strings passed to a "char *" argument value = w_init.str_w(space) + if isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveBool): + self._must_be_string_of_zero_or_one(value) keepalives[i] = value buf, buf_flag = rffi.get_nonmovingbuffer_final_null(value) rffi.cast(rffi.CCHARPP, cdata)[0] = buf 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 @@ -885,6 +885,15 @@ py.test.raises(OverflowError, f, 128, 0) py.test.raises(OverflowError, f, 0, 128) +def test_call_function_0_pretend_bool_result(): + BSignedChar = new_primitive_type("signed char") + BBool = new_primitive_type("_Bool") + BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False) + f = cast(BFunc0, _testfunc(0)) + assert f(40, -39) is True + assert f(40, -40) is False + py.test.raises(ValueError, f, 40, 2) + def test_call_function_1(): BInt = new_primitive_type("int") BLong = new_primitive_type("long") @@ -1047,6 +1056,17 @@ res = f(b"foo") assert res == 1000 * ord(b'f') +def test_call_function_23_bool_array(): + # declaring the function as int(_Bool*) + BBool = new_primitive_type("_Bool") + BBoolP = new_pointer_type(BBool) + BInt = new_primitive_type("int") + BFunc23 = new_function_type((BBoolP,), BInt, False) + f = cast(BFunc23, _testfunc(23)) + res = f(b"\x01\x01") + assert res == 1000 + py.test.raises(ValueError, f, b"\x02\x02") + def test_cannot_pass_struct_with_array_of_length_0(): BInt = new_primitive_type("int") BArray0 = new_array_type(new_pointer_type(BInt), 0) @@ -2617,13 +2637,38 @@ py.test.raises(OverflowError, newp, BBoolP, 2) py.test.raises(OverflowError, newp, BBoolP, -1) BCharP = new_pointer_type(new_primitive_type("char")) - p = newp(BCharP, b'X') + p = newp(BCharP, b'\x01') q = cast(BBoolP, p) - assert q[0] == ord(b'X') + assert q[0] is True + p = newp(BCharP, b'\x00') + q = cast(BBoolP, p) + assert q[0] is False py.test.raises(TypeError, string, cast(BBool, False)) BDouble = new_primitive_type("double") assert int(cast(BBool, cast(BDouble, 0.1))) == 1 assert int(cast(BBool, cast(BDouble, 0.0))) == 0 + BBoolA = new_array_type(BBoolP, None) + p = newp(BBoolA, b'\x01\x00') + assert p[0] is True + assert p[1] is False + +def test_bool_forbidden_cases(): + BBool = new_primitive_type("_Bool") + BBoolP = new_pointer_type(BBool) + BBoolA = new_array_type(BBoolP, None) + BCharP = new_pointer_type(new_primitive_type("char")) + p = newp(BCharP, b'X') + q = cast(BBoolP, p) + py.test.raises(ValueError, "q[0]") + py.test.raises(TypeError, newp, BBoolP, b'\x00') + assert newp(BBoolP, 0)[0] is False + assert newp(BBoolP, 1)[0] is True + py.test.raises(OverflowError, newp, BBoolP, 2) + py.test.raises(OverflowError, newp, BBoolP, -1) + py.test.raises(ValueError, newp, BBoolA, b'\x00\x01\x02') + py.test.raises(OverflowError, newp, BBoolA, [0, 1, 2]) + py.test.raises(TypeError, string, newp(BBoolP, 1)) + py.test.raises(TypeError, string, newp(BBoolA, [1])) def test_typeoffsetof(): BChar = new_primitive_type("char") @@ -3663,7 +3708,7 @@ ("int16_t", [-2**15, 2**15-1]), ("int32_t", [-2**31, 2**31-1]), ("int64_t", [-2**63, 2**63-1]), - ("_Bool", [0, 1]), + ("_Bool", [False, True]), ("float", [0.0, 10.5]), ("double", [12.34, 56.78]), ]: diff --git a/pypy/module/_cffi_backend/test/test_fastpath.py b/pypy/module/_cffi_backend/test/test_fastpath.py --- a/pypy/module/_cffi_backend/test/test_fastpath.py +++ b/pypy/module/_cffi_backend/test/test_fastpath.py @@ -109,9 +109,8 @@ P_BOOL = _cffi_backend.new_pointer_type(BOOL) BOOL_ARRAY = _cffi_backend.new_array_type(P_BOOL, None) buf = _cffi_backend.newp(BOOL_ARRAY, [1, 0]) - assert buf[0] == 1 - assert buf[1] == 0 - assert type(buf[1]) is int + assert buf[0] is True + assert buf[1] is False raises(OverflowError, _cffi_backend.newp, BOOL_ARRAY, [2]) raises(OverflowError, _cffi_backend.newp, BOOL_ARRAY, [-1]) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit