[pygobject] pyg_value_from_pyobject: support GArray



commit 23d1f14f553069740465c82eaa937b877c41e0cb
Author: Ray Strode <rstrode redhat com>
Date:   Wed Dec 19 13:04:32 2012 -0500

    pyg_value_from_pyobject: support GArray
    
    This commit adds support for marshalling a python list (or other sequence)
    returned from signal handlers to GArray, if necessary.
    
    This parallels the implementation written to marshal to (the now deprecated)
    GValueArray.
    
    This fixes a crash in rhythmbox as seen downstream here:
    https://bugzilla.redhat.com/show_bug.cgi?id=872851
    
    https://bugzilla.gnome.org/show_bug.cgi?id=690514
    
    Co-Authored-By: Martin Pitt <martinpitt gnome org>

 gi/_gobject/pygtype.c    |   60 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_everything.py |   22 +++++++++++++++++
 2 files changed, 82 insertions(+), 0 deletions(-)
---
diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c
index 79c8387..921f75f 100644
--- a/gi/_gobject/pygtype.c
+++ b/gi/_gobject/pygtype.c
@@ -727,6 +727,63 @@ pyg_value_array_from_pyobject(GValue *value,
     return 0;
 }
 
+static int
+pyg_array_from_pyobject(GValue *value,
+		        PyObject *obj)
+{
+    int len;
+    GArray *array;
+    int i;
+
+    len = PySequence_Length(obj);
+    if (len == -1) {
+	PyErr_Clear();
+	return -1;
+    }
+
+    array = g_array_new(FALSE, TRUE, sizeof(GValue));
+
+    for (i = 0; i < len; ++i) {
+	PyObject *item = PySequence_GetItem(obj, i);
+	GType type;
+	GValue item_value = { 0, };
+	int status;
+
+	if (! item) {
+	    PyErr_Clear();
+	    g_array_free(array, FALSE);
+	    return -1;
+	}
+
+	if (item == Py_None)
+	    type = G_TYPE_POINTER; /* store None as NULL */
+	else {
+	    type = pyg_type_from_object((PyObject*)Py_TYPE(item));
+	    if (! type) {
+		PyErr_Clear();
+		g_array_free(array, FALSE);
+		Py_DECREF(item);
+		return -1;
+	    }
+	}
+
+	g_value_init(&item_value, type);
+	status = pyg_value_from_pyobject(&item_value, item);
+	Py_DECREF(item);
+
+	if (status == -1) {
+	    g_array_free(array, FALSE);
+	    g_value_unset(&item_value);
+	    return -1;
+	}
+
+	g_array_append_val(array, item_value);
+    }
+
+    g_value_take_boxed(value, array);
+    return 0;
+}
+
 /**
  * pyg_value_from_pyobject:
  * @value: the GValue object to store the converted value in.
@@ -959,6 +1016,9 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
         else if (PySequence_Check(obj) &&
 		   G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY))
 	    return pyg_value_array_from_pyobject(value, obj, NULL);
+        else if (PySequence_Check(obj) &&
+		   G_VALUE_HOLDS(value, G_TYPE_ARRAY))
+	    return pyg_array_from_pyobject(value, obj);
 	else if (PYGLIB_PyUnicode_Check(obj) &&
                  G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
             GString *string;
diff --git a/tests/test_everything.py b/tests/test_everything.py
index f1f14b7..4907a84 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -1195,6 +1195,28 @@ class TestSignals(unittest.TestCase):
         obj.emit_sig_with_uint64()
         self.assertEqual(obj.callback_i, GObject.G_MAXUINT64)
 
+    def test_intarray_ret(self):
+        obj = Everything.TestObj()
+
+        def callback(obj, i):
+            obj.callback_i = i
+            return [i, i + 1]
+
+        obj.callback_i = None
+
+        try:
+            obj.connect('sig-with-intarray-ret', callback)
+        except TypeError as e:
+            # compat with g-i 1.34.x
+            if 'unknown signal' in str(e):
+                return
+            raise
+
+        rv = obj.emit('sig-with-intarray-ret', 42)
+        self.assertEqual(obj.callback_i, 42)
+        self.assertEqual(type(rv), GLib.Array)
+        self.assertEqual(rv.len, 2)
+
 
 @unittest.skipUnless(has_cairo, 'built without cairo support')
 @unittest.skipUnless(Gtk, 'Gtk not available')



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