Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit