Author: Armin Rigo <[email protected]>
Branch:
Changeset: r471:01700d5bff2e
Date: 2012-06-19 20:24 +0200
http://bitbucket.org/cffi/cffi/changeset/01700d5bff2e/
Log: Be clearer about refusing float values where we expect integer
cdata's.
diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -320,21 +320,61 @@
/************************************************************/
+static PY_LONG_LONG
+_my_PyLong_AsLongLong(PyObject *ob)
+{
+ /* (possibly) convert and cast a Python object to a long long.
+ Like PyLong_AsLongLong(), this version accepts a Python int too, and
+ does convertions from other types of objects. The difference is that
+ this version refuses floats. */
+ if (PyInt_Check(ob)) {
+ return PyInt_AS_LONG(ob);
+ }
+ else if (PyLong_Check(ob)) {
+ return PyLong_AsLongLong(ob);
+ }
+ else {
+ PyObject *io;
+ PY_LONG_LONG res;
+ PyNumberMethods *nb = ob->ob_type->tp_as_number;
+
+ if (PyFloat_Check(ob) ||
+ nb == NULL || nb->nb_int == NULL) {
+ PyErr_SetString(PyExc_TypeError, "an integer is required");
+ return -1;
+ }
+ io = (*nb->nb_int) (ob);
+ if (io == NULL)
+ return -1;
+
+ if (PyInt_Check(io) || PyLong_Check(io)) {
+ res = _my_PyLong_AsLongLong(io);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "integer conversion failed");
+ res = -1;
+ }
+ Py_DECREF(io);
+ return res;
+ }
+}
+
static unsigned PY_LONG_LONG
-_my_PyLong_AsUnsignedLongLong(PyObject *ob, int overflow)
+_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict)
{
/* (possibly) convert and cast a Python object to an unsigned long long.
- Like PyLong_AsLongLong(), this version accepts a Python int too,
- does convertions from other types of objects. If 'overflow',
- complains with OverflowError; if '!overflow', mask the result. */
+ Like PyLong_AsLongLong(), this version accepts a Python int too, and
+ does convertions from other types of objects. If 'strict', complains
+ with OverflowError and refuses floats. If '!strict', rounds floats
+ and masks the result. */
if (PyInt_Check(ob)) {
long value1 = PyInt_AS_LONG(ob);
- if (overflow && value1 < 0)
+ if (strict && value1 < 0)
goto negative;
return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1;
}
else if (PyLong_Check(ob)) {
- if (overflow) {
+ if (strict) {
if (_PyLong_Sign(ob) < 0)
goto negative;
return PyLong_AsUnsignedLongLong(ob);
@@ -348,7 +388,8 @@
unsigned PY_LONG_LONG res;
PyNumberMethods *nb = ob->ob_type->tp_as_number;
- if (nb == NULL || nb->nb_int == NULL) {
+ if ((strict && PyFloat_Check(ob)) ||
+ nb == NULL || nb->nb_int == NULL) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
return (unsigned PY_LONG_LONG)-1;
}
@@ -356,12 +397,13 @@
if (io == NULL)
return (unsigned PY_LONG_LONG)-1;
- if (!PyInt_Check(io) && !PyLong_Check(io)) {
- Py_DECREF(io);
+ if (PyInt_Check(io) || PyLong_Check(io)) {
+ res = _my_PyLong_AsUnsignedLongLong(io, strict);
+ }
+ else {
PyErr_SetString(PyExc_TypeError, "integer conversion failed");
- return -1;
+ res = (unsigned PY_LONG_LONG)-1;
}
- res = _my_PyLong_AsUnsignedLongLong(io, overflow);
Py_DECREF(io);
return res;
}
@@ -369,7 +411,7 @@
negative:
PyErr_SetString(PyExc_OverflowError,
"can't convert negative number to unsigned");
- return -1;
+ return (unsigned PY_LONG_LONG)-1;
}
static PY_LONG_LONG
@@ -717,7 +759,7 @@
return 0;
}
if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
- PY_LONG_LONG value = PyLong_AsLongLong(init);
+ PY_LONG_LONG value = _my_PyLong_AsLongLong(init);
if (value == -1 && PyErr_Occurred()) {
if (!(ct->ct_flags & CT_IS_ENUM))
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -176,6 +176,13 @@
p = newp(BPtr, 1.1)
assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors
+def test_cast_float_to_int():
+ for type in ["int", "unsigned int", "long", "unsigned long",
+ "long long", "unsigned long long"]:
+ p = new_primitive_type(type)
+ assert int(cast(p, 4.2)) == 4
+ py.test.raises(TypeError, newp, new_pointer_type(p), 4.2)
+
def test_reading_pointer_to_char():
BChar = new_primitive_type("char")
py.test.raises(TypeError, newp, BChar, None)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit