Commit d9608c33 authored by Martin Pitt's avatar Martin Pitt
Browse files

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
parent e7a909c1
......@@ -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);
......
......@@ -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):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment