=?utf-8?q?=5Bpygobject=5D_Accept_=C2=B1inf_and_NaN_as_float_and_double_va?= =?utf-8?q?lues?=



commit e65c124893ceaa9c97eb4c8c743fbeb756b9a6e6
Author: Martin Pitt <martinpitt gnome org>
Date:   Wed Jan 23 14:56:02 2013 +0100

    Accept Âinf and NaN as float and double values
    
    Also fix the broken error message when a float value is out of range.
    PyErr_Format() does not support float macros.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=692381

 gi/pygi-marshal-from-py.c |   37 +++++++++++++++++++------------------
 tests/test_gobject.py     |   14 ++++++++++++++
 2 files changed, 33 insertions(+), 18 deletions(-)
---
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index a676123..c14455c 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -659,6 +659,23 @@ _pygi_marshal_from_py_uint64 (PyGIInvokeState   *state,
     return TRUE;
 }
 
+static gboolean
+check_valid_double (double x, double min, double max)
+{
+    char buf[100];
+
+    if ((x < min || x > max) && x != INFINITY && x != -INFINITY && x != NAN) {
+        if (PyErr_Occurred())
+            PyErr_Clear ();
+
+        /* we need this as PyErr_Format() does not support float types */
+        snprintf (buf, sizeof (buf), "%g not in range %g to %g", x, min, max);
+        PyErr_SetString (PyExc_ValueError, buf);
+        return FALSE;
+    }
+    return TRUE;
+}
+
 gboolean
 _pygi_marshal_from_py_float (PyGIInvokeState   *state,
                              PyGICallableCache *callable_cache,
@@ -682,16 +699,8 @@ _pygi_marshal_from_py_float (PyGIInvokeState   *state,
     double_ = PyFloat_AsDouble (py_float);
     Py_DECREF (py_float);
 
-    if (PyErr_Occurred ()) {
-        PyErr_Clear ();
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
-        return FALSE;
-    }
-
-    if (double_ < -G_MAXFLOAT || double_ > G_MAXFLOAT) {
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
+    if (PyErr_Occurred () || !check_valid_double (double_, -G_MAXFLOAT, G_MAXFLOAT))
         return FALSE;
-    }
 
     arg->v_float = double_;
 
@@ -721,16 +730,8 @@ _pygi_marshal_from_py_double (PyGIInvokeState   *state,
     double_ = PyFloat_AsDouble (py_float);
     Py_DECREF (py_float);
 
-    if (PyErr_Occurred ()) {
-        PyErr_Clear ();
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
+    if (PyErr_Occurred () || !check_valid_double (double_, -G_MAXDOUBLE, G_MAXDOUBLE))
         return FALSE;
-    }
-
-    if (double_ < -G_MAXDOUBLE || double_ > G_MAXDOUBLE) {
-        PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
-        return FALSE;
-    }
 
     arg->v_double = double_;
 
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index a05d758..ec4cb44 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -624,10 +624,24 @@ class TestGValue(unittest.TestCase):
         # python float is G_TYPE_DOUBLE
         value = GObject.Value(float, 23.4)
         self.assertEqual(value.g_type, GObject.TYPE_DOUBLE)
+        value.set_value(1e50)
+        self.assertAlmostEqual(value.get_value(), 1e50)
 
         value = GObject.Value(GObject.TYPE_FLOAT, 23.4)
         self.assertEqual(value.g_type, GObject.TYPE_FLOAT)
         self.assertRaises(TypeError, value.set_value, 'string')
+        self.assertRaises(ValueError, value.set_value, 1e50)
+
+    def test_float_inf_nan(self):
+        nan = float('nan')
+        for type_ in [GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE]:
+            for x in [float('inf'), float('-inf'), nan]:
+                value = GObject.Value(type_, x)
+                # assertEqual() is False for (nan, nan)
+                if x is nan:
+                    self.assertEqual(str(value.get_value()), 'nan')
+                else:
+                    self.assertEqual(value.get_value(), x)
 
     def test_enum(self):
         value = GObject.Value(GLib.FileError, GLib.FileError.FAILED)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]