[pygobject] [gi] make parameter check less strict when dealing with GValue params



commit b483852904468722230903989e3451c7c6a24c0f
Author: John (J5) Palmieri <johnp redhat com>
Date:   Tue Oct 12 12:18:33 2010 -0400

    [gi] make parameter check less strict when dealing with GValue params
    
    * Some GValue API can store a pointer to a python object for later
      use but our parameter checking was too strict to allow this
    * Add pyg_type_from_object_strict API which takes a strict boolean and
      returns PY_TYPE_OBJECT if no other GType can be found
    * Since we don't have enough info to genrically check GValue parameters
      use the less strict type guessing when encountering a GValue param
    * Other API stays the same and continues to do strict testing
    
    https://bugzilla.gnome.org/show_bug.cgi?id=622987

 gi/pygi-argument.c          |   17 +++++---------
 gobject/gobjectmodule.c     |    4 +-
 gobject/pygobject-private.h |    1 +
 gobject/pygobject.h         |    2 +
 gobject/pygtype.c           |   37 ++++++++++++++++++++++++++++---
 tests/test_gi.py            |    1 -
 tests/test_overrides.py     |   50 +++++++++++++++++++++++++++++++++++++++---
 7 files changed, 90 insertions(+), 22 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index e3dd8c3..b768e9e 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -222,22 +222,17 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
 
             /* Handle special cases. */
             type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
-            if (g_type_is_a (type, G_TYPE_VALUE)) {
-                GType object_type;
-                object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
-                if (object_type == G_TYPE_INVALID) {
-                    PyErr_Format (PyExc_TypeError, "Must be of a known GType, not %s",
-                                  object->ob_type->tp_name);
-                    retval = 0;
-                }
-                break;
-            } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+            if (g_type_is_a (type, G_TYPE_CLOSURE)) {
                 if (!PyCallable_Check (object)) {
                     PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
                                   object->ob_type->tp_name);
                     retval = 0;
                 }
                 break;
+            } else if (g_type_is_a (type, G_TYPE_VALUE)) {
+                /* we can't check g_values because we don't have 
+                 * enough context so just pass them through */
+                break;
             }
 
             /* Fallback. */
@@ -904,7 +899,7 @@ array_item_error:
                         GType object_type;
                         gint retval;
 
-                        object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
+                        object_type = pyg_type_from_object_strict ( (PyObject *) object->ob_type, FALSE);
                         if (object_type == G_TYPE_INVALID) {
                             PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
                             break;
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c
index f830251..a33ec24 100644
--- a/gobject/gobjectmodule.c
+++ b/gobject/gobjectmodule.c
@@ -2501,8 +2501,8 @@ struct _PyGObject_Functions pygobject_api_functions = {
   pyg_type_register_custom_callback,
   pyg_gerror_exception_check,
 
-  pyglib_option_group_new
-
+  pyglib_option_group_new,
+  pyg_type_from_object_strict
 };
 
 /* for addon libraries ... */
diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h
index 26cb5f2..ae4cfe1 100644
--- a/gobject/pygobject-private.h
+++ b/gobject/pygobject-private.h
@@ -98,6 +98,7 @@ gboolean pyg_gerror_exception_check(GError **error);
 extern PyTypeObject PyGTypeWrapper_Type;
 
 PyObject *pyg_type_wrapper_new (GType type);
+GType     pyg_type_from_object_strict (PyObject *obj, gboolean strict);
 GType     pyg_type_from_object (PyObject *obj);
 
 gint pyg_enum_get_value  (GType enum_type, PyObject *obj, gint *val);
diff --git a/gobject/pygobject.h b/gobject/pygobject.h
index afbc665..21743ba 100644
--- a/gobject/pygobject.h
+++ b/gobject/pygobject.h
@@ -198,6 +198,7 @@ struct _PyGObject_Functions {
 				      gpointer data);
     gboolean  (*gerror_exception_check) (GError **error);
     PyObject* (*option_group_new) (GOptionGroup *group);
+    GType (* type_from_object_strict) (PyObject *obj, gboolean strict);    
 };
 
 #ifndef _INSIDE_PYGOBJECT_
@@ -218,6 +219,7 @@ struct _PyGObject_Functions *_PyGObject_API;
 #define pygobject_watch_closure     (_PyGObject_API->object_watch_closure)
 #define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler)
 #define pyg_destroy_notify          (_PyGObject_API->destroy_notify)
+#define pyg_type_from_object_strict   (_PyGObject_API->type_from_object_strict)
 #define pyg_type_from_object        (_PyGObject_API->type_from_object)
 #define pyg_type_wrapper_new        (_PyGObject_API->type_wrapper_new)
 #define pyg_enum_get_value          (_PyGObject_API->enum_get_value)
diff --git a/gobject/pygtype.c b/gobject/pygtype.c
index 32f8640..a2ba55a 100644
--- a/gobject/pygtype.c
+++ b/gobject/pygtype.c
@@ -349,16 +349,20 @@ pyg_type_wrapper_new(GType type)
 }
 
 /**
- * pyg_type_from_object:
+ * pyg_type_from_object_strict:
  * obj: a Python object
+ * strict: if set to TRUE, raises an exception if it can't perform the
+ *         conversion
  *
- * converts a python object to a GType.  Raises an exception if it
- * can't perform the conversion.
+ * converts a python object to a GType.  If strict is set, raises an 
+ * exception if it can't perform the conversion, otherwise returns
+ * PY_TYPE_OBJECT.
  *
  * Returns: the corresponding GType, or 0 on error.
  */
+
 GType
-pyg_type_from_object(PyObject *obj)
+pyg_type_from_object_strict(PyObject *obj, gboolean strict)
 {
     PyObject *gtype;
     GType type;
@@ -416,10 +420,35 @@ pyg_type_from_object(PyObject *obj)
     }
 
     PyErr_Clear();
+
+    /* Some API like those that take GValues can hold a python object as
+     * a pointer.  This is potentially dangerous becuase everything is 
+     * passed in as a PyObject so we can't actually type check it.  Only
+     * fallback to PY_TYPE_OBJECT if strict checking is disabled
+     */
+    if (!strict)
+        return PY_TYPE_OBJECT;
+
     PyErr_SetString(PyExc_TypeError, "could not get typecode from object");
     return 0;
 }
 
+/**
+ * pyg_type_from_object:
+ * obj: a Python object
+ *
+ * converts a python object to a GType.  Raises an exception if it
+ * can't perform the conversion.
+ *
+ * Returns: the corresponding GType, or 0 on error.
+ */
+GType
+pyg_type_from_object(PyObject *obj)
+{
+    /* Legacy call always defaults to strict type checking */
+    return pyg_type_from_object_strict(obj, TRUE);
+}
+
 /* -------------- GValue marshalling ------------------ */
 
 /**
diff --git a/tests/test_gi.py b/tests/test_gi.py
index fa9df70..cc1b7ae 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -915,7 +915,6 @@ class TestGValue(unittest.TestCase):
 
     def test_gvalue_in(self):
         GIMarshallingTests.gvalue_in(42)
-        self.assertRaises(TypeError, GIMarshallingTests.gvalue_in, None)
 
     def test_gvalue_out(self):
         self.assertEquals(42, GIMarshallingTests.gvalue_out())
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index b86222b..33ec95e 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -272,12 +272,24 @@ class TestGtk(unittest.TestCase):
         self.assertEquals(Gtk.TreeModel, overrides.Gtk.TreeModel)
         self.assertEquals(Gtk.TreeViewColumn, overrides.Gtk.TreeViewColumn)
 
-        tree_store = Gtk.TreeStore(int, 'gchararray', TestGtk.TestClass)
+        class TestPyObject(object):
+            pass
+
+        test_pyobj = TestPyObject()
+        test_pydict = {1:1, "2":2, "3":"3"}
+        test_pylist = [1,"2", "3"]
+        tree_store = Gtk.TreeStore(int, 'gchararray', TestGtk.TestClass, object, object, object)
+
         parent = None
         for i in range(100):
             label = 'this is child #%d' % i
             testobj = TestGtk.TestClass(self, i, label)
-            parent = tree_store.append(parent, (i, label, testobj))
+            parent = tree_store.append(parent, (i,
+                                                label,
+                                                testobj,
+                                                test_pyobj,
+                                                test_pydict,
+                                                test_pylist))
 
         # len gets the number of children in the root node
         # since we kept appending to the previous node
@@ -293,18 +305,41 @@ class TestGtk(unittest.TestCase):
            i = tree_store.get_value(treeiter, 0)
            s = tree_store.get_value(treeiter, 1)
            obj = tree_store.get_value(treeiter, 2)
+           i = tree_store.get_value(treeiter, 0)
+           s = tree_store.get_value(treeiter, 1)
+           obj = tree_store.get_value(treeiter, 2)
            obj.check(i, s)
+
+           pyobj = tree_store.get_value(treeiter, 3)
+           self.assertEquals(pyobj, test_pyobj)
+           pydict = tree_store.get_value(treeiter, 4)
+           self.assertEquals(pydict, test_pydict)
+           pylist = tree_store.get_value(treeiter, 5)
+           self.assertEquals(pylist, test_pylist)
+
            parent = treeiter
            treeiter = tree_store.iter_children(parent)
 
         self.assertEquals(i, 99)
 
     def test_list_store(self):
-        list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest')
+        class TestPyObject(object):
+            pass
+
+        test_pyobj = TestPyObject()
+        test_pydict = {1:1, "2":2, "3":"3"}
+        test_pylist = [1,"2", "3"]
+
+        list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object)
         for i in range(100):
             label = 'this is row #%d' % i
             testobj = TestGtk.TestClass(self, i, label)
-            parent = list_store.append((i, label, testobj))
+            parent = list_store.append((i,
+                                        label,
+                                        testobj,
+                                        test_pyobj,
+                                        test_pydict,
+                                        test_pylist))
 
         self.assertEquals(len(list_store), 100)
 
@@ -317,6 +352,13 @@ class TestGtk(unittest.TestCase):
             s = list_store.get_value(treeiter, 1)
             obj = list_store.get_value(treeiter, 2)
             obj.check(i, s)
+
+            pyobj = list_store.get_value(treeiter, 3)
+            self.assertEquals(pyobj, test_pyobj)
+            pydict = list_store.get_value(treeiter, 4)
+            self.assertEquals(pydict, test_pydict)
+            pylist = list_store.get_value(treeiter, 5)
+            self.assertEquals(pylist, test_pylist)
             treeiter = list_store.iter_next(treeiter)
 
         self.assertEquals(i, 99)



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