[pygobject] gerror: Add special case marshaling for boxing GErrors



commit 5f4b08f4e8a98046eab71537c7827edde2ca8742
Author: Simon Feltman <sfeltman src gnome org>
Date:   Mon Feb 29 22:50:32 2016 -0800

    gerror: Add special case marshaling for boxing GErrors
    
    Transfer gtype from introspection GError class to Python GError implementation.
    Expose the PyGError pointer as an extern so other C files can pick this up.
    Add custom to/from GValue marshalers for GError.
    Add tests for both complete and incomplete (no boxed pointer held).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=761592

 gi/overrides/GLib.py  |    1 +
 gi/pygi-error.c       |   32 +++++++++++++++++++++++++++++++-
 gi/pygi-error.h       |    2 ++
 gi/pygi-value.c       |    1 +
 tests/test_gobject.py |   17 +++++++++++++++++
 5 files changed, 52 insertions(+), 1 deletions(-)
---
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 455ea84..c12b4d8 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -74,6 +74,7 @@ def gerror_new_literal(domain, message, code):
 # Monkey patch methods that rely on GLib introspection to be loaded at runtime.
 Error.__name__ = 'Error'
 Error.__module__ = 'GLib'
+Error.__gtype__ = GLib.Error.__gtype__
 Error.matches = gerror_matches
 Error.new_literal = staticmethod(gerror_new_literal)
 
diff --git a/gi/pygi-error.c b/gi/pygi-error.c
index 9a9a10d..d86021c 100644
--- a/gi/pygi-error.c
+++ b/gi/pygi-error.c
@@ -23,9 +23,10 @@
 #include "pyglib.h"
 #include "pygi-private.h"
 #include "pygi-error.h"
+#include "pygtype.h"
 
 
-static PyObject *PyGError = NULL;
+PyObject *PyGError = NULL;
 static PyObject *exception_table = NULL;
 
 /**
@@ -346,6 +347,31 @@ pygi_arg_gerror_new_from_info (GITypeInfo   *type_info,
     }
 }
 
+static PyObject *
+pygerror_from_gvalue (const GValue *value)
+{
+    GError *gerror = (GError *) g_value_get_boxed (value);
+    PyObject *pyerr = pygi_error_marshal_to_py (&gerror);
+    if (pyerr == NULL) {
+        Py_RETURN_NONE;
+    } else {
+        return pyerr;
+    }
+}
+
+static int
+pygerror_to_gvalue (GValue *value, PyObject *pyerror)
+{
+    GError *gerror = NULL;
+
+    if (pygi_error_marshal_from_py (pyerror, &gerror)) {
+        g_value_take_boxed (value, gerror);
+        return 0;
+    }
+
+    return -1;
+}
+
 void
 pygi_error_register_types (PyObject *module)
 {
@@ -356,5 +382,9 @@ pygi_error_register_types (PyObject *module)
 
     /* Stash a reference to the Python implemented gi._error.GError. */
     PyGError = PyObject_GetAttrString (error_module, "GError");
+
+    pyg_register_gtype_custom (G_TYPE_ERROR,
+                               pygerror_from_gvalue,
+                               pygerror_to_gvalue);
 }
 
diff --git a/gi/pygi-error.h b/gi/pygi-error.h
index 378c1b4..e7cc05f 100644
--- a/gi/pygi-error.h
+++ b/gi/pygi-error.h
@@ -27,6 +27,8 @@
 
 G_BEGIN_DECLS
 
+extern PyObject *PyGError;
+
 gboolean      pygi_error_check              (GError **error);
 
 PyObject*     pygi_error_marshal_to_py      (GError **error);
diff --git a/gi/pygi-value.c b/gi/pygi-value.c
index b155a68..9da87a5 100644
--- a/gi/pygi-value.c
+++ b/gi/pygi-value.c
@@ -874,6 +874,7 @@ pyg_value_as_pyobject (const GValue *value, gboolean copy_boxed)
     }
 
     return NULL;
+
 }
 
 
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index 87b0e4c..e78132d 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -675,5 +675,22 @@ class TestGValue(unittest.TestCase):
         value.set_value([32, 'foo_bar', 0.3])
         self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3])
 
+    def test_gerror_boxing(self):
+        error = GLib.Error('test message', domain='mydomain', code=42)
+        value = GObject.Value(GLib.Error, error)
+        self.assertEqual(value.g_type, GObject.type_from_name('GError'))
+
+        unboxed = value.get_value()
+        self.assertEqual(unboxed.message, error.message)
+        self.assertEqual(unboxed.domain, error.domain)
+        self.assertEqual(unboxed.code, error.code)
+
+    def test_gerror_novalue(self):
+        error = GLib.Error('test message', domain='mydomain', code=42)
+        value = GObject.Value(GLib.Error)
+        self.assertEqual(value.g_type, GObject.type_from_name('GError'))
+        self.assertEqual(value.get_value(), None)
+
+
 if __name__ == '__main__':
     unittest.main()


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