[pygobject] Support marshalling of GVariants for closures



commit d9608c332d9592f03545b110cfac8105453ea035
Author: Martin Pitt <martinpitt gnome org>
Date:   Sat May 5 12:42:42 2012 -0700

    Support marshalling of GVariants for closures
    
    Add GVariant handling to pyg_value_{as,from}_pyobject(), so that closures can
    be called with GVariant arguments and return GVariant.
    
    Unmark the corresponding test case as "expected failure", and also add cases
    for None values and type mismatches.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=656554

 gi/_gobject/pygtype.c    |   47 ++++++++++++++++++++++++++++++++++++++++++++-
 tests/test_everything.py |   16 +++++++++++---
 2 files changed, 57 insertions(+), 6 deletions(-)
---
diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c
index fa95d13..fe2c3b6 100644
--- a/gi/_gobject/pygtype.c
+++ b/gi/_gobject/pygtype.c
@@ -727,6 +727,26 @@ pyg_value_array_from_pyobject(GValue *value,
     return 0;
 }
 
+static
+PyObject *
+pyg_get_gvariant_type()
+{
+    static PyObject *variant_type = NULL;
+    PyObject *py_module;
+
+    if (variant_type == NULL) {
+	py_module = PyImport_ImportModule ("gi.repository.GLib");
+	if (py_module == NULL)
+	    return NULL;
+
+	variant_type = PyObject_GetAttrString (py_module, "Variant");
+
+	Py_DECREF (py_module);
+    }
+
+    return variant_type;
+}
+
 /**
  * pyg_value_from_pyobject:
  * @value: the GValue object to store the converted value in.
@@ -991,6 +1011,17 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
 	} else
 	    return -1;
 	break;
+    case G_TYPE_VARIANT:
+        {
+            PyObject* variant_type = pyg_get_gvariant_type();
+            if (obj == Py_None)
+                g_value_set_variant(value, NULL);
+            else if (variant_type != NULL && PyObject_IsInstance(obj, variant_type))
+                g_value_set_variant(value, pyg_boxed_get(obj, GVariant));
+            else
+                return -1;
+            break;
+        }
     default:
 	{
 	    PyGTypeMarshal *bm;
@@ -1147,6 +1178,15 @@ pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed)
 	return pyg_param_spec_new(g_value_get_param(value));
     case G_TYPE_OBJECT:
 	return pygobject_new(g_value_get_object(value));
+    case G_TYPE_VARIANT:
+        {
+	    GVariant *v = g_value_get_variant(value);
+	    if (v == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	    }
+	    return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE);
+        }
     default:
 	{
 	    PyGTypeMarshal *bm;
@@ -1229,8 +1269,11 @@ pyg_closure_marshal(GClosure *closure,
     }
 
     if (return_value && pyg_value_from_pyobject(return_value, ret) != 0) {
-	PyErr_SetString(PyExc_TypeError,
-			"can't convert return value to desired type");
+	/* If we already have an exception set, use that, otherwise set a
+	 * generic one */
+	if (!PyErr_Occurred())
+	    PyErr_SetString(PyExc_TypeError,
+                            "can't convert return value to desired type");
 
 	if (pc->exception_handler)
 	    pc->exception_handler(return_value, n_param_values, param_values);
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 1e8ad59..aa27059 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -476,13 +476,12 @@ class TestClosures(unittest.TestCase):
         self.assertTrue(self.called)
         self.assertEqual(result, 43)
 
-    # https://bugzilla.gnome.org/show_bug.cgi?id=656554
-
-    @unittest.expectedFailure
     def test_variant(self):
         def callback(variant):
-            self.assertEqual(variant.get_type_string(), 'i')
             self.called = True
+            if variant is None:
+                return None
+            self.assertEqual(variant.get_type_string(), 'i')
             return GLib.Variant('i', variant.get_int32() + 1)
 
         self.called = False
@@ -491,6 +490,15 @@ class TestClosures(unittest.TestCase):
         self.assertEqual(result.get_type_string(), 'i')
         self.assertEqual(result.get_int32(), 43)
 
+        self.called = False
+        result = Everything.test_closure_variant(callback, None)
+        self.assertTrue(self.called)
+        self.assertEqual(result, None)
+
+        self.called = False
+        self.assertRaises(TypeError, Everything.test_closure_variant, callback, 'foo')
+        self.assertFalse(self.called)
+
 
 class TestProperties(unittest.TestCase):
 



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