[pygobject] Support functions which return GError



commit adcfe96d49b09bcc550653d73de196610fd5144d
Author: Will Thompson <will thompson collabora co uk>
Date:   Fri Jan 20 16:20:10 2012 +0000

    Support functions which return GError
    
    GStreamer has the following method:
    
      void gst_message_parse_error (
          GstMessage *message,
          GError **error,
          gchar **debug_message);
    
    With this patch, we marshal the GError out parameter as a GObject.GError
    exception, but return it rather than throwing it. The test cases cover
    two variations on the theme of the function above (one with (transfer
    full), as in GStreamer, and another with (transfer none)) as well as a
    function with return type GError *.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=666098

 gi/_glib/pyglib.c       |   46 +++++++++++++++++++++++++++++++++++-----------
 gi/_glib/pyglib.h       |    1 +
 gi/pygi-marshal-to-py.c |   16 +++++++++++++---
 tests/test_gi.py        |   32 ++++++++++++++++++++++++++++++++
 4 files changed, 81 insertions(+), 14 deletions(-)
---
diff --git a/gi/_glib/pyglib.c b/gi/_glib/pyglib.c
index f127fb4..5172aaa 100644
--- a/gi/_glib/pyglib.c
+++ b/gi/_glib/pyglib.c
@@ -233,30 +233,28 @@ pyglib_set_thread_block_funcs (PyGLibThreadBlockFunc block_threads_func,
     _PyGLib_API->unblock_threads = unblock_threads_func;
 }
 
-
 /**
- * pyglib_error_check:
+ * pyglib_error_marshal:
  * @error: a pointer to the GError.
  *
- * Checks to see if the GError has been set.  If the error has been
- * set, then the glib.GError Python exception will be raised, and
- * the GError cleared.
+ * Checks to see if @error has been set.  If @error has been set, then a
+ * GLib.GError Python exception object is returned (but not raised).
  *
- * Returns: True if an error was set.
+ * Returns: a GLib.GError Python exception object, or NULL.
  */
-gboolean
-pyglib_error_check(GError **error)
+PyObject *
+pyglib_error_marshal (GError **error)
 {
     PyGILState_STATE state;
     PyObject *exc_type;
     PyObject *exc_instance;
     PyObject *d;
 
-    g_return_val_if_fail(error != NULL, FALSE);
+    g_return_val_if_fail(error != NULL, NULL);
 
     if (*error == NULL)
-	return FALSE;
-    
+	return NULL;
+
     state = pyglib_gil_state_ensure();
 
     exc_type = _PyGLib_API->gerror_exception;
@@ -289,7 +287,33 @@ pyglib_error_check(GError **error)
     } else {
 	PyObject_SetAttrString(exc_instance, "message", Py_None);
     }
+
+    pyglib_gil_state_release(state);
     
+    return exc_instance;
+}
+
+/**
+ * pyglib_error_check:
+ * @error: a pointer to the GError.
+ *
+ * Checks to see if the GError has been set.  If the error has been
+ * set, then the glib.GError Python exception will be raised, and
+ * the GError cleared.
+ *
+ * Returns: True if an error was set.
+ */
+gboolean
+pyglib_error_check(GError **error)
+{
+    PyGILState_STATE state;
+    PyObject *exc_instance;
+
+    g_return_val_if_fail(error != NULL, FALSE);
+
+    state = pyglib_gil_state_ensure();
+
+    exc_instance = pyglib_error_marshal (error);
     PyErr_SetObject(_PyGLib_API->gerror_exception, exc_instance);
     Py_DECREF(exc_instance);
     g_clear_error(error);
diff --git a/gi/_glib/pyglib.h b/gi/_glib/pyglib.h
index 44ead47..261af7b 100644
--- a/gi/_glib/pyglib.h
+++ b/gi/_glib/pyglib.h
@@ -37,6 +37,7 @@ PyGILState_STATE pyglib_gil_state_ensure(void);
 void pyglib_gil_state_release(PyGILState_STATE state);
 int pyglib_enable_threads(void);
 gboolean pyglib_error_check(GError **error);
+PyObject *pyglib_error_marshal (GError **error);
 gboolean pyglib_gerror_exception_check(GError **error);
 PyObject *pyglib_register_exception_for_domain(gchar *name,
 					       gint error_domain);
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 709fef8..4b99278 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <time.h>
 
+#include <pyglib.h>
 #include <pygobject.h>
 #include <pyglib-python-compat.h>
 
@@ -598,11 +599,20 @@ _pygi_marshal_to_py_gerror (PyGIInvokeState   *state,
                             PyGIArgCache      *arg_cache,
                             GIArgument        *arg)
 {
+    GError *error = arg->v_pointer;
     PyObject *py_obj = NULL;
 
-    PyErr_Format (PyExc_NotImplementedError,
-                  "Marshalling for gerror to PyObject is not implemented");
-    return py_obj;
+    py_obj = pyglib_error_marshal(&error);
+
+    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) {
+        g_error_free (error);
+    }
+
+    if (py_obj != NULL) {
+        return py_obj;
+    } else {
+        Py_RETURN_NONE;
+    }
 }
 
 PyObject *
diff --git a/tests/test_gi.py b/tests/test_gi.py
index b95bebe..7d2fbed 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1829,6 +1829,38 @@ class TestGErrorArrayInCrash(unittest.TestCase):
     def test_gerror_array_in_crash(self):
         self.assertRaises(GObject.GError, GIMarshallingTests.gerror_array_in, [1, 2, 3])
 
+class TestGErrorOut(unittest.TestCase):
+    # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+    def test_gerror_out(self):
+        error, debug = GIMarshallingTests.gerror_out()
+
+        self.assertIsInstance(error, GObject.GError)
+        self.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+        self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+        self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+        self.assertEquals(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE)
+
+class TestGErrorOutTransferNone(unittest.TestCase):
+    # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+    def test_gerror_out_transfer_none(self):
+        error, debug = GIMarshallingTests.gerror_out_transfer_none()
+
+        self.assertIsInstance(error, GObject.GError)
+        self.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+        self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+        self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+        self.assertEquals(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug)
+
+class TestGErrorReturn(unittest.TestCase):
+    # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+    def test_return_gerror(self):
+        error = GIMarshallingTests.gerror_return()
+
+        self.assertIsInstance(error, GObject.GError)
+        self.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+        self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+        self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+
 class TestKeywordArgs(unittest.TestCase):
     def test_calling(self):
         kw_func = GIMarshallingTests.int_three_in_three_out



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