Commit adcfe96d authored by Will Thompson's avatar Will Thompson Committed by Tomeu Vizoso
Browse files

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
parent 09f00372
......@@ -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);
......
......@@ -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);
......
......@@ -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 *
......
......@@ -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
......
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