Imported Upstream version 3.19.91 upstream/3.19.91
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 30 Oct 2018 01:28:49 +0000 (10:28 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 30 Oct 2018 01:28:49 +0000 (10:28 +0900)
20 files changed:
ChangeLog
NEWS
PKG-INFO
configure
configure.ac
gi/overrides/GLib.py
gi/pygboxed.c
gi/pygi-error.c
gi/pygi-error.h
gi/pygi-struct.c
gi/pygi-struct.h
gi/pygi-value.c
gi/pygtype.c
tests/Makefile.am
tests/Makefile.in
tests/gimarshallingtestsextra.c [new file with mode: 0644]
tests/gimarshallingtestsextra.h [new file with mode: 0644]
tests/test_error.py
tests/test_gobject.py
tests/test_overrides_glib.py

index 17088b3..82cbb84 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,156 @@
+commit a4865ef2f8c70b93f84f93236786c65ad5f973af
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Tue Mar 1 21:46:21 2016 -0800
+
+    release 3.19.91
+
+ NEWS | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+commit cc75f994a07639b9ffcc6afef757768780a076de
+Author: Thibault Saunier <tsaunier@gnome.org>
+Date:   Fri Feb 5 15:00:10 2016 +0100
+
+    tests: check passing Boxed type in GValue as function parameters
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=761592
+
+ tests/Makefile.am               | 13 +++++++++++--
+ tests/gimarshallingtestsextra.c | 37
+ +++++++++++++++++++++++++++++++++++++
+ tests/gimarshallingtestsextra.h | 26 ++++++++++++++++++++++++++
+ tests/test_error.py             |  6 ++++++
+ 4 files changed, 80 insertions(+), 2 deletions(-)
+
+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 deletion(-)
+
+commit cfca1457c39e3c4c7ef97e7b46a73c19e5adf305
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Sun Feb 28 01:39:31 2016 -0800
+
+    gerror: Add support for marshaling GError from Python to C
+
+    Refactor pygi_gerror_exception_check() to use a new broken out
+    function
+    pygi_error_marshal_from_py(). This allows re-use for argument
+    marshaling
+    of a Python GError to a C GError.
+    Remove PYGI_META_ARG_TYPE_CHILD setting for GError out argument
+    marshaling.
+    This was incorrect since GError exception arguments are not specified
+    explicitly and instead uses the "throws" option.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=685197
+
+ gi/pygi-error.c              | 132
+ +++++++++++++++++++++++++++++--------------
+ gi/pygi-error.h              |   3 +
+ tests/test_overrides_glib.py |  30 ++++++++++
+ 3 files changed, 123 insertions(+), 42 deletions(-)
+
+commit 2fc1a689a81614649d042965997f4546b0a58ada
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Sat Feb 27 17:21:53 2016 -0800
+
+    gerror: Add "_to_py" suffix to pygi_error_marshal
+
+    This will allow for the a pygi_error_marshal_from_py function.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=685197
+
+ gi/pygi-error.c | 8 ++++----
+ gi/pygi-error.h | 2 +-
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 7e29227b6f58cfcc96118a4af83658ca1a6fa1f4
+Author: Christoph Reiter <creiter@src.gnome.org>
+Date:   Sat Jul 4 22:09:46 2015 +0200
+
+    Some error handling/reporting fixes.
+
+    * Check in pyg_boxed_new() if the passed type is an actual subclass
+    * Don't replace existing exceptions in pyg_value_as_pyobject()
+    * Print an error in pyg_closure_marshal() in case marshalling
+      an argument failed.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=751956
+
+ gi/pygboxed.c   |  8 +++++++-
+ gi/pygi-value.c | 15 ++++++++++-----
+ gi/pygtype.c    | 11 ++++++++++-
+ 3 files changed, 27 insertions(+), 7 deletions(-)
+
+commit 49880800b35029de3731523eede1b3174f10c1db
+Author: Christoph Reiter <creiter@src.gnome.org>
+Date:   Sat Jul 4 21:40:04 2015 +0200
+
+    GVariant: Don't use pyg_boxed_new as GVariant isn't a PyGBoxed but
+    a PyGIStruct.
+
+    This only worked because they share the same struct layout.
+    This adds a new constructor for creating a new PyGIStruct instance
+    from GType.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=751956
+
+ gi/pygi-struct.c | 32 ++++++++++++++++++++++++++++++++
+ gi/pygi-struct.h |  5 +++++
+ gi/pygi-value.c  |  3 ++-
+ 3 files changed, 39 insertions(+), 1 deletion(-)
+
+commit f27b1976ea325fcd55359888401dd08ac8fb074a
+Author: Mikhail Fludkov <misha@pexip.com>
+Date:   Tue Sep 1 17:54:17 2015 +0200
+
+    pygi-value: special case for NULL GValueArray
+
+    Don't segfault when dealing with GValue of GValueArray type containing
+    NULL. Return empty list in this case.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=754359
+
+ gi/pygi-value.c       | 5 +++--
+ tests/test_gobject.py | 6 ++++++
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+commit c8176dfabea694ce738ff4633e7522b0d1fc1c51
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Sat Feb 20 20:42:40 2016 -0800
+
+    post-release version bump to 3.19.91
+
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d16ae38f0a12653557bdeba17eb155144d91bff4
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Sat Feb 20 19:56:24 2016 -0800
+
+    release 3.19.90
+
+ NEWS | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
 commit 0190fb84fc1f88ba4c0623bf1b29fe3ca4f80932
 Author: Simon Feltman <sfeltman@src.gnome.org>
 Date:   Sat Feb 20 19:49:31 2016 -0800
diff --git a/NEWS b/NEWS
index 7a3ca39..500a962 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+3.19.91 01-Mar-2016
+        - Fix marshaling of GError stored in GValue
+          (Simon Feltman) (Thibault Saunier) (#761592)
+        - Fix marshaling or GError from Python to C from function calls
+          (Simon Feltman) (#685197)
+        - Error handling/reporting fixes (Christoph Reiter) (#751956)
+        - Fix crash due to GVariant implemented as PyGBoxed not PyGIStruct
+          (Christoph Reiter) (#751956)
+        - Fix crash with GValueArray stored in GValue
+          (Mikhail Fludkov) (#754359)
+
 3.19.90 20-Feb-2016
         - tests: Set the active style context state before retrieving values
           (Simon Feltman)
index 9e53b03..187f30d 100644 (file)
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: PyGObject
-Version: 3.19.90
+Version: 3.19.91
 Summary: Python bindings for GObject
 Home-page: http://www.pygtk.org/
 Author: James Henstridge
@@ -8,7 +8,7 @@ Author-email: james@daa.com.au
 Maintainer: Simon Feltman
 Maintainer-email: sfeltman@src.gnome.org
 License: GNU LGPL
-Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.19/pygobject-3.19.90.tar.gz
+Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.19/pygobject-3.19.91.tar.gz
 Description: Python bindings for GLib and GObject
 Platform: POSIX, Windows
 Classifier: Development Status :: 5 - Production/Stable
index 1fea2d3..2f6c3f9 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pygobject 3.19.90.
+# Generated by GNU Autoconf 2.69 for pygobject 3.19.91.
 #
 # Report bugs to <http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject>.
 #
@@ -591,8 +591,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='pygobject'
 PACKAGE_TARNAME='pygobject'
-PACKAGE_VERSION='3.19.90'
-PACKAGE_STRING='pygobject 3.19.90'
+PACKAGE_VERSION='3.19.91'
+PACKAGE_STRING='pygobject 3.19.91'
 PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject'
 PACKAGE_URL='https://wiki.gnome.org/Projects/PyGObject/'
 
@@ -1398,7 +1398,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures pygobject 3.19.90 to adapt to many kinds of systems.
+\`configure' configures pygobject 3.19.91 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1468,7 +1468,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of pygobject 3.19.90:";;
+     short | recursive ) echo "Configuration of pygobject 3.19.91:";;
    esac
   cat <<\_ACEOF
 
@@ -1611,7 +1611,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-pygobject configure 3.19.90
+pygobject configure 3.19.91
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1889,7 +1889,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by pygobject $as_me 3.19.90, which was
+It was created by pygobject $as_me 3.19.91, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2253,9 +2253,9 @@ $as_echo "#define PYGOBJECT_MINOR_VERSION 19" >>confdefs.h
 PYGOBJECT_MINOR_VERSION=19
 
 
-$as_echo "#define PYGOBJECT_MICRO_VERSION 90" >>confdefs.h
+$as_echo "#define PYGOBJECT_MICRO_VERSION 91" >>confdefs.h
 
-PYGOBJECT_MICRO_VERSION=90
+PYGOBJECT_MICRO_VERSION=91
 
 
 ac_config_headers="$ac_config_headers config.h"
@@ -2777,7 +2777,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='pygobject'
- VERSION='3.19.90'
+ VERSION='3.19.91'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -15861,7 +15861,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by pygobject $as_me 3.19.90, which was
+This file was extended by pygobject $as_me 3.19.91, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -15928,7 +15928,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-pygobject config.status 3.19.90
+pygobject config.status 3.19.91
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 99ff6b2..3ed9aff 100644 (file)
@@ -18,7 +18,7 @@ m4_define(python3_min_ver, 3.1)
 dnl the pygobject version number
 m4_define(pygobject_major_version, 3)
 m4_define(pygobject_minor_version, 19)
-m4_define(pygobject_micro_version, 90)
+m4_define(pygobject_micro_version, 91)
 m4_define(pygobject_version, pygobject_major_version.pygobject_minor_version.pygobject_micro_version)
 
 dnl versions of packages we require ...
index 455ea84..c12b4d8 100644 (file)
@@ -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)
 
index 30ab423..cdb766c 100644 (file)
@@ -189,7 +189,7 @@ pyg_register_boxed(PyObject *dict, const gchar *class_name,
  * wrapper will be freed when the wrapper is deallocated.  If
  * @copy_boxed is True, then @own_ref must also be True.
  *
- * Returns: the boxed wrapper.
+ * Returns: the boxed wrapper or %NULL and sets an exception.
  */
 PyObject *
 pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed,
@@ -218,6 +218,12 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed,
     if (!tp)
        tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */
 
+    if (!PyType_IsSubtype (tp, &PyGBoxed_Type)) {
+        PyErr_Format (PyExc_RuntimeError, "%s isn't a GBoxed", tp->tp_name);
+        pyglib_gil_state_release (state);
+        return NULL;
+    }
+
     self = (PyGBoxed *)tp->tp_alloc(tp, 0);
 
     if (self == NULL) {
index b019a09..d86021c 100644 (file)
 #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;
 
 /**
- * pygi_error_marshal:
+ * pygi_error_marshal_to_py:
  * @error: a pointer to the GError.
  *
  * Checks to see if @error has been set.  If @error has been set, then a
@@ -38,7 +39,7 @@ static PyObject *exception_table = NULL;
  * Returns: a GLib.GError Python exception object, or NULL.
  */
 PyObject *
-pygi_error_marshal (GError **error)
+pygi_error_marshal_to_py (GError **error)
 {
     PyGILState_STATE state;
     PyObject *exc_type;
@@ -97,7 +98,7 @@ pygi_error_check (GError **error)
 
     state = pyglib_gil_state_ensure();
 
-    exc_instance = pygi_error_marshal (error);
+    exc_instance = pygi_error_marshal_to_py (error);
     PyErr_SetObject(PyGError, exc_instance);
     Py_DECREF(exc_instance);
     g_clear_error(error);
@@ -108,6 +109,64 @@ pygi_error_check (GError **error)
 }
 
 /**
+ * pygi_error_marshal_from_py:
+ * @pyerr: A Python exception instance.
+ * @error: a standard GLib GError ** output parameter
+ *
+ * Converts from a Python implemented GError into a GError.
+ *
+ * Returns: TRUE if the conversion was successful, otherwise a Python exception
+ *          is set and FALSE is returned.
+ */
+gboolean
+pygi_error_marshal_from_py (PyObject *pyerr, GError **error)
+{
+    gboolean res = FALSE;
+    PyObject *py_message = NULL,
+             *py_domain = NULL,
+             *py_code = NULL;
+
+    if (PyObject_IsInstance (pyerr, PyGError) != 1) {
+        PyErr_Format (PyExc_TypeError, "Must be GLib.Error, not %s",
+                      pyerr->ob_type->tp_name);
+        return FALSE;
+    }
+
+    py_message = PyObject_GetAttrString (pyerr, "message");
+    if (!py_message || !PYGLIB_PyUnicode_Check (py_message)) {
+        PyErr_SetString (PyExc_ValueError,
+                         "GLib.Error instances must have a 'message' string attribute");
+        goto cleanup;
+    }
+
+    py_domain = PyObject_GetAttrString (pyerr, "domain");
+    if (!py_domain || !PYGLIB_PyUnicode_Check (py_domain)) {
+        PyErr_SetString (PyExc_ValueError,
+                         "GLib.Error instances must have a 'domain' string attribute");
+        goto cleanup;
+    }
+
+    py_code = PyObject_GetAttrString (pyerr, "code");
+    if (!py_code || !PYGLIB_PyLong_Check (py_code)) {
+        PyErr_SetString (PyExc_ValueError,
+                         "GLib.Error instances must have a 'code' int attribute");
+        goto cleanup;
+    }
+
+    res = TRUE;
+    g_set_error_literal (error,
+                         g_quark_from_string (PYGLIB_PyUnicode_AsString (py_domain)),
+                         PYGLIB_PyLong_AsLong (py_code),
+                         PYGLIB_PyUnicode_AsString (py_message));
+
+cleanup:
+    Py_XDECREF (py_message);
+    Py_XDECREF (py_code);
+    Py_XDECREF (py_domain);
+    return res;
+}
+
+/**
  * pygi_gerror_exception_check:
  * @error: a standard GLib GError ** output parameter
  *
@@ -121,10 +180,8 @@ pygi_error_check (GError **error)
 gboolean
 pygi_gerror_exception_check (GError **error)
 {
+    int res = -1;
     PyObject *type, *value, *traceback;
-    PyObject *py_message, *py_domain, *py_code;
-    const char *bad_gerror_message;
-
     PyErr_Fetch(&type, &value, &traceback);
     if (type == NULL)
         return 0;
@@ -144,44 +201,14 @@ pygi_gerror_exception_check (GError **error)
     Py_DECREF(type);
     Py_XDECREF(traceback);
 
-    py_message = PyObject_GetAttrString(value, "message");
-    if (!py_message || !PYGLIB_PyUnicode_Check(py_message)) {
-        bad_gerror_message = "GLib.Error instances must have a 'message' string attribute";
-        Py_XDECREF(py_message);
-        goto bad_gerror;
-    }
-
-    py_domain = PyObject_GetAttrString(value, "domain");
-    if (!py_domain || !PYGLIB_PyUnicode_Check(py_domain)) {
-        bad_gerror_message = "GLib.Error instances must have a 'domain' string attribute";
-        Py_DECREF(py_message);
-        Py_XDECREF(py_domain);
-        goto bad_gerror;
-    }
-
-    py_code = PyObject_GetAttrString(value, "code");
-    if (!py_code || !PYGLIB_PyLong_Check(py_code)) {
-        bad_gerror_message = "GLib.Error instances must have a 'code' int attribute";
-        Py_DECREF(py_message);
-        Py_DECREF(py_domain);
-        Py_XDECREF(py_code);
-        goto bad_gerror;
+    if (!pygi_error_marshal_from_py (value, error)) {
+        PyErr_Print();
+        res = -2;
     }
 
-    g_set_error(error, g_quark_from_string(PYGLIB_PyUnicode_AsString(py_domain)),
-                PYGLIB_PyLong_AsLong(py_code), "%s", PYGLIB_PyUnicode_AsString(py_message));
-
-    Py_DECREF(py_message);
-    Py_DECREF(py_code);
-    Py_DECREF(py_domain);
-    return -1;
-
-bad_gerror:
     Py_DECREF(value);
-    g_set_error(error, g_quark_from_static_string("pygi"), 0, "%s", bad_gerror_message);
-    PyErr_SetString(PyExc_ValueError, bad_gerror_message);
-    PyErr_Print();
-    return -2;
+    return res;
+
 }
 
 /**
@@ -221,9 +248,27 @@ _pygi_marshal_from_py_gerror (PyGIInvokeState   *state,
                               GIArgument        *arg,
                               gpointer          *cleanup_data)
 {
-    PyErr_Format (PyExc_NotImplementedError,
-                  "Marshalling for GErrors is not implemented");
-    return FALSE;
+    GError *error = NULL;
+    if (pygi_error_marshal_from_py (py_arg, &error)) {
+        arg->v_pointer = error;
+        *cleanup_data = error;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+
+static void
+_pygi_marshal_from_py_gerror_cleanup  (PyGIInvokeState *state,
+                                       PyGIArgCache    *arg_cache,
+                                       PyObject        *py_arg,
+                                       gpointer         data,
+                                       gboolean         was_processed)
+{
+    if (was_processed) {
+        g_error_free ((GError *)data);
+    }
 }
 
 static PyObject *
@@ -235,7 +280,7 @@ _pygi_marshal_to_py_gerror (PyGIInvokeState   *state,
     GError *error = arg->v_pointer;
     PyObject *py_obj = NULL;
 
-    py_obj = pygi_error_marshal (&error);
+    py_obj = pygi_error_marshal_to_py (&error);
 
     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) {
         g_error_free (error);
@@ -261,7 +306,11 @@ pygi_arg_gerror_setup_from_info (PyGIArgCache  *arg_cache,
 
     if (direction & PYGI_DIRECTION_FROM_PYTHON) {
         arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror;
-        arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+
+        /* Assign cleanup function if we manage memory after call completion. */
+        if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
+            arg_cache->from_py_cleanup = _pygi_marshal_from_py_gerror_cleanup;
+        }
     }
 
     if (direction & PYGI_DIRECTION_TO_PYTHON) {
@@ -298,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)
 {
@@ -308,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);
 }
 
index 72d2be0..e7cc05f 100644 (file)
 
 G_BEGIN_DECLS
 
+extern PyObject *PyGError;
+
 gboolean      pygi_error_check              (GError **error);
 
-PyObject*     pygi_error_marshal            (GError **error);
+PyObject*     pygi_error_marshal_to_py      (GError **error);
+
+gboolean      pygi_error_marshal_from_py    (PyObject  *pyerr,
+                                             GError   **error);
 
 gboolean      pygi_gerror_exception_check   (GError **error);
 
index d84eed5..c379a88 100644 (file)
@@ -132,6 +132,38 @@ _struct_init (PyObject *self,
 
 PYGLIB_DEFINE_TYPE("gi.Struct", PyGIStruct_Type, PyGIStruct);
 
+
+PyObject *
+_pygi_struct_new_from_g_type (GType g_type,
+                              gpointer      pointer,
+                              gboolean      free_on_dealloc)
+{
+    PyGIStruct *self;
+    PyTypeObject *type;
+
+    type = (PyTypeObject *)pygi_type_import_by_g_type (g_type);
+
+    if (!type)
+        type = (PyTypeObject *)&PyGIStruct_Type; /* fallback */
+
+    if (!PyType_IsSubtype (type, &PyGIStruct_Type)) {
+        PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Struct");
+        return NULL;
+    }
+
+    self = (PyGIStruct *) type->tp_alloc (type, 0);
+    if (self == NULL) {
+        return NULL;
+    }
+
+    pyg_pointer_set_ptr (self, pointer);
+    ( (PyGPointer *) self)->gtype = g_type;
+    self->free_on_dealloc = free_on_dealloc;
+
+    return (PyObject *) self;
+}
+
+
 PyObject *
 _pygi_struct_new (PyTypeObject *type,
                   gpointer      pointer,
index ab303e0..347c55f 100644 (file)
@@ -31,6 +31,11 @@ _pygi_struct_new (PyTypeObject *type,
                   gpointer      pointer,
                   gboolean      free_on_dealloc);
 
+PyObject *
+_pygi_struct_new_from_g_type (GType g_type,
+                              gpointer      pointer,
+                              gboolean      free_on_dealloc);
+
 void _pygi_struct_register_types (PyObject *m);
 
 G_END_DECLS
index 2cf567d..9da87a5 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <Python.h>
 #include "pygi-value.h"
+#include "pygi-struct.h"
 #include "pyglib-python-compat.h"
 #include "pygobject-private.h"
 #include "pygtype.h"
@@ -775,9 +776,10 @@ pygi_value_to_py_structured_type (const GValue *value, GType fundamental, gboole
             return pyg_value_as_pyobject(n_value, copy_boxed);
         } else if (holds_value_array) {
             GValueArray *array = (GValueArray *) g_value_get_boxed(value);
-            PyObject *ret = PyList_New(array->n_values);
+            Py_ssize_t n_values = array ? array->n_values : 0;
+            PyObject *ret = PyList_New(n_values);
             int i;
-            for (i = 0; i < array->n_values; ++i)
+            for (i = 0; i < n_values; ++i)
                 PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
                         (array->values + i, copy_boxed));
             return ret;
@@ -809,7 +811,7 @@ pygi_value_to_py_structured_type (const GValue *value, GType fundamental, gboole
             Py_INCREF(Py_None);
             return Py_None;
         }
-        return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE);
+        return _pygi_struct_new_from_g_type (G_TYPE_VARIANT, g_variant_ref(v), FALSE);
     }
     default:
     {
@@ -832,13 +834,13 @@ pygi_value_to_py_structured_type (const GValue *value, GType fundamental, gboole
  * This function creates/returns a Python wrapper object that
  * represents the GValue passed as an argument.
  *
- * Returns: a PyObject representing the value.
+ * Returns: a PyObject representing the value or %NULL and sets an exception.
  */
 PyObject *
 pyg_value_as_pyobject (const GValue *value, gboolean copy_boxed)
 {
-    gchar buf[128];
     PyObject *pyobj;
+    const gchar *type_name;
     GType fundamental = G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value));
 
     /* HACK: special case char and uchar to return PyBytes intstead of integers
@@ -863,10 +865,16 @@ pyg_value_as_pyobject (const GValue *value, gboolean copy_boxed)
         return pyobj;
     }
 
-    g_snprintf(buf, sizeof(buf), "unknown type %s",
-               g_type_name(G_VALUE_TYPE(value)));
-    PyErr_SetString(PyExc_TypeError, buf);
+    if (!PyErr_Occurred ()) {
+        type_name = g_type_name (G_VALUE_TYPE (value));
+        if (type_name == NULL) {
+            type_name = "(null)";
+        }
+        PyErr_Format (PyExc_TypeError, "unknown type %s", type_name);
+    }
+
     return NULL;
+
 }
 
 
index 985e969..a3784c8 100644 (file)
@@ -704,7 +704,16 @@ pyg_closure_marshal(GClosure *closure,
 
            /* error condition */
            if (!item) {
-               goto out;
+            if (!PyErr_Occurred ())
+                PyErr_SetString (PyExc_TypeError,
+                                 "can't convert parameter to desired type");
+
+            if (pc->exception_handler)
+                pc->exception_handler (return_value, n_param_values, param_values);
+            else
+                PyErr_Print();
+
+            goto out;
            }
            PyTuple_SetItem(params, i, item);
        }
index 9d5db5e..233175c 100644 (file)
@@ -2,7 +2,14 @@ CLEANFILES =
 check_LTLIBRARIES = libgimarshallingtests.la
 test_typelibs = GIMarshallingTests-1.0.typelib
 
-nodist_libgimarshallingtests_la_SOURCES = $(GI_DATADIR)/tests/gimarshallingtests.c $(GI_DATADIR)/tests/gimarshallingtests.h
+nodist_libgimarshallingtests_la_SOURCES = \
+       $(GI_DATADIR)/tests/gimarshallingtests.c \
+       $(GI_DATADIR)/tests/gimarshallingtests.h
+
+dist_libgimarshallingtests_la_SOURCES = \
+       $(srcdir)/gimarshallingtestsextra.c \
+       $(srcdir)/gimarshallingtestsextra.h
+
 libgimarshallingtests_la_CFLAGS = $(GLIB_CFLAGS)
 libgimarshallingtests_la_LDFLAGS = -module -avoid-version $(GLIB_LIBS) -no-undefined
 
@@ -17,7 +24,9 @@ GIMarshallingTests-1.0.gir: libgimarshallingtests.la Makefile
        --library=libgimarshallingtests.la \
        --libtool="$(top_builddir)/libtool" \
        --output $@ \
-       $(nodist_libgimarshallingtests_la_SOURCES)
+       $(nodist_libgimarshallingtests_la_SOURCES) \
+       $(dist_libgimarshallingtests_la_SOURCES)
+
 GIMarshallingTests-1.0.typelib: GIMarshallingTests-1.0.gir Makefile
        $(AM_V_GEN) g-ir-compiler $< -o $@
 
index 838399c..05005e4 100644 (file)
@@ -106,9 +106,12 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 libgimarshallingtests_la_LIBADD =
+dist_libgimarshallingtests_la_OBJECTS =  \
+       libgimarshallingtests_la-gimarshallingtestsextra.lo
 nodist_libgimarshallingtests_la_OBJECTS =  \
        libgimarshallingtests_la-gimarshallingtests.lo
 libgimarshallingtests_la_OBJECTS =  \
+       $(dist_libgimarshallingtests_la_OBJECTS) \
        $(nodist_libgimarshallingtests_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -169,9 +172,11 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(nodist_libgimarshallingtests_la_SOURCES) \
+SOURCES = $(dist_libgimarshallingtests_la_SOURCES) \
+       $(nodist_libgimarshallingtests_la_SOURCES) \
        $(nodist_libregress_la_SOURCES) $(testhelper_la_SOURCES)
-DIST_SOURCES = $(testhelper_la_SOURCES)
+DIST_SOURCES = $(dist_libgimarshallingtests_la_SOURCES) \
+       $(testhelper_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -371,7 +376,14 @@ CLEANFILES = Regress-1.0.gir Regress-1.0.typelib \
 check_LTLIBRARIES = libgimarshallingtests.la $(am__append_1) \
        testhelper.la
 test_typelibs = GIMarshallingTests-1.0.typelib $(am__append_2)
-nodist_libgimarshallingtests_la_SOURCES = $(GI_DATADIR)/tests/gimarshallingtests.c $(GI_DATADIR)/tests/gimarshallingtests.h
+nodist_libgimarshallingtests_la_SOURCES = \
+       $(GI_DATADIR)/tests/gimarshallingtests.c \
+       $(GI_DATADIR)/tests/gimarshallingtests.h
+
+dist_libgimarshallingtests_la_SOURCES = \
+       $(srcdir)/gimarshallingtestsextra.c \
+       $(srcdir)/gimarshallingtestsextra.h
+
 libgimarshallingtests_la_CFLAGS = $(GLIB_CFLAGS)
 libgimarshallingtests_la_LDFLAGS = -module -avoid-version $(GLIB_LIBS) -no-undefined
 @ENABLE_CAIRO_TRUE@nodist_libregress_la_SOURCES = $(GI_DATADIR)/tests/regress.c $(GI_DATADIR)/tests/regress.h
@@ -501,6 +513,7 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgimarshallingtests_la-gimarshallingtestsextra.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libregress_la-regress.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-test-floating.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-test-thread.Plo@am__quote@
@@ -528,6 +541,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+libgimarshallingtests_la-gimarshallingtestsextra.lo: $(srcdir)/gimarshallingtestsextra.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) -MT libgimarshallingtests_la-gimarshallingtestsextra.lo -MD -MP -MF $(DEPDIR)/libgimarshallingtests_la-gimarshallingtestsextra.Tpo -c -o libgimarshallingtests_la-gimarshallingtestsextra.lo `test -f '$(srcdir)/gimarshallingtestsextra.c' || echo '$(srcdir)/'`$(srcdir)/gimarshallingtestsextra.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/libgimarshallingtests_la-gimarshallingtestsextra.Tpo $(DEPDIR)/libgimarshallingtests_la-gimarshallingtestsextra.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$(srcdir)/gimarshallingtestsextra.c' object='libgimarshallingtests_la-gimarshallingtestsextra.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) -c -o libgimarshallingtests_la-gimarshallingtestsextra.lo `test -f '$(srcdir)/gimarshallingtestsextra.c' || echo '$(srcdir)/'`$(srcdir)/gimarshallingtestsextra.c
+
 libgimarshallingtests_la-gimarshallingtests.lo: $(GI_DATADIR)/tests/gimarshallingtests.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) -MT libgimarshallingtests_la-gimarshallingtests.lo -MD -MP -MF $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Tpo -c -o libgimarshallingtests_la-gimarshallingtests.lo `test -f '$(GI_DATADIR)/tests/gimarshallingtests.c' || echo '$(srcdir)/'`$(GI_DATADIR)/tests/gimarshallingtests.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Tpo $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Plo
@@ -796,7 +816,9 @@ GIMarshallingTests-1.0.gir: libgimarshallingtests.la Makefile
        --library=libgimarshallingtests.la \
        --libtool="$(top_builddir)/libtool" \
        --output $@ \
-       $(nodist_libgimarshallingtests_la_SOURCES)
+       $(nodist_libgimarshallingtests_la_SOURCES) \
+       $(dist_libgimarshallingtests_la_SOURCES)
+
 GIMarshallingTests-1.0.typelib: GIMarshallingTests-1.0.gir Makefile
        $(AM_V_GEN) g-ir-compiler $< -o $@
 
diff --git a/tests/gimarshallingtestsextra.c b/tests/gimarshallingtestsextra.c
new file mode 100644 (file)
index 0000000..9624077
--- /dev/null
@@ -0,0 +1,37 @@
+/* gimarshallingtestsextra.c
+ *
+ * Copyright (C) 2016 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gimarshallingtestsextra.h"
+
+void
+gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1)
+{
+  GError *error, * error1;
+
+  g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v)), ==,
+                   g_type_name (G_TYPE_ERROR));
+  g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v1)), ==,
+                   g_type_name (G_TYPE_ERROR));
+
+  error = (GError*) g_value_get_boxed (v);
+  error1 = (GError*) g_value_get_boxed (v1);
+
+  g_assert_cmpint (error->domain, ==, error1->domain);
+  g_assert_cmpint (error->code, ==, error1->code);
+  g_assert_cmpstr (error->message, ==, error1->message);
+}
diff --git a/tests/gimarshallingtestsextra.h b/tests/gimarshallingtestsextra.h
new file mode 100644 (file)
index 0000000..6858551
--- /dev/null
@@ -0,0 +1,26 @@
+/* gimarshallingtestsextra.h
+ *
+ * Copyright (C) 2016 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EXTRA_TESTS
+#define EXTRA_TESTS
+
+#include <glib-object.h>
+
+void gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1);
+
+#endif /* EXTRA_TESTS */
index f5a89ce..5702490 100644 (file)
@@ -133,6 +133,12 @@ class TestMarshalling(unittest.TestCase):
         self.assertEqual(e.domain, 'mydomain')
         self.assertEqual(e.code, 42)
 
+    def tests_compare_two_gerrors_in_gvalue(self):
+        error = GLib.Error.new_literal(1, "error", 1)
+        error1 = GLib.Error.new_literal(1, "error", 1)
+
+        GIMarshallingTests.compare_two_gerrors_in_gvalue(error, error1)
+
 
 if __name__ == '__main__':
     unittest.main()
index 6c15e20..e78132d 100644 (file)
@@ -669,5 +669,28 @@ class TestGValue(unittest.TestCase):
         value = GObject.Value(GObject.TYPE_OBJECT, obj)
         self.assertEqual(value.get_value(), obj)
 
+    def test_value_array(self):
+        value = GObject.Value(GObject.ValueArray)
+        self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
+        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()
index 4f630dc..891923e 100644 (file)
@@ -495,6 +495,36 @@ class TestGVariant(unittest.TestCase):
         v = GLib.Variant('(is)', (1, 'somestring'))
         self.assertEqual(str(v), "(1, 'somestring')")
 
+    def test_parse_error(self):
+        # This test doubles as a test for GLib.Error marshaling.
+        source_str = 'abc'
+        with self.assertRaises(GLib.Error) as context:
+            GLib.Variant.parse(None, source_str, None, None)
+        e = context.exception
+        text = GLib.Variant.parse_error_print_context(e, source_str)
+        self.assertTrue(source_str in text)
+
+    def test_parse_error_exceptions(self):
+        source_str = 'abc'
+        self.assertRaisesRegexp(TypeError, 'Must be GLib.Error, not int',
+                                GLib.Variant.parse_error_print_context,
+                                42, source_str)
+
+        gerror = GLib.Error(message=42)  # not a string
+        self.assertRaisesRegexp(ValueError, ".*must have a 'message'.*",
+                                GLib.Variant.parse_error_print_context,
+                                gerror, source_str)
+
+        gerror = GLib.Error(domain=42)  # not a string
+        self.assertRaisesRegexp(ValueError, ".*must have a 'domain'.*",
+                                GLib.Variant.parse_error_print_context,
+                                gerror, source_str)
+
+        gerror = GLib.Error(code='not an int')
+        self.assertRaisesRegexp(ValueError, ".*must have a 'code' int.*",
+                                GLib.Variant.parse_error_print_context,
+                                gerror, source_str)
+
 
 class TestConstants(unittest.TestCase):