[pygobject/gsoc2009: 25/160] Add closure support in input arguments



commit 4a1210ae5e12d65d5e6f0df1d7ca484d69d72efe
Author: Simon van der Linden <simon vanderlinden student uclouvain be>
Date:   Mon Jul 6 11:15:22 2009 +0200

    Add closure support in input arguments
    
    The input argument must be a Python callable. When passed, it is wrapped
    into a PyGClosure.
    
    Add pyg_base_info_from_object.

 girepository/bank-argument.c |  115 ++++++++++++++++++++++++++++++-----------
 girepository/bank-info.c     |   27 ++++++++++
 girepository/bank.h          |    2 +
 tests/test_girepository.py   |   19 ++-----
 4 files changed, 118 insertions(+), 45 deletions(-)
---
diff --git a/girepository/bank-argument.c b/girepository/bank-argument.c
index 1939e11..95df956 100644
--- a/girepository/bank-argument.c
+++ b/girepository/bank-argument.c
@@ -284,26 +284,52 @@ pyg_argument_from_pyobject_check(PyObject *object, GITypeInfo *type_info, GError
             interface_info = g_type_info_get_interface(type_info);
             interface_info_type = g_base_info_get_type(interface_info);
 
-            if (interface_info_type == GI_INFO_TYPE_ENUM) {
-                (void) PyInt_AsLong(object);
-                if (PyErr_Occurred()) {
-                    PyErr_Clear();
-                    g_base_info_unref(interface_info);
-                    py_type_name_expected = "int";
-                    goto check_error_type;
+            switch (interface_info_type) {
+                case GI_INFO_TYPE_ENUM:
+                {
+                    (void) PyInt_AsLong(object);
+                    if (PyErr_Occurred()) {
+                        PyErr_Clear();
+                        py_type_name_expected = "int";
+                        goto check_error_type;
+                    }
+                    /* XXX: What if the value doesn't correspond to any enum field? */
+                    break;
                 }
-                /* XXX: What if the value doesn't correspond to any enum field? */
-            } else if (interface_info_type == GI_INFO_TYPE_STRUCT || interface_info_type == GI_INFO_TYPE_BOXED) {
-                GType gtype;
-                GType object_gtype;
+                case GI_INFO_TYPE_STRUCT:
+                case GI_INFO_TYPE_BOXED:
+                {
+                    GType gtype;
+
+                    gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)interface_info);
+
+                    if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
+                        if (!PyCallable_Check(object)) {
+                            g_base_info_unref(interface_info);
+                            py_type_name_expected = "callable";
+                            goto check_error_type;
+                        }
+                    } else {
+                        GIBaseInfo *info;
+
+                        info = pyg_base_info_from_object(object);
+                        if (info == NULL || !g_base_info_equals(info, interface_info)) {
+                            py_type_name_expected = g_base_info_get_name(interface_info);
+                            if (info != NULL) {
+                                g_base_info_unref(info);
+                            }
+                            g_base_info_unref(interface_info);
+                            goto check_error_type;
+                        }
+
+                        g_base_info_unref(info);
+                    }
 
-                gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)interface_info);
-                object_gtype = pyg_type_from_object(object);
-                if (object_gtype != gtype) {
-                    g_base_info_unref(interface_info);
-                    py_type_name_expected = g_type_name(gtype);
-                    goto check_error_type;
+                    break;
                 }
+                default:
+                    /* TODO: To complete with other types. */
+                    g_assert_not_reached();
             }
 
             g_base_info_unref(interface_info);
@@ -354,8 +380,6 @@ pyg_argument_from_pyobject(PyObject *object, GITypeInfo *type_info)
 {
     GArgument arg;
     GITypeTag type_tag;
-    GIBaseInfo* interface_info;
-    GIInfoType interface_type;
 
     type_tag = g_type_info_get_tag((GITypeInfo*)type_info);
     switch (type_tag) {
@@ -421,20 +445,49 @@ pyg_argument_from_pyobject(PyObject *object, GITypeInfo *type_info)
         arg.v_double = PyFloat_AsDouble(object);
         break;
     case GI_TYPE_TAG_INTERFACE:
+    {
+        GIBaseInfo* interface_info;
+        GIInfoType interface_info_type;
+
         interface_info = g_type_info_get_interface(type_info);
-        interface_type = g_base_info_get_type(interface_info);
-        if (interface_type == GI_INFO_TYPE_ENUM) {
-            arg.v_int = PyInt_AsLong(object);
-        } else if (interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) {
-            PyObject *py_buffer;
-            py_buffer = PyObject_GetAttrString(object, "__buffer__");
-            g_assert(py_buffer != NULL);
-            (*py_buffer->ob_type->tp_as_buffer->bf_getreadbuffer)(py_buffer, 0, &arg.v_pointer);
-        } else if (object == Py_None)
-            arg.v_pointer = NULL;
-        else
-            arg.v_pointer = pygobject_get(object);
+        interface_info_type = g_base_info_get_type(interface_info);
+
+        switch (interface_info_type) {
+            case GI_INFO_TYPE_ENUM:
+                arg.v_int = PyInt_AsLong(object);
+                break;
+            case GI_INFO_TYPE_STRUCT:
+            {
+                GType gtype;
+                PyObject *py_buffer;
+
+                gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)interface_info);
+
+                if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
+                    arg.v_pointer = pyg_closure_new(object, NULL, NULL);
+                    break;
+                }
+
+                py_buffer = PyObject_GetAttrString(object, "__buffer__");
+                g_assert(py_buffer != NULL);
+                (*py_buffer->ob_type->tp_as_buffer->bf_getreadbuffer)(py_buffer, 0, &arg.v_pointer);
+
+                break;
+            }
+            case GI_INFO_TYPE_OBJECT:
+                if (object == Py_None) {
+                    arg.v_pointer = NULL;
+                    break;
+                }
+                arg.v_pointer = pygobject_get(object);
+                break;
+            default:
+                /* TODO: To complete with other types. */
+                g_assert_not_reached();
+        }
+        g_base_info_unref((GIBaseInfo *)interface_info);
         break;
+    }
     case GI_TYPE_TAG_ARRAY:
     {
         gsize length;
diff --git a/girepository/bank-info.c b/girepository/bank-info.c
index ed1246c..2a63274 100644
--- a/girepository/bank-info.c
+++ b/girepository/bank-info.c
@@ -266,6 +266,33 @@ pyg_info_new(void *info)
     return (PyObject*)self;
 }
 
+GIBaseInfo *
+pyg_base_info_from_object(PyObject *object)
+{
+    PyObject *py_info;
+    GIBaseInfo *info;
+
+    g_return_val_if_fail(object != NULL, NULL);
+
+    py_info = PyObject_GetAttrString(object, "__info__");
+    if (py_info == NULL) {
+        PyErr_Clear();
+        return NULL;
+    }
+    if (!PyObject_TypeCheck(py_info, (PyTypeObject *)&PyGIBaseInfo_Type)) {
+        Py_DECREF(py_info);
+        return NULL;
+    }
+
+    info = ((PyGIBaseInfo *)py_info)->info;
+    g_base_info_ref(info);
+
+    Py_DECREF(py_info);
+
+    return info;
+}
+
+
 static PyMethodDef _PyGIBaseInfo_methods[] = {
     { "getName", (PyCFunction)_wrap_g_base_info_get_name, METH_NOARGS },
     { "getType", (PyCFunction)_wrap_g_base_info_get_type, METH_NOARGS },
diff --git a/girepository/bank.h b/girepository/bank.h
index 5808f80..ddda161 100644
--- a/girepository/bank.h
+++ b/girepository/bank.h
@@ -41,6 +41,8 @@ extern PyTypeObject PyGIRepository_Type;
 
 PyObject * pyg_info_new(gpointer info);
 
+GIBaseInfo* pyg_base_info_from_object(PyObject *object);
+
 typedef struct {
     PyObject_HEAD
     GIBaseInfo *info;
diff --git a/tests/test_girepository.py b/tests/test_girepository.py
index 58b867b..63d9d7c 100644
--- a/tests/test_girepository.py
+++ b/tests/test_girepository.py
@@ -365,20 +365,11 @@ class TestGIEverything(unittest.TestCase):
         self.assertEquals(retval[1], '2')
         self.assertEquals(retval[2], '3')
 
-# XXX Currently causes a segfault.
-#    def testClosure(self):
-#        def someCallback():
-#            return 3
-#        self.assertEquals(3, Everything.test_closure(someCallback))
-#        someLambda = lambda: 3
-#        self.assertEquals(3, Everything.test_closure(someLambda))
-
-#    def testClosureOneArg(self):
-#        def someCallback(arg):
-#            return arg
-#        self.assertEquals(3, Everything.test_closure_one_arg(someCallback, 3))
-#        someLambda = lambda x: x
-#        self.assertEquals(3, Everything.test_closure_one_arg(someLambda, 3))
+    def testClosure(self):
+        self.assertEquals(3, Everything.test_closure(lambda: 3))
+
+    def testClosureOneArg(self):
+        self.assertEquals(3, Everything.test_closure_one_arg(lambda x: x, 3))
 
 #    def testIntValueArg(self):
 #        i = Everything.test_int_value_arg(42)



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