diff options
-rw-r--r-- | ChangeLog | 153 | ||||
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | PKG-INFO | 4 | ||||
-rwxr-xr-x | configure | 24 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | gi/overrides/GLib.py | 1 | ||||
-rw-r--r-- | gi/pygboxed.c | 8 | ||||
-rw-r--r-- | gi/pygi-error.c | 172 | ||||
-rw-r--r-- | gi/pygi-error.h | 7 | ||||
-rw-r--r-- | gi/pygi-struct.c | 32 | ||||
-rw-r--r-- | gi/pygi-struct.h | 5 | ||||
-rw-r--r-- | gi/pygi-value.c | 24 | ||||
-rw-r--r-- | gi/pygtype.c | 11 | ||||
-rw-r--r-- | tests/Makefile.am | 13 | ||||
-rw-r--r-- | tests/Makefile.in | 30 | ||||
-rw-r--r-- | tests/gimarshallingtestsextra.c | 37 | ||||
-rw-r--r-- | tests/gimarshallingtestsextra.h | 26 | ||||
-rw-r--r-- | tests/test_error.py | 6 | ||||
-rw-r--r-- | tests/test_gobject.py | 23 | ||||
-rw-r--r-- | tests/test_overrides_glib.py | 30 |
20 files changed, 540 insertions, 79 deletions
@@ -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 @@ -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) @@ -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 @@ -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\\" diff --git a/configure.ac b/configure.ac index 99ff6b2..3ed9aff 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ... 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/pygboxed.c b/gi/pygboxed.c index 30ab423..cdb766c 100644 --- a/gi/pygboxed.c +++ b/gi/pygboxed.c @@ -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) { diff --git a/gi/pygi-error.c b/gi/pygi-error.c index b019a09..d86021c 100644 --- a/gi/pygi-error.c +++ b/gi/pygi-error.c @@ -23,13 +23,14 @@ #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); } diff --git a/gi/pygi-error.h b/gi/pygi-error.h index 72d2be0..e7cc05f 100644 --- a/gi/pygi-error.h +++ b/gi/pygi-error.h @@ -27,9 +27,14 @@ 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); diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c index d84eed5..c379a88 100644 --- a/gi/pygi-struct.c +++ b/gi/pygi-struct.c @@ -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, diff --git a/gi/pygi-struct.h b/gi/pygi-struct.h index ab303e0..347c55f 100644 --- a/gi/pygi-struct.h +++ b/gi/pygi-struct.h @@ -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 diff --git a/gi/pygi-value.c b/gi/pygi-value.c index 2cf567d..9da87a5 100644 --- a/gi/pygi-value.c +++ b/gi/pygi-value.c @@ -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; + } diff --git a/gi/pygtype.c b/gi/pygtype.c index 985e969..a3784c8 100644 --- a/gi/pygtype.c +++ b/gi/pygtype.c @@ -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); } diff --git a/tests/Makefile.am b/tests/Makefile.am index 9d5db5e..233175c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 $@ diff --git a/tests/Makefile.in b/tests/Makefile.in index 838399c..05005e4 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -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 index 0000000..9624077 --- /dev/null +++ b/tests/gimarshallingtestsextra.c @@ -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 index 0000000..6858551 --- /dev/null +++ b/tests/gimarshallingtestsextra.h @@ -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 */ diff --git a/tests/test_error.py b/tests/test_error.py index f5a89ce..5702490 100644 --- a/tests/test_error.py +++ b/tests/test_error.py @@ -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() diff --git a/tests/test_gobject.py b/tests/test_gobject.py index 6c15e20..e78132d 100644 --- a/tests/test_gobject.py +++ b/tests/test_gobject.py @@ -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() diff --git a/tests/test_overrides_glib.py b/tests/test_overrides_glib.py index 4f630dc..891923e 100644 --- a/tests/test_overrides_glib.py +++ b/tests/test_overrides_glib.py @@ -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): |