[pygobject] _pygi_argument_from_object(): Check for compatible data type



commit 168a08753cec1ff77ccca5d81b9a5fd2af5d3720
Author: Martin Pitt <martinpitt gnome org>
Date:   Sun May 6 18:02:04 2012 -0700

    _pygi_argument_from_object(): Check for compatible data type
    
    Verify that the passed PyObject actually matches the expected type of the
    argument. With this, trying to assign a wrong type to a property will now raise
    a proper TypeError.

 gi/pygi-argument.c |   39 +++++++++++++++++++++++++++++++++++++++
 gi/pygi-property.c |    3 +++
 tests/test_gi.py   |   40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 0 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 64602f2..ca88911 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -728,6 +728,12 @@ _pygi_argument_from_object (PyObject   *object,
         {
             PyObject *int_;
 
+            if (!PyObject_TypeCheck (object, &PyInt_Type) && 
+                !PyObject_TypeCheck (object, &PyLong_Type)) {
+                PyErr_SetString (PyExc_TypeError, "expected int or long argument");
+                break;
+            }
+
             int_ = PYGLIB_PyNumber_Long (object);
             if (int_ == NULL) {
                 break;
@@ -752,6 +758,12 @@ _pygi_argument_from_object (PyObject   *object,
             PyObject *number;
             guint64 value;
 
+            if (!PyObject_TypeCheck (object, &PyInt_Type) && 
+                !PyObject_TypeCheck (object, &PyLong_Type)) {
+                PyErr_SetString (PyExc_TypeError, "expected int or long argument");
+                break;
+            }
+
             number = PYGLIB_PyNumber_Long (object);
             if (number == NULL) {
                 break;
@@ -782,6 +794,12 @@ _pygi_argument_from_object (PyObject   *object,
             PyObject *number;
             gint64 value;
 
+            if (!PyObject_TypeCheck (object, &PyInt_Type) && 
+                !PyObject_TypeCheck (object, &PyLong_Type)) {
+                PyErr_SetString (PyExc_TypeError, "expected int or long argument");
+                break;
+            }
+
             number = PYGLIB_PyNumber_Long (object);
             if (number == NULL) {
                 break;
@@ -804,6 +822,13 @@ _pygi_argument_from_object (PyObject   *object,
         {
             PyObject *float_;
 
+            if (!PyObject_TypeCheck (object, &PyFloat_Type) && 
+                !PyObject_TypeCheck (object, &PyInt_Type) && 
+                !PyObject_TypeCheck (object, &PyLong_Type)) {
+                PyErr_SetString (PyExc_TypeError, "expected float or int argument");
+                break;
+            }
+
             float_ = PyNumber_Float (object);
             if (float_ == NULL) {
                 break;
@@ -818,6 +843,13 @@ _pygi_argument_from_object (PyObject   *object,
         {
             PyObject *float_;
 
+            if (!PyObject_TypeCheck (object, &PyFloat_Type) && 
+                !PyObject_TypeCheck (object, &PyInt_Type) && 
+                !PyObject_TypeCheck (object, &PyLong_Type)) {
+                PyErr_SetString (PyExc_TypeError, "expected float or int argument");
+                break;
+            }
+
             float_ = PyNumber_Float (object);
             if (float_ == NULL) {
                 break;
@@ -951,6 +983,13 @@ _pygi_argument_from_object (PyObject   *object,
                 break;
             }
 
+            /* Note, strings are sequences, but we cannot accept them here */
+            if (!PySequence_Check (object) || 
+                PyString_Check (object) || PyUnicode_Check (object)) {
+                PyErr_SetString (PyExc_TypeError, "expected sequence");
+                break;
+            }
+
             length = PySequence_Length (object);
             if (length < 0) {
                 break;
diff --git a/gi/pygi-property.c b/gi/pygi-property.c
index 06f7b02..56a9745 100644
--- a/gi/pygi-property.c
+++ b/gi/pygi-property.c
@@ -287,6 +287,9 @@ pygi_set_property_value_real (PyGObject *instance,
     transfer = g_property_info_get_ownership_transfer (property_info);
     arg = _pygi_argument_from_object (py_value, type_info, transfer);
 
+    if (PyErr_Occurred())
+        goto out;
+
     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
     // FIXME: Lots of types still unhandled
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 0c67623..572d438 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -2021,6 +2021,11 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_int=-42)
         self.assertEqual(obj.props.some_int, -42)
 
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_int', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_int', None)
+
+        self.assertEqual(obj.props.some_int, -42)
+
     def test_uint(self):
         self.assertEqual(self.obj.props.some_uint, 0)
         self.obj.props.some_uint = GObject.G_MAXUINT
@@ -2029,6 +2034,11 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_uint=42)
         self.assertEqual(obj.props.some_uint, 42)
 
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_uint', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_uint', None)
+
+        self.assertEqual(obj.props.some_uint, 42)
+
     def test_long(self):
         self.assertEqual(self.obj.props.some_long, 0)
         self.obj.props.some_long = GObject.G_MAXLONG
@@ -2037,6 +2047,11 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_long=-42)
         self.assertEqual(obj.props.some_long, -42)
 
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_long', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_long', None)
+
+        self.assertEqual(obj.props.some_long, -42)
+
     def test_ulong(self):
         self.assertEqual(self.obj.props.some_ulong, 0)
         self.obj.props.some_ulong = GObject.G_MAXULONG
@@ -2045,6 +2060,11 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_ulong=42)
         self.assertEqual(obj.props.some_ulong, 42)
 
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_ulong', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_ulong', None)
+
+        self.assertEqual(obj.props.some_ulong, 42)
+
     def test_int64(self):
         self.assertEqual(self.obj.props.some_int64, 0)
         self.obj.props.some_int64 = GObject.G_MAXINT64
@@ -2069,6 +2089,14 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_float=42.42)
         self.assertAlmostEqual(obj.props.some_float, 42.42, 4)
 
+        obj = GIMarshallingTests.PropertiesObject(some_float=42)
+        self.assertAlmostEqual(obj.props.some_float, 42.0, 4)
+
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_float', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_float', None)
+
+        self.assertAlmostEqual(obj.props.some_float, 42.0, 4)
+
     def test_double(self):
         self.assertEqual(self.obj.props.some_double, 0)
         self.obj.props.some_double = GObject.G_MAXDOUBLE
@@ -2077,13 +2105,25 @@ class TestPropertiesObject(unittest.TestCase):
         obj = GIMarshallingTests.PropertiesObject(some_double=42.42)
         self.assertAlmostEqual(obj.props.some_double, 42.42)
 
+        obj = GIMarshallingTests.PropertiesObject(some_double=42)
+        self.assertAlmostEqual(obj.props.some_double, 42.0)
+
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_double', 'foo')
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_double', None)
+
+        self.assertAlmostEqual(obj.props.some_double, 42.0)
+
     def test_strv(self):
         self.assertEqual(self.obj.props.some_strv, [])
         self.obj.props.some_strv = ['hello', 'world']
         self.assertEqual(self.obj.props.some_strv, ['hello', 'world'])
 
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', 1)
+        self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', 'foo')
         self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', [1, 2])
         self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', ['foo', 1])
 
+        self.assertEqual(self.obj.props.some_strv, ['hello', 'world'])
+
         obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world'])
         self.assertEqual(obj.props.some_strv, ['hello', 'world'])



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