From dacff02c31708d5a702fbbeb7f386be1bbb8918e Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 12 Jul 2017 08:39:41 +0900 Subject: [PATCH] Imported Upstream version 3.11.1 Change-Id: I6f6a69c5dd77017d0c62c4fbefa44a2e57514c47 Signed-off-by: DongHun Kwak --- ChangeLog | 836 +++++++++++++++++-- Makefile.am | 6 + Makefile.in | 18 +- NEWS | 29 +- PKG-INFO | 4 +- README | 3 +- aclocal.m4 | 137 +--- config.h.in | 3 + configure | 370 ++++----- configure.ac | 10 +- examples/Makefile.in | 2 +- gi/Makefile.in | 6 +- gi/_glib/Makefile.in | 6 +- gi/_glib/pyglib-python-compat.h | 1 + gi/_gobject/Makefile.in | 6 +- gi/_gobject/pygobject.c | 88 +- gi/docstring.py | 30 +- gi/gimodule.c | 6 + gi/overrides/GLib.py | 123 ++- gi/overrides/GObject.py | 95 +-- gi/overrides/Makefile.in | 2 +- gi/pygi-argument.c | 8 +- gi/pygi-cache.c | 526 ++++++------ gi/pygi-cache.h | 53 +- gi/pygi-closure.c | 30 +- gi/pygi-info.c | 1348 +++++++++++++++++++------------ gi/pygi-invoke-state-struct.h | 7 +- gi/pygi-invoke.c | 131 ++- gi/pygi-marshal-cleanup.c | 152 ++-- gi/pygi-marshal-cleanup.h | 14 + gi/pygi-marshal-from-py.c | 421 +++++----- gi/pygi-marshal-from-py.h | 61 +- gi/pygi-marshal-to-py.c | 55 +- gi/pygi.h | 1 + gi/repository/Makefile.in | 2 +- pygtkcompat/Makefile.in | 2 +- tests/Makefile.am | 11 +- tests/Makefile.in | 17 +- tests/test_docstring.py | 10 + tests/test_everything.py | 45 ++ tests/test_gi.py | 122 ++- tests/test_glib.py | 21 + tests/test_gobject.py | 41 +- tests/test_repository.py | 344 ++++++++ tests/test_signal.py | 5 +- tests/test_source.py | 18 +- tests/test_subprocess.py | 88 +- 47 files changed, 3464 insertions(+), 1850 deletions(-) create mode 100644 tests/test_repository.py diff --git a/ChangeLog b/ChangeLog index 7c4d231..0f4c934 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,13 +1,13 @@ -commit 7b037393e640711f54837794c942003b3a8df0af +commit 5bcdb56433d0ba2976f05946c6c5b6ffe3e84901 Author: Martin Pitt -Date: Mon Nov 11 14:58:19 2013 +0100 +Date: Mon Oct 28 15:59:51 2013 +0100 - release 3.10.2 + release 3.11.1 - NEWS | 4 ++++ - 1 file changed, 4 insertions(+) + NEWS | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) -commit 9c44080f95c4c73688a34cf8033605c049fed77d +commit 65b8f7bd77474e361c80905ec23de6dbde27970c Author: Simon Feltman Date: Sun Oct 27 22:09:27 2013 -0700 @@ -24,62 +24,78 @@ Date: Sun Oct 27 22:09:27 2013 -0700 https://bugzilla.gnome.org/show_bug.cgi?id=709223 + gi/__init__.py | 2 -- gi/gimodule.c | 18 +++++++----------- - gi/overrides/GLib.py | 8 +++++++- - 2 files changed, 14 insertions(+), 12 deletions(-) + gi/overrides/GLib.py | 8 ++------ + 3 files changed, 9 insertions(+), 19 deletions(-) -commit 9f913abdfa46af3c6ddf2fd35f1fb0e08d7791d4 -Author: Martin Pitt -Date: Mon Nov 11 14:34:12 2013 +0100 +commit 57195c9c864bc25521bb3cb98286e6d6f0645652 +Author: Simon Feltman +Date: Sun Oct 27 16:02:13 2013 -0700 - Revert "Add type checking to positional Gtk.Box and Gtk.Window - ctor arguments" + Add consistent GLib.MainLoop SIGINT cleanup - While this enforces correctness, this can cause new crashes in - software which - incorrectly uses the GObject constructor and needs - fixing. E. g. Ubuntu's - current sofware-center (wrongly) does + Remove auto cleanup of SIGINT source handling by returning True + from the + signal callback. This gives the __del__ method consistent cleanup + semantics + regardless of whether or not a SIGINT occurred. - Gtk.Box(Gtk.Orientation.HORIZONTAL) + https://bugzilla.gnome.org/show_bug.cgi?id=710978 - which now causes a crash with this new check. + gi/overrides/GLib.py | 4 ++++ + 1 file changed, 4 insertions(+) - This reverts commit 2cc4dfaf877f202977de4a7ede24aa3bad7d91c8. +commit 1c03ebba9598e7b6d5293889f46b015bfac3611c +Author: Simon Feltman +Date: Sun Oct 27 15:16:09 2013 -0700 - gi/overrides/Gtk.py | 7 ------- - tests/test_overrides_gtk.py | 18 ------------------ - tests/test_properties.py | 9 --------- - 3 files changed, 34 deletions(-) + tests: Fix source testing to handle critical with non-existing sources -commit 2cc4dfaf877f202977de4a7ede24aa3bad7d91c8 -Author: Martin Pitt -Date: Tue Nov 5 15:28:12 2013 +0100 + Silence new critical coming from g_source_remove on non-existing + sources. + This function still returns False, but we need to silence the new + critical + so the test suite doesn't fail. See bug 710724. - Add type checking to positional Gtk.Box and Gtk.Window ctor arguments + https://bugzilla.gnome.org/show_bug.cgi?id=710978 - Gtk.Box and Gtk.Window are base classes of a lot of widgets. Avoid - confusion - when trying to create a subclass of them through the GObject - constructor with - positional arguments by at least verifying that their type is - right. Otherwise - you can do things like + tests/test_source.py | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +commit ac776da7e56b78a2fa422487f0ef0d8771bcb78f +Author: Simon Feltman +Date: Sun Jul 28 00:01:35 2013 -0700 - chooser = Gtk.FileChooserWidget(Gtk.FileChooserAction.SELECT_FOLDER) + docs: Add a keyword value of None for allow-none annotations - which succeeds, but does not have the desired effect (it sets the - "homogenous" - property of the Gtk.Box superclass instead). + Update documentation generator for allow-none arguments and + user_data arguments to show a keyword value of None. + Add skip for GDestroyNotify closure arguments. - https://bugzilla.gnome.org/show_bug.cgi?id=711487 + https://bugzilla.gnome.org/show_bug.cgi?id=640812 - gi/overrides/Gtk.py | 7 +++++++ - tests/test_overrides_gtk.py | 18 ++++++++++++++++++ - tests/test_properties.py | 9 +++++++++ - 3 files changed, 34 insertions(+) + gi/docstring.py | 20 +++++++++++++++++--- + tests/test_docstring.py | 10 ++++++++++ + 2 files changed, 27 insertions(+), 3 deletions(-) -commit 7036e9d79ed49fe153758ec0507d6af62f067f2f +commit e1bf9c069644ea0bff0c6a7efa72a285e122a414 +Author: Simon Feltman +Date: Sat Oct 19 19:03:12 2013 -0700 + + Remove overrides for supporting pre-3.10 GObject signal functions + + Remove GObject override code for supporting pre-3.10 signal functions + which + annotate the object argument as "gpointer". With PyGObject 3.11 + having a + dependency on GObject 3.10, clear the special case overrides out. + + gi/overrides/GObject.py | 76 + ++++++------------------------------------------- + 1 file changed, 9 insertions(+), 67 deletions(-) + +commit 0c308de528c402f67808b13760ca30d55d4c99d7 Author: Simon Feltman Date: Fri Oct 18 17:15:06 2013 -0700 @@ -96,29 +112,157 @@ Date: Fri Oct 18 17:15:06 2013 -0700 https://bugzilla.gnome.org/show_bug.cgi?id=710447 + gi/__init__.py | 2 ++ gi/gimodule.c | 10 ++++++++++ - gi/overrides/GLib.py | 9 +-------- - 2 files changed, 11 insertions(+), 8 deletions(-) + gi/overrides/GLib.py | 11 +++++++---- + 3 files changed, 19 insertions(+), 4 deletions(-) -commit 26c34534f8771e0ee31cf37eb8df3be8cb1cb2f6 -Author: Martin Pitt -Date: Mon Oct 14 12:54:36 2013 +0200 +commit a2fa531b4dee73c193cac92fa3e870808688b5d7 +Author: Simon Feltman +Date: Mon Oct 14 20:38:13 2013 -0700 - configure.ac: Post-release bump to 3.10.2 + Add dir method to GObject props accessor - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + Remove special case __members__ attribute from the props accessor + objects getattr method. This has been deprecated since Python 2.3 and + removed in Python 3. Replace this with a __dir__ method making use + of the + old members list building code. Additionally fix error where the + GObjectClass was being unref'd too many times when using + dir(Object.props), + causing a GLib critical. + + https://bugzilla.gnome.org/show_bug.cgi?id=705754 + + gi/_gobject/pygobject.c | 29 +++++++++++++++++++++-------- + tests/test_gi.py | 14 ++++++++++++++ + 2 files changed, 35 insertions(+), 8 deletions(-) + +commit 799989ada2f6b1d729f078f204445651c808a2c7 +Author: Simon Feltman +Date: Fri May 3 04:37:13 2013 -0700 + + Remove PyGObjectWeakRef now that g_binding_unbind exists + + Remove the static code for managing GBinding weak references now + that GLib + has a method (unbind) for clearing out bindings. + + https://bugzilla.gnome.org/show_bug.cgi?id=699571 + + gi/_gobject/pygobject.c | 59 + +------------------------------------------------ + gi/overrides/GObject.py | 19 ++++++++++++++++ + tests/test_gobject.py | 41 ++++++++++++++++++++-------------- + 3 files changed, 44 insertions(+), 75 deletions(-) -commit 863124b6268d1ea2c649d27771813c27cc9faa06 +commit fe217e0afbd63f05285e59628533f351896377d9 +Author: Simon Feltman +Date: Wed Oct 9 00:34:37 2013 -0700 + + Fix GArray, GList, GSList, and GHashTable marshaling leaks + + Remove calling of cleanup code for transfer-everything modes by + ensuring + cleanup_data is set to NULL in from_py marshalers. Use array and hash + table ref/unref functions for container transfer mode to ensure we + have a + valid container ref after invoke and during from_py cleanup of + contents. + Rework restrictions with to_py marshaling cleanup so we always + unref the + container for transfer-everything and transfer-container modes. + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-marshal-cleanup.c | 54 +++++++++++---------------------- + gi/pygi-marshal-from-py.c | 77 + ++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 84 insertions(+), 47 deletions(-) + +commit 7407367f424595c2780a2d6a47d936ad0bd91735 +Author: Simon Feltman +Date: Mon Oct 7 14:11:39 2013 -0700 + + Add cleanup_data argument used for Python to C marshaler cleanup + + Add a new output argument to all from_py marshalers which is used for + keeping track of marshaling data that later needs cleanup. Previously + most + marshalers would rely on the GIArgument->v_pointer as the means + for data + cleanup. However, this pointer would get clobbered in the case of + bi-directional arguments (inout) and the memory lost. + Use the new cleanup_data for storing temporarily wrapped C arrays + so we + don't need to re-calculate the length argument during cleanup. + + Additionally delay the from_py marshaling cleanup function until after + _invoke_marshal_out_args is called. This gives inout arguments + which don't + modify the pointer sufficient time to exist until they marshaled + back to + Python (gi_marshalling_tests_gvalue_inout). + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-argument.c | 4 +- + gi/pygi-cache.h | 3 +- + gi/pygi-invoke-state-struct.h | 7 +- + gi/pygi-invoke.c | 20 +++--- + gi/pygi-marshal-cleanup.c | 43 +++++------- + gi/pygi-marshal-from-py.c | 160 + ++++++++++++++++++++++++++++-------------- + gi/pygi-marshal-from-py.h | 45 ++++++++---- + 7 files changed, 177 insertions(+), 105 deletions(-) + +commit 9456e83233a927f1f01c6ffcb1f07c62b491a1df +Author: Simon Feltman +Date: Wed Aug 7 12:08:15 2013 -0700 + + Add support for variable user data arguments + + Support a variable number of user data arguments for all callback + connection function where the user data is the last explicit argument. + This adds convience as well as consistency with the rest of PyGObject. + Cleanup overrides for GLib.idle_add, timeout_add, timeout_add_seconds, + io_add_watch, and child_watch_add which manually implemented this + feature. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/overrides/GLib.py | 75 + +++++++++++++++-------------------------------- + gi/pygi-cache.c | 14 +++++++++ + gi/pygi-cache.h | 3 ++ + gi/pygi-closure.c | 37 +++++++++++++++-------- + gi/pygi-invoke.c | 71 + +++++++++++++++++++++++++++++++------------- + gi/pygi-marshal-from-py.c | 5 ++++ + tests/test_everything.py | 32 ++++++++++++++++++++ + tests/test_glib.py | 21 +++++++++++++ + tests/test_subprocess.py | 8 ++--- + 9 files changed, 177 insertions(+), 89 deletions(-) + +commit ba4a0a65bf9ec44c3b9449f63d63035bff75d8df Author: Martin Pitt -Date: Mon Oct 14 12:51:44 2013 +0200 +Date: Mon Oct 14 12:57:04 2013 +0200 - release 3.10.1 + Bump glib and g-i dependencies to latest stable. - NEWS | 8 ++++++++ - 1 file changed, 8 insertions(+) + glib 2.38 and g-i 1.38 are from stable GNOME 3.10 which we now + assume as + minimal version. + + Drop @unittest.skipUnless tags from tests which didn't work with + g-i 1.36. -commit 43ac1f9fd4b1f5132b7fa996da7e307371d11bb1 + README | 3 ++- + configure.ac | 6 +++--- + tests/test_gi.py | 2 -- + 3 files changed, 5 insertions(+), 6 deletions(-) + +commit 2a5ad2af6bc91b187a2f07fc8d001ec7ad618adf Author: Nuno Araujo Date: Fri Oct 11 18:41:48 2013 +0200 @@ -147,7 +291,7 @@ Date: Fri Oct 11 18:41:48 2013 +0200 tests/test_overrides_gtk.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) -commit 90beeee7600bf39768c38bcfc47582c0e592eec9 +commit 27e9f6ede021fc58e952491b67d69c2a5cdd6acb Author: Simon Feltman Date: Tue Oct 1 17:09:39 2013 -0700 @@ -172,7 +316,374 @@ Date: Tue Oct 1 17:09:39 2013 -0700 gi/_gobject/pygobject.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) -commit 073f3870f2671a387d99529bab386f2218f44e2e +commit 55d925d5f0fb87464b1f391c325c1e70da10d33d +Author: Simon Feltman +Date: Thu Oct 10 16:10:16 2013 -0700 + + Add expected failure to deal with fixes in gimarshallingtests.c + + Fix test_object_full_inout based on newer gimarshallingtests.c > + 1.38.0. + Add expectedFailure to deal with previous versions of + gimarshallingtests.c. + + https://bugzilla.gnome.org/show_bug.cgi?id=709796 + + tests/test_gi.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +commit d866d422cc39b229f443dd08a3ea50cb3f7df8e6 +Author: Simon Feltman +Date: Mon Oct 7 01:17:08 2013 -0700 + + Fix memory leaks for inout array arguments + + Add tracking for array allocations to from_py marashalers in the + argument states extra data (arg_data). This is then used later + for inout + marshaling cleanup to call the array cleanup function. + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-invoke.c | 1 + + gi/pygi-marshal-cleanup.c | 1 + + gi/pygi-marshal-from-py.c | 13 +++++++++---- + 3 files changed, 11 insertions(+), 4 deletions(-) + +commit 31263ac117027446c8e2fd1b56d7e348384aabef +Author: Simon Feltman +Date: Sun Oct 6 21:54:15 2013 -0700 + + Fix to Python marshaling leaks for arrays holding GVariants + + Add early check for array items holding pointers and simply assign the + pointer to GIArgument.v_pointer prior giving it to the per-item + marshaler. + This simplifies marshaling and fixes leaks regarding arrays of + GVariants by + removing the unneeded g_variant_ref_sink (variants are always + pointers). + Conditionalize the use of g_variant_ref_sink based on transfer mode + in the + per-item marshaler. This fixes a reference leak where we are given + ownership + of the variant (transfer full) but added a new ref anyway. + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-marshal-to-py.c | 34 ++++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 16 deletions(-) + +commit c9580ce1156789221aa19b00c7aab404db5431b5 +Author: Simon Feltman +Date: Sun Oct 6 04:26:18 2013 -0700 + + Cleanup per-item array marshaling code for flat arrays + + Add an early per-item check which tests if the item being marshaled + is a + pointer and simply copies the pointer into the array. This takes + care of the + GdkAtom and GVariant special cases because these items are always + reported + as pointers. + Fix error condition cleanup code when an item fails marshaling in + the middle + of an array. + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-marshal-from-py.c | 87 + +++++++++++++++++++++-------------------------- + tests/test_gi.py | 32 +++++++++++++++++ + 2 files changed, 71 insertions(+), 48 deletions(-) + +commit 4623caa71c54958ab821db27a9eff2790acb3975 +Author: Simon Feltman +Date: Sat Oct 5 17:00:54 2013 -0700 + + Fix GValue array marshaling leaks and crash fallout + + * Decrement references for results of PySequence_GetItem. There were + a few + places we were not decrementing the Python reference, leaking + the value. + * Add tracking of Python arguments with recursive marshaling + cleanup. This + allows arrays of GValues which have been coerced from Python types + to be + properly free'd (also fixes bug 703662). + * Use g_variant_ref for variant arguments marked as transfer + everything. + This fixes double free's caused by the decrementing of + PySequence_GetItem + results. + + https://bugzilla.gnome.org/show_bug.cgi?id=693402 + + gi/pygi-cache.h | 1 + + gi/pygi-invoke.c | 1 + + gi/pygi-marshal-cleanup.c | 50 + +++++++++++++++++++++++++++++++++++++++++------ + gi/pygi-marshal-cleanup.h | 14 +++++++++++++ + gi/pygi-marshal-from-py.c | 20 ++++++++++++++++--- + gi/pygi-marshal-to-py.c | 1 + + 6 files changed, 78 insertions(+), 9 deletions(-) + +commit 549f849ef8854352483657df3d7558688a4b0007 +Author: Simon Feltman +Date: Sat Sep 28 00:26:28 2013 -0700 + + Refactor GLib.io_add_watch to make it more testable + + Break the argument munging code into a separate function which + can be tested in isolation of adding an io watch. + Add additional failing test which specifies all args as keywords + which we eventually need to support for consistency with the + rest of PyGObject. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/overrides/GLib.py | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +commit bc780ed17bc4cc62959c63c3f0142161a924679f +Author: Simon Feltman +Date: Fri Sep 27 20:59:45 2013 -0700 + + Refactor GLib.child_watch_add to make it more testable + + Break the argument munging code into a separate function which + can be tested in isolation of adding a child watch. Update tests + to reflect this. Add additional failing test which specify + all args as keywords which we eventually need to support for + consistency with the rest of PyGObject. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/overrides/GLib.py | 25 +++++++++----- + tests/test_subprocess.py | 88 + +++++++++++++++++++++--------------------------- + 2 files changed, 56 insertions(+), 57 deletions(-) + +commit 73c6213e8b47fa7c4c2c7a517fe7b56126145888 +Author: Simon Feltman +Date: Thu Sep 26 19:05:20 2013 -0700 + + Don't pass None to callbacks when user data is not specified + + For APIs which support a callback and optional user data, + don't pass the user data to the callback if it was not explicitly + specified when the callback was connected. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-closure.c | 17 ++++++++++++++--- + gi/pygi-marshal-from-py.c | 5 ----- + tests/test_everything.py | 7 ++----- + 3 files changed, 16 insertions(+), 13 deletions(-) + +commit a76b06179cdca43f1c7d1feb8e2563e3d884a8ff +Author: Simon Feltman +Date: Fri Oct 4 17:27:47 2013 -0700 + + Add missing methods on PyGIBaseInfo and sub-classes + + Expose all methods of GIBaseBase info and its sub-classes. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/_glib/pyglib-python-compat.h | 1 + + gi/pygi-info.c | 550 + +++++++++++++++++++++++++++++++++++++++- + tests/test_repository.py | 134 ++++++++++ + 3 files changed, 677 insertions(+), 8 deletions(-) + +commit e190eb75093e8bf36190dc1beb18d1c1b95b9582 +Author: Simon Feltman +Date: Fri Oct 4 13:46:36 2013 -0700 + + Expose all GI enum and flags types + + Add new types for GIDirection, GITransfer, GIArrayType, GIScopeType, + GIVFuncInfoFlags, GIFieldInfoFlags, GIFuncitonInfoFlags, GITypeTag, + and + GInfoType. These types are found in the gi._gi module exposed + without the + "GI" prefix and contain all of their values as class attributes. e.g. + gi._gi.Transfer.EVERYTHING. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/docstring.py | 10 ++-- + gi/pygi-info.c | 150 + ++++++++++++++++++++++++++++++++++++++++++++--- + tests/test_repository.py | 13 +++- + 3 files changed, 158 insertions(+), 15 deletions(-) + +commit 0120af6c418d0f67f39c02a4e8327813645b97f4 +Author: Simon Feltman +Date: Fri Oct 4 13:42:34 2013 -0700 + + Avoid calling g_base_info_get_name on GI_INFO_TYPE_TYPE + + Calling g_base_info_get_name on infos tagged with GI_INFO_TYPE_TYPE + will + cause a crash. Avoid this by adding _safe_base_info_get_name and + using that + throughout the bindings. + Logged GI bug as: https://bugzilla.gnome.org/show_bug.cgi?id=709456 + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 35 +++++++++++++++++++++++++---------- + 1 file changed, 25 insertions(+), 10 deletions(-) + +commit c86b2fe8d01070f06c45fffd910d890afba1313a +Author: Simon Feltman +Date: Fri Oct 4 13:41:08 2013 -0700 + + Add GIBaseInfo.equal method + + Break PyGIBaseInfo rich compare into two methods: equal and + richcompare. + Equal is a direct exposure of the GI method and richcompare makes + use of + this with additional support for Pyton "==" and "!=" operators. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 32 ++++++++++++++++++++++++-------- + tests/test_repository.py | 1 + + 2 files changed, 25 insertions(+), 8 deletions(-) + +commit e7b758badd0ab0b147117859f7871c39fb5399c1 +Author: Simon Feltman +Date: Fri Oct 4 13:36:11 2013 -0700 + + Move info string retrieval into generic function + + Add get_info_string for sharing binding of simple string retrieval on + GIBaseInfo objects. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +commit d2aef364de778da966bc1cfffe184d649f9ebb21 +Author: Simon Feltman +Date: Tue Sep 24 06:26:17 2013 -0700 + + Move child info retrieval into generic function + + Add a generic function for bindings which return a single child info. + This trivializes binding methods like PyGIObjectInfo.get_parent and + fixes leaks in PyGIObjectInfo.get_class_struct and + PyGIVFuncInfo.get_invoker. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 56 + +++++++++++++++++++++++--------------------------------- + 1 file changed, 23 insertions(+), 33 deletions(-) + +commit cdd03a2b0baef19797a5b55c2880e5b7acf1dd93 +Author: Simon Feltman +Date: Tue Sep 24 02:52:22 2013 -0700 + + Move info tuple retrieval into generic function + + Create new generic function for retrieving a tuple of child infos. + This greatly simplifies all the bindings which return tuples from + a common pattern of functions on GIBaseInfo based instances. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 469 + ++++++++------------------------------------------------- + 1 file changed, 59 insertions(+), 410 deletions(-) + +commit 62f185bef20b42f18290a3cf1d3b19dddc957f8a +Author: Simon Feltman +Date: Sun Oct 6 16:41:37 2013 -0700 + + tests: Update check.valgrind with always-malloc and add logging + options + + Based on notes in https://wiki.gnome.org/Valgrind we need to use + always-malloc for valgrind runs. + Add check.valgrindlog and check.valgrindxml which output valgrind + logs into + an ignored local tmp. Output logs are named -$TEST_NAMES.log + so we + can track commits and use diff tools on the logs. + + .gitignore | 1 + + Makefile.am | 6 ++++++ + tests/Makefile.am | 10 +++++++++- + 3 files changed, 16 insertions(+), 1 deletion(-) + +commit 314c933626c4dc5fc585d0e5b6c45ddb17c2e52f +Author: Simon Feltman +Date: Fri Oct 4 20:43:02 2013 -0700 + + Move existing repository tests into test_repository + + Move flags and enum double registration tests into test_repository.py. + Remove duplicate ObjectInfo tests from test_gi.py. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + tests/test_gi.py | 38 -------------------------------------- + tests/test_repository.py | 28 ++++++++++++++++++++++++++++ + 2 files changed, 28 insertions(+), 38 deletions(-) + +commit 31840888c8948aab78041da93c329572f3aabb64 +Author: Simon Feltman +Date: Fri Oct 4 17:31:21 2013 -0700 + + Add unittests for GIRepository + + Add basic unittests for the existing classes and methods exposed for + the GIRepository module (gi._gi). + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + tests/Makefile.am | 1 + + tests/test_repository.py | 170 + +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 171 insertions(+) + +commit 4408f83be70e92c5e3943f5ce85c551e7f2c87d0 +Author: Simon Feltman +Date: Fri Oct 4 15:50:05 2013 -0700 + + Derive SignalInfo info from CallableInfo + + Change Python class derivation of PyGISignalInfo to use + PyGICallableInfo as + the base class. This accurately reflects the GI class layout and + provides + the callable information for signals. + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +commit b01daba04ff001b9e63d343938e879d339d9a98c +Author: Simon Feltman +Date: Fri Oct 4 15:48:05 2013 -0700 + + Use PYGLIB_PyLong_FromLong for GIDirection return + + https://bugzilla.gnome.org/show_bug.cgi?id=709008 + + gi/pygi-info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit d644cbd0c0ad85142286754838db848c4eb1707f Author: Simon Feltman Date: Thu Oct 3 19:25:34 2013 -0700 @@ -193,6 +704,207 @@ Date: Thu Oct 3 19:25:34 2013 -0700 gi/pygi-marshal-cleanup.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) +commit 510789d52e9e2fd863d26613f3282364eb175601 +Author: Simon Feltman +Date: Sun Jul 28 14:44:51 2013 -0700 + + Add support for default arguments annotated with allow-none + + Support default value of NULL for tail end arguments which are + marked with allow-none. + The implementation uses a place holder object for un-supplied + arguments + which are annotated with allow-none. This is then used later during + marshaling to supply NULL as the default. + Additionally support an implicit default for callback user_data + using the same technique. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/gimodule.c | 6 +++ + gi/pygi-cache.c | 103 + ++++++++++++++++++++++++++++++---------------- + gi/pygi-cache.h | 8 ++++ + gi/pygi-invoke.c | 42 +++++++++++++------ + gi/pygi-marshal-from-py.c | 5 +++ + gi/pygi.h | 1 + + tests/test_everything.py | 16 +++++++ + tests/test_gi.py | 30 ++++++++++++++ + 8 files changed, 162 insertions(+), 49 deletions(-) + +commit 03f531ffb1adde0c48e98f92bd92f79416654fbe +Author: Simon Feltman +Date: Fri Aug 2 22:27:10 2013 -0700 + + cache refactoring: Move arg cache field assignments into + _arg_cache_new + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +commit cb7e7311bff57eb4c79c7772b6db4d00084656bb +Author: Simon Feltman +Date: Fri Aug 2 20:27:02 2013 -0700 + + cache refactoring: Cleanup array length argument marshaling + + Add shared function: _arg_cache_array_len_arg_setup for use + with both to and from array marshaling setup. This function + consolidates all of the edge cases regarding array length setup + and removes the need for flagging arguments with + PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 145 + +++++++++++++++++++++++++++----------------------------- + gi/pygi-cache.h | 5 -- + 2 files changed, 71 insertions(+), 79 deletions(-) + +commit c9d8639401ae82977e960de44d80b94a501a2184 +Author: Simon Feltman +Date: Sat Aug 3 00:26:11 2013 -0700 + + cache refactoring: Move variable declarations to blocks where they + are used + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +commit dbc2cf5f1fa0f9cc046170efa6afb086b90253cb +Author: Simon Feltman +Date: Thu Aug 1 19:33:27 2013 -0700 + + cache refactoring: Remove continue statements from + _args_cache_generate + + Remove continue and goto statements from the large loop within + _args_cache_generate. This simplifies the sharing of parts of + the loop for future refactoring. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 126 + +++++++++++++++++++++++++++----------------------------- + 1 file changed, 61 insertions(+), 65 deletions(-) + +commit 87ae14b8b4a0ed9beb22f48314247e988a2e017f +Author: Simon Feltman +Date: Wed Jul 31 18:10:05 2013 -0700 + + cache refactoring: Use bit field for PyGIDirection instead of enum + + This supports cleaner logic when testing the direction of + arguments due to the majority of these tests being along the + lines of: (direction == FROM_PYTHON || direction == BIDIRECTIONAL) + Which is replaced with: (direction & FROM_PYTHON) + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 64 + ++++++++++++++++++++++++++++----------------------------- + gi/pygi-cache.h | 6 +++--- + 2 files changed, 35 insertions(+), 35 deletions(-) + +commit d5925b76afa3a429092cbafd82aed40bb0cf0b18 +Author: Simon Feltman +Date: Sun Jul 28 20:45:05 2013 -0700 + + cache refactoring: Remove special case marshaling for instance + arguments + + Remove duplicate code for marshaling struct and objects for + instance arguments. Re-use individual cache marshalers for + structs and objects with the instance argument. This required + removal of passing GITypeInfo to the marshaler because it is + not available for instance arguments. Instead always assume + "is_pointer" for the instance argument by using the cache. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-argument.c | 4 +-- + gi/pygi-cache.c | 16 ++++----- + gi/pygi-marshal-from-py.c | 87 + +++-------------------------------------------- + gi/pygi-marshal-from-py.h | 16 ++------- + 4 files changed, 16 insertions(+), 107 deletions(-) + +commit c19bed69c669160737e12d92cc29f3e6d1b008cc +Author: Simon Feltman +Date: Sun Jul 28 16:44:01 2013 -0700 + + cache refactoring: Use GPtrArray for callable arg cache + + Replace manual management of the C array holding individual + argument caches with usage of GPtrArray. This provides storage + of the array length along with item memory management. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 62 + +++++++++++++++++++++++------------------------ + gi/pygi-cache.h | 16 +++++++++--- + gi/pygi-invoke.c | 16 ++++++------ + gi/pygi-marshal-cleanup.c | 8 +++--- + gi/pygi-marshal-from-py.c | 6 ++--- + gi/pygi-marshal-to-py.c | 6 ++--- + 6 files changed, 62 insertions(+), 52 deletions(-) + +commit 52ea3afb0a6494423eca36a54af928d4ae5d9954 +Author: Simon Feltman +Date: Sun Jul 28 15:02:51 2013 -0700 + + cache refactoring: Move PyGI direction code into new function + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.c | 42 +++++++++++++++++++++--------------------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +commit 83208bf495b152e93a28a231d445f43ea827d2eb +Author: Simon Feltman +Date: Fri Aug 2 15:59:25 2013 -0700 + + cache refactoring: Add comments to callable cache structure + + Add comments to count fields on _PyGICallableCache. + + https://bugzilla.gnome.org/show_bug.cgi?id=640812 + + gi/pygi-cache.h | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +commit 0a8d5695972601eaa9f7f463bac173d02b0380a0 +Author: Simon Feltman +Date: Wed Jul 24 01:14:29 2013 -0700 + + Remove support for allowing PyObjects as void pointers + + Final removal of marshaling Python object addresses as + void pointers. This ensures we can successfully pass + integer values as the pointer without the Python object + leaking or crashing due to invalid memory. + + https://bugzilla.gnome.org/show_bug.cgi?id=688081 + + gi/pygi-marshal-from-py.c | 20 ++++++-------------- + gi/pygi-marshal-to-py.c | 14 ++------------ + tests/test_signal.py | 5 +---- + 3 files changed, 9 insertions(+), 30 deletions(-) + +commit 1469403ee2faa699430055384b338f0cd8e672d7 +Author: Simon Feltman +Date: Wed Sep 25 18:21:22 2013 -0700 + + configure.ac: bump trunk to 3.11.1 + + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + commit 8e774e61d62c82efa3d907c1201359121878b4b5 Author: Simon Feltman Date: Mon Sep 23 03:57:03 2013 -0700 diff --git a/Makefile.am b/Makefile.am index 5e91024..5051b54 100644 --- a/Makefile.am +++ b/Makefile.am @@ -148,4 +148,10 @@ check.nemiver: check.valgrind: cd tests && $(MAKE) check.valgrind +check.valgrindlog: + cd tests && $(MAKE) check.valgrindlog + +check.valgrindxml: + cd tests && $(MAKE) check.valgrindxml + @GNOME_CODE_COVERAGE_RULES@ diff --git a/Makefile.in b/Makefile.in index 71694fb..b4528f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -493,8 +493,8 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 @@ -767,16 +767,10 @@ dist-xz: distdir $(am__post_remove_distdir) dist-tarZ: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) @@ -1095,6 +1089,12 @@ check.nemiver: check.valgrind: cd tests && $(MAKE) check.valgrind +check.valgrindlog: + cd tests && $(MAKE) check.valgrindlog + +check.valgrindxml: + cd tests && $(MAKE) check.valgrindxml + @GNOME_CODE_COVERAGE_RULES@ # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/NEWS b/NEWS index 5d9b042..f0a4503 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,29 @@ -3.10.2 11-Nov-2013 - - Fix thread safety problems by always enabling the GIL - (Simon Feltman) (#709223, #710447) - -3.10.1 14-Oct-2013 +3.11.1 28-Oct-2013 + - Fix toggleref safety problems by always enabling the GIL + (Simon Feltman) (#709223) + - Add consistent GLib.MainLoop SIGINT cleanup (Simon Feltman) (#710978) + - docs: Add a keyword value of None for allow-none annotations + (Simon Feltman) (#640812) + - Remove overrides for supporting pre-3.10 GObject signal functions + (Simon Feltman) + - Add threads_init back as a requirement for non-Python threaded repos + (Simon Feltman) (#710447) + - Add dir method to GObject props accessor (Simon Feltman) (#705754) + - Remove PyGObjectWeakRef now that g_binding_unbind exists + (Simon Feltman) (#699571) + - Fix lots of memory leaks leaks (Simon Feltman) (#693402, #709397) + - Add support for variable user data arguments (Simon Feltman) (#640812) + - Bump glib and g-i dependencies to latest stable. (Martin Pitt) - Fix TypeError when setting drag target_list to None (Nuno Araujo) (#709926) - Use qdata for wrapper retrieval in toggle reference notifications (Simon Feltman) (#709223) - - Fix memory leak for caller allocated GValue out arguments - (Simon Feltman) (#709397) + - Expose all GI enum and flags types (Simon Feltman) (#709008) + - Add support for default arguments annotated with allow-none + (Simon Feltman) (#640812) + - Refactor argument cache handling (Simon Feltman) (#640812) + - Remove support for allowing PyObjects as void pointers + (Simon Feltman) (#688081) 3.10.0 23-Sep-2013 - Fix test_gi.TestProjectVersion.test_version_str() (Martin Pitt) diff --git a/PKG-INFO b/PKG-INFO index 86a104e..5751559 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: PyGObject -Version: 3.10.2 +Version: 3.11.1 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: Johan Dahlin Maintainer-email: johan@gnome.org License: GNU LGPL -Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.10/pygobject-3.10.2.tar.gz +Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.11/pygobject-3.11.1.tar.gz Description: Python bindings for GLib and GObject Platform: POSIX, Windows Classifier: Development Status :: 5 - Production/Stable diff --git a/README b/README index 7530c61..d38e974 100644 --- a/README +++ b/README @@ -46,7 +46,8 @@ Requirements ============ * C compiler (GCC and MSVC supported) * Python 2.7 or higher - * Glib/Gio 2.35.9 or higher + * Glib/Gio 2.38.0 or higher + * gobject-introspection 1.38.0 or higher * libffi (optional) Copyright Information diff --git a/aclocal.m4 b/aclocal.m4 index aa08057..43d9348 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.14 -*- Autoconf -*- +# generated automatically by aclocal 1.13.3 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. @@ -753,10 +753,10 @@ fi[]dnl # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.14' +[am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.14], [], +m4_if([$1], [1.13.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -772,7 +772,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.14])dnl +[AM_AUTOMAKE_VERSION([1.13.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -1139,12 +1139,6 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. -dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. -m4_define([AC_PROG_CC], -m4_defn([AC_PROG_CC]) -[_AM_PROG_CC_C_O -]) - # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- @@ -1253,48 +1247,7 @@ dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) - fi -fi]) +]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further @@ -1302,6 +1255,7 @@ dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. @@ -1413,6 +1367,38 @@ AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. @@ -1489,53 +1475,6 @@ AC_DEFUN([_AM_IF_OPTION], # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# _AM_PROG_CC_C_O -# --------------- -# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC -# to automatically call this. -AC_DEFUN([_AM_PROG_CC_C_O], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) - -# For backward compatibility. -AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) - -# Copyright (C) 1999-2013 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- diff --git a/config.h.in b/config.h.in index f93b29e..fa098f6 100644 --- a/config.h.in +++ b/config.h.in @@ -37,6 +37,9 @@ */ #undef LT_OBJDIR +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + /* Name of package */ #undef PACKAGE diff --git a/configure b/configure index 7e8e0fd..791a090 100755 --- 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.10.2. +# Generated by GNU Autoconf 2.69 for pygobject 3.11.1. # # Report bugs to . # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pygobject' PACKAGE_TARNAME='pygobject' -PACKAGE_VERSION='3.10.2' -PACKAGE_STRING='pygobject 3.10.2' +PACKAGE_VERSION='3.11.1' +PACKAGE_STRING='pygobject 3.11.1' PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject' PACKAGE_URL='https://live.gnome.org/PyGObject/' @@ -1395,7 +1395,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.10.2 to adapt to many kinds of systems. +\`configure' configures pygobject 3.11.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1465,7 +1465,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pygobject 3.10.2:";; + short | recursive ) echo "Configuration of pygobject 3.11.1:";; esac cat <<\_ACEOF @@ -1602,7 +1602,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pygobject configure 3.10.2 +pygobject configure 3.11.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1880,7 +1880,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.10.2, which was +It was created by pygobject $as_me 3.11.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2239,14 +2239,14 @@ $as_echo "#define PYGOBJECT_MAJOR_VERSION 3" >>confdefs.h PYGOBJECT_MAJOR_VERSION=3 -$as_echo "#define PYGOBJECT_MINOR_VERSION 10" >>confdefs.h +$as_echo "#define PYGOBJECT_MINOR_VERSION 11" >>confdefs.h -PYGOBJECT_MINOR_VERSION=10 +PYGOBJECT_MINOR_VERSION=11 -$as_echo "#define PYGOBJECT_MICRO_VERSION 2" >>confdefs.h +$as_echo "#define PYGOBJECT_MICRO_VERSION 1" >>confdefs.h -PYGOBJECT_MICRO_VERSION=2 +PYGOBJECT_MICRO_VERSION=1 ac_config_headers="$ac_config_headers config.h" @@ -2290,7 +2290,7 @@ else fi AM_BACKSLASH='\' -am__api_version='1.14' +am__api_version='1.13' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do @@ -2766,7 +2766,7 @@ fi # Define the identity of the package. PACKAGE='pygobject' - VERSION='3.10.2' + VERSION='3.11.1' cat >>confdefs.h <<_ACEOF @@ -2817,47 +2817,6 @@ am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 - fi -fi ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" @@ -3921,65 +3880,6 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 @@ -12420,65 +12320,6 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 @@ -12607,6 +12448,131 @@ else fi +if test "x$CC" != xcc; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + # option to specify python interpreter to use; this just sets $PYTHON, so that @@ -13439,7 +13405,7 @@ fi PKG_CONFIG=no fi - min_glib_version=2.35.9 + min_glib_version=2.38.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB - version >= $min_glib_version" >&5 $as_echo_n "checking for GLIB - version >= $min_glib_version... " >&6; } @@ -13784,12 +13750,12 @@ if test -n "$GIO_CFLAGS"; then pkg_cv_GIO_CFLAGS="$GIO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gio-2.0 >= 2.35.9\""; } >&5 - ($PKG_CONFIG --exists --print-errors "gio-2.0 >= 2.35.9") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gio-2.0 >= 2.38.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gio-2.0 >= 2.38.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_GIO_CFLAGS=`$PKG_CONFIG --cflags "gio-2.0 >= 2.35.9" 2>/dev/null` + pkg_cv_GIO_CFLAGS=`$PKG_CONFIG --cflags "gio-2.0 >= 2.38.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -13801,12 +13767,12 @@ if test -n "$GIO_LIBS"; then pkg_cv_GIO_LIBS="$GIO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gio-2.0 >= 2.35.9\""; } >&5 - ($PKG_CONFIG --exists --print-errors "gio-2.0 >= 2.35.9") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gio-2.0 >= 2.38.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gio-2.0 >= 2.38.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_GIO_LIBS=`$PKG_CONFIG --libs "gio-2.0 >= 2.35.9" 2>/dev/null` + pkg_cv_GIO_LIBS=`$PKG_CONFIG --libs "gio-2.0 >= 2.38.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -13827,14 +13793,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - GIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gio-2.0 >= 2.35.9" 2>&1` + GIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gio-2.0 >= 2.38.0" 2>&1` else - GIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gio-2.0 >= 2.35.9" 2>&1` + GIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gio-2.0 >= 2.38.0" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GIO_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (gio-2.0 >= 2.35.9) were not met: + as_fn_error $? "Package requirements (gio-2.0 >= 2.38.0) were not met: $GIO_PKG_ERRORS @@ -13884,17 +13850,17 @@ if test -n "$GI_CFLAGS"; then pkg_cv_GI_CFLAGS="$GI_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 \""; } >&5 - ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 ") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_GI_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + pkg_cv_GI_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 " 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else @@ -13907,17 +13873,17 @@ if test -n "$GI_LIBS"; then pkg_cv_GI_LIBS="$GI_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 \""; } >&5 - ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 ") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_GI_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + pkg_cv_GI_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 " 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else @@ -13939,19 +13905,19 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - GI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + GI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 " 2>&1` else - GI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + GI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 " 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GI_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (glib-2.0 >= 2.35.9 - gobject-introspection-1.0 >= 1.35.9 + as_fn_error $? "Package requirements (glib-2.0 >= 2.38.0 + gobject-introspection-1.0 >= 1.38.0 ) were not met: $GI_PKG_ERRORS @@ -15368,7 +15334,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.10.2, which was +This file was extended by pygobject $as_me 3.11.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15435,7 +15401,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.10.2 +pygobject config.status 3.11.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 002681a..05f54ba 100644 --- a/configure.ac +++ b/configure.ac @@ -17,16 +17,16 @@ m4_define(python3_min_ver, 3.1) dnl the pygobject version number m4_define(pygobject_major_version, 3) -m4_define(pygobject_minor_version, 10) -m4_define(pygobject_micro_version, 2) +m4_define(pygobject_minor_version, 11) +m4_define(pygobject_micro_version, 1) m4_define(pygobject_version, pygobject_major_version.pygobject_minor_version.pygobject_micro_version) dnl versions of packages we require ... -m4_define(introspection_required_version, 1.35.9) +m4_define(introspection_required_version, 1.38.0) m4_define(py2cairo_required_version, 1.2.0) m4_define(py3cairo_required_version, 1.10.0) -m4_define(glib_required_version, 2.35.9) -m4_define(gio_required_version, 2.35.9) +m4_define(glib_required_version, 2.38.0) +m4_define(gio_required_version, 2.38.0) AC_INIT([pygobject],[pygobject_version], [http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject], diff --git a/examples/Makefile.in b/examples/Makefile.in index 69875b8..0c05343 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. diff --git a/gi/Makefile.in b/gi/Makefile.in index 20c203c..abc8c4e 100644 --- a/gi/Makefile.in +++ b/gi/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -642,14 +642,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/gi/_glib/Makefile.in b/gi/_glib/Makefile.in index 6d56bb5..b08e8f1 100644 --- a/gi/_glib/Makefile.in +++ b/gi/_glib/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -578,14 +578,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/gi/_glib/pyglib-python-compat.h b/gi/_glib/pyglib-python-compat.h index 7b4c595..844bc55 100644 --- a/gi/_glib/pyglib-python-compat.h +++ b/gi/_glib/pyglib-python-compat.h @@ -198,6 +198,7 @@ PyTypeObject symbol = { \ #define PYGLIB_PyLong_Check PyLong_Check #define PYGLIB_PyLong_FromLong PyLong_FromLong +#define PYGLIB_PyLong_FromSize_t PyLong_FromSize_t #define PYGLIB_PyLong_AsLong PyLong_AsLong #define PYGLIB_PyLong_AS_LONG(o) PyLong_AS_LONG((PyObject*)(o)) #define PYGLIB_PyLongObject PyLongObject diff --git a/gi/_gobject/Makefile.in b/gi/_gobject/Makefile.in index 81b9f3f..b057108 100644 --- a/gi/_gobject/Makefile.in +++ b/gi/_gobject/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -535,14 +535,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c index 65d5de9..f78b7f5 100644 --- a/gi/_gobject/pygobject.c +++ b/gi/_gobject/pygobject.c @@ -38,7 +38,6 @@ static int pygobject_clear(PyGObject *self); static PyObject * pyg_type_get_bases(GType gtype); static inline int pygobject_clear(PyGObject *self); static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data); -static PyObject * pygbinding_weak_ref_new(GObject *obj); static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj); static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present); @@ -242,14 +241,13 @@ build_parameter_list(GObjectClass *class) g_free(name); } - g_type_class_unref(class); - if (props) g_free(props); return props_list; } + static PyObject* PyGProps_getattro(PyGProps *self, PyObject *attr) { @@ -266,12 +264,6 @@ PyGProps_getattro(PyGProps *self, PyObject *attr) } class = g_type_class_ref(self->gtype); - - if (!strcmp(attr_name, "__members__")) { - ret = build_parameter_list(class); - g_type_class_unref(class); - return ret; - } /* g_object_class_find_property recurses through the class hierarchy, * so the resulting pspec tells us the owner_type that owns the property @@ -441,6 +433,25 @@ pygobject_props_get_iter(PyGProps *self) return (PyObject *) iter; } +static PyObject* +pygobject_props_dir(PyGProps *self) +{ + PyObject *ret; + GObjectClass *class; + + class = g_type_class_ref (self->gtype); + ret = build_parameter_list (class); + g_type_class_unref (class); + + return ret; +} + +static PyMethodDef pygobject_props_methods[] = { + { "__dir__", (PyCFunction)pygobject_props_dir, METH_NOARGS}, + { NULL, NULL, 0} +}; + + static Py_ssize_t PyGProps_length(PyGProps *self) { @@ -1637,7 +1648,7 @@ pygobject_bind_property(PyGObject *self, PyObject *args) return NULL; } - return pygbinding_weak_ref_new(G_OBJECT (binding)); + return pygobject_new (G_OBJECT (binding)); } static PyObject * @@ -2341,54 +2352,6 @@ pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw) } } - -/* -------------- GBinding Weak Reference ----------------- */ - -/** - * BindingWeakRef - * - * The BindingWeakRef object is used to manage GBinding objects within python - * created through GObject.bind_property. It is a sub-class PyGObjectWeakRef so - * that we can maintain the same reference counting semantics between Python - * and GObject Binding objects. This gives explicit direct control of the - * binding lifetime by using the "unbind" method on the BindingWeakRef object - * along with implicit management based on the lifetime of the source or - * target objects. - */ - -PYGLIB_DEFINE_TYPE("gi._gobject.GBindingWeakRef", PyGBindingWeakRef_Type, PyGObjectWeakRef); - -static PyObject * -pygbinding_weak_ref_new(GObject *obj) -{ - PyGObjectWeakRef *self; - - self = PyObject_GC_New(PyGObjectWeakRef, &PyGBindingWeakRef_Type); - self->callback = NULL; - self->user_data = NULL; - self->obj = obj; - g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); - return (PyObject *) self; -} - -static PyObject * -pygbinding_weak_ref_unbind(PyGObjectWeakRef *self, PyObject *args) -{ - if (!self->obj) { - PyErr_SetString(PyExc_ValueError, "weak binding ref already unreffed"); - return NULL; - } - g_object_unref(self->obj); - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef pygbinding_weak_ref_methods[] = { - { "unbind", (PyCFunction)pygbinding_weak_ref_unbind, METH_NOARGS}, - { NULL, NULL, 0} -}; - - static gpointer pyobject_copy(gpointer boxed) { @@ -2462,6 +2425,7 @@ pygobject_object_register_types(PyObject *d) "Python attributes."; PyGProps_Type.tp_traverse = (traverseproc)pygobject_props_traverse; PyGProps_Type.tp_iter = (getiterfunc)pygobject_props_get_iter; + PyGProps_Type.tp_methods = pygobject_props_methods; if (PyType_Ready(&PyGProps_Type) < 0) return; @@ -2494,12 +2458,4 @@ pygobject_object_register_types(PyObject *d) if (PyType_Ready(&PyGObjectWeakRef_Type) < 0) return; PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type); - - PyGBindingWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; - PyGBindingWeakRef_Type.tp_doc = "A GBinding weak reference"; - PyGBindingWeakRef_Type.tp_methods = pygbinding_weak_ref_methods; - PyGBindingWeakRef_Type.tp_base = &PyGObjectWeakRef_Type; - if (PyType_Ready(&PyGBindingWeakRef_Type) < 0) - return; - PyDict_SetItemString(d, "GBindingWeakRef", (PyObject *) &PyGBindingWeakRef_Type); } diff --git a/gi/docstring.py b/gi/docstring.py index 713bb6e..2aa2629 100644 --- a/gi/docstring.py +++ b/gi/docstring.py @@ -23,9 +23,7 @@ from ._gi import \ VFuncInfo, \ FunctionInfo, \ - DIRECTION_IN, \ - DIRECTION_OUT, \ - DIRECTION_INOUT + Direction #: Module storage for currently registered doc string generator function. @@ -60,7 +58,7 @@ def generate_doc_string(info): def split_function_info_args(info): """Split a functions args into a tuple of two lists. - Note that args marked as DIRECTION_INOUT will be in both lists. + Note that args marked as Direction.INOUT will be in both lists. :Returns: Tuple of (in_args, out_args) @@ -69,9 +67,9 @@ def split_function_info_args(info): out_args = [] for arg in info.get_arguments(): direction = arg.get_direction() - if direction in (DIRECTION_IN, DIRECTION_INOUT): + if direction in (Direction.IN, Direction.INOUT): in_args.append(arg) - if direction in (DIRECTION_OUT, DIRECTION_INOUT): + if direction in (Direction.OUT, Direction.INOUT): out_args.append(arg) return (in_args, out_args) @@ -88,9 +86,23 @@ def _generate_callable_info_function_signature(info): elif info.is_constructor(): in_args_strs = ['cls'] - for arg in in_args: - argstr = arg.get_name() + ':' + arg.get_pytype_hint() - if arg.is_optional(): + # Build a lists of indices prior to adding the docs because + # because it is possible the index retrieved comes before in + # argument being used. + ignore_indices = set([arg.get_destroy() for arg in in_args]) + user_data_indices = set([arg.get_closure() for arg in in_args]) + + for i, arg in enumerate(in_args): + if i in ignore_indices: + continue + argstr = arg.get_name() + hint = arg.get_pytype_hint() + if hint not in ('void',): + argstr += ':' + hint + if arg.may_be_null() or i in user_data_indices: + # allow-none or user_data from a closure + argstr += '=None' + elif arg.is_optional(): argstr += '=' in_args_strs.append(argstr) in_args_str = ', '.join(in_args_strs) diff --git a/gi/gimodule.c b/gi/gimodule.c index 0d30b67..12addbc 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -29,6 +29,7 @@ #include PyObject *PyGIDeprecationWarning; +PyObject *_PyGIDefaultArgPlaceholder; static PyObject * _wrap_pyg_enum_add (PyObject *self, @@ -662,6 +663,11 @@ PYGLIB_MODULE_START(_gi, "_gi") PyExc_DeprecationWarning, NULL); #endif + /* Place holder object used to fill in "from Python" argument lists + * for values not supplied by the caller but support a GI default. + */ + _PyGIDefaultArgPlaceholder = PyObject_New(PyObject, &PyType_Type); + Py_INCREF(PyGIDeprecationWarning); PyModule_AddObject(module, "PyGIDeprecationWarning", PyGIDeprecationWarning); diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py index c80a727..fc38f69 100644 --- a/gi/overrides/GLib.py +++ b/gi/overrides/GLib.py @@ -48,7 +48,7 @@ spawn_async = _glib.spawn_async def threads_init(): - warnings.warn('Since version 3.10, calling threads_init is no longer needed. ' + warnings.warn('Since version 3.11, calling threads_init is no longer needed. ' 'See: https://wiki.gnome.org/PyGObject/Threading', PyGIDeprecationWarning, stacklevel=2) @@ -503,6 +503,10 @@ class MainLoop(GLib.MainLoop): def _handler(loop): loop.quit() loop._quit_by_sigint = True + # We handle signal deletion in __del__, return True so GLib + # doesn't do the deletion for us. + return True + if sys.platform != 'win32': # compatibility shim, keep around until we depend on glib 2.36 if hasattr(GLib, 'unix_signal_add'): @@ -616,60 +620,41 @@ class Timeout(Source): __all__.append('Timeout') -def user_data_varargs_shim(callback, user_data, cb_num_args=0): - '''Adjust callback and user_data varargs for PyGTK backwards compatibility - - GLib only accepts exactly one user_data argument, but older pygtk - traditionally accepted zero or more for some specific functions. For "one - argument", use the actual user-supplied callback for efficiency; for all - others, rewire it to accept zero or more than one. - - Return the adjusted callback and the real user data to pass to GLib. - ''' - if len(user_data) == 1: - return (callback, user_data[0]) - - if cb_num_args == 0: - return (lambda data: callback(*data), user_data) - if cb_num_args == 2: - return (lambda a1, a2, data: callback(a1, a2, *data), user_data) - raise NotImplementedError('%i number of callback arguments not supported' % cb_num_args) - - # backwards compatible API def idle_add(function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE) - return GLib.idle_add(priority, fn, data) + return GLib.idle_add(priority, function, *user_data) __all__.append('idle_add') def timeout_add(interval, function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) - return GLib.timeout_add(priority, interval, fn, data) + return GLib.timeout_add(priority, interval, function, *user_data) __all__.append('timeout_add') def timeout_add_seconds(interval, function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) - return GLib.timeout_add_seconds(priority, interval, fn, data) + return GLib.timeout_add_seconds(priority, interval, function, *user_data) __all__.append('timeout_add_seconds') -# The real GLib API is io_add_watch(IOChannel, priority, condition, callback, -# user_data). This needs to take into account several historical APIs: +# The GI GLib API uses g_io_add_watch_full renamed to g_io_add_watch with +# a signature of (channel, priority, condition, func, user_data). +# Prior to PyGObject 3.8, this function was statically bound with an API closer to the +# non-full version with a signature of: (fd, condition, func, *user_data) +# We need to support this until we are okay with breaking API in a way which is +# not backwards compatible. +# +# This needs to take into account several historical APIs: # - calling with an fd as first argument # - calling with a Python file object as first argument (we keep this one as # it's really convenient and does not change the number of arguments) # - calling without a priority as second argument -# and the usual "call without or multiple user_data", in which case the -# callback gets the same user data arguments. -def io_add_watch(channel, priority_, condition, *cb_and_user_data, **kwargs): +def _io_add_watch_get_args(channel, priority_, condition, *cb_and_user_data, **kwargs): if not isinstance(priority_, int) or isinstance(priority_, GLib.IOCondition): warnings.warn('Calling io_add_watch without priority as second argument is deprecated', PyGIDeprecationWarning) @@ -693,23 +678,28 @@ def io_add_watch(channel, priority_, condition, *cb_and_user_data, **kwargs): callback = cb_and_user_data[0] user_data = cb_and_user_data[1:] - (func, user_data) = user_data_varargs_shim(callback, user_data, 2) - # backwards compatibility: Allow calling with fd if isinstance(channel, int): - func_fdtransform = lambda _, cond, data: func(channel, cond, data) + func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data) real_channel = GLib.IOChannel.unix_new(channel) elif hasattr(channel, 'fileno'): # backwards compatibility: Allow calling with Python file - func_fdtransform = lambda _, cond, data: func(channel, cond, data) + func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data) real_channel = GLib.IOChannel.unix_new(channel.fileno()) else: assert isinstance(channel, GLib.IOChannel) - func_fdtransform = func + func_fdtransform = callback real_channel = channel - return GLib.io_add_watch(real_channel, priority_, condition, - func_fdtransform, user_data) + return real_channel, priority_, condition, func_fdtransform, user_data + +__all__.append('_io_add_watch_get_args') + + +def io_add_watch(*args, **kwargs): + """io_add_watch(channel, priority, condition, func, *user_data) -> event_source_id""" + channel, priority, condition, func, user_data = _io_add_watch_get_args(*args, **kwargs) + return GLib.io_add_watch(channel, priority, condition, func, *user_data) __all__.append('io_add_watch') @@ -807,14 +797,14 @@ PollFD = override(PollFD) __all__.append('PollFD') -# The real GLib API is child_watch_add(priority, pid, callback, data). -# The old static bindings had the following API which we still need to support -# for a while: -# child_watch_add(pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT) -# and the usual "call without user_data", in which case the callback does not -# get an user_data either. -def child_watch_add(priority_or_pid, pid_or_callback, *args, **kwargs): - _unspecified = object() +# The GI GLib API uses g_child_watch_add_full renamed to g_child_watch_add with +# a signature of (priority, pid, callback, data). +# Prior to PyGObject 3.8, this function was statically bound with an API closer to the +# non-full version with a signature of: (pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT) +# We need to support this until we are okay with breaking API in a way which is +# not backwards compatible. +def _child_watch_add_get_args(priority_or_pid, pid_or_callback, *args, **kwargs): + user_data = [] if callable(pid_or_callback): warnings.warn('Calling child_watch_add without priority as first argument is deprecated', @@ -822,35 +812,42 @@ def child_watch_add(priority_or_pid, pid_or_callback, *args, **kwargs): pid = priority_or_pid callback = pid_or_callback if len(args) == 0: - user_data = kwargs.get('data', _unspecified) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 1: - user_data = args[0] + user_data = args priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 2: - user_data = args[0] + user_data = [args[0]] priority = args[1] else: raise TypeError('expected at most 4 positional arguments') else: priority = priority_or_pid pid = pid_or_callback - if len(args) == 0 or not callable(args[0]): - raise TypeError('expected callback as third argument') - callback = args[0] - if len(args) == 1: - user_data = kwargs.get('data', _unspecified) + if 'function' in kwargs: + callback = kwargs['function'] + user_data = args + elif len(args) > 0 and callable(args[0]): + callback = args[0] + user_data = args[1:] else: - user_data = args[1] + raise TypeError('expected callback as third argument') + + if 'data' in kwargs: + if user_data: + raise TypeError('got multiple values for "data" argument') + user_data = [kwargs['data']] + + return priority, pid, callback, user_data + +# we need this to be accessible for unit testing +__all__.append('_child_watch_add_get_args') - if user_data is _unspecified: - # we have to call the callback without the user_data argument - func = lambda pid, status, data: callback(pid, status) - user_data = None - else: - func = callback - return GLib.child_watch_add(priority, pid, func, user_data) +def child_watch_add(*args, **kwargs): + """child_watch_add(priority, pid, function, *data)""" + priority, pid, function, data = _child_watch_add_get_args(*args, **kwargs) + return GLib.child_watch_add(priority, pid, function, *data) __all__.append('child_watch_add') diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py index b3aad47..83f1481 100644 --- a/gi/overrides/GObject.py +++ b/gi/overrides/GObject.py @@ -425,21 +425,6 @@ def signal_query(id_or_name, type_=None): __all__.append('signal_query') -# Check needed for glib versions which annotate signal related methods -# with a void pointer instead of GObject.Object. -# See: https://bugzilla.gnome.org/show_bug.cgi?id=685387 -_is_first_signal_arg_void = GObjectModule.signal_stop_emission.get_arguments()[0].get_pytype_hint() == 'void' - - -def _get_instance_for_signal(obj): - if not _is_first_signal_arg_void: - return obj - elif isinstance(obj, GObjectModule.Object): - return obj.__gpointer__ - else: - raise TypeError('Unsupported object "%s" for signal function' % obj) - - class _HandlerBlockManager(object): def __init__(self, obj, handler_id): self.obj = obj @@ -449,7 +434,7 @@ class _HandlerBlockManager(object): pass def __exit__(self, exc_type, exc_value, traceback): - signal_handler_unblock(self.obj, self.handler_id) + GObjectModule.signal_handler_unblock(self.obj, self.handler_id) def signal_handler_block(obj, handler_id): @@ -461,55 +446,12 @@ def signal_handler_block(obj, handler_id): with GObject.signal_handler_block(obj, id): pass """ - GObjectModule.signal_handler_block(_get_instance_for_signal(obj), handler_id) + GObjectModule.signal_handler_block(obj, handler_id) return _HandlerBlockManager(obj, handler_id) __all__.append('signal_handler_block') -if _is_first_signal_arg_void: - # The following functions wrap GI functions but coerce the first arg into - # something compatible with gpointer - - def _wrap_signal_func(func): - @functools.wraps(func) - def wrapper(obj, *args, **kwargs): - return func(_get_instance_for_signal(obj), *args, **kwargs) - return wrapper - - signal_handler_unblock = _wrap_signal_func(GObjectModule.signal_handler_unblock) - signal_handler_disconnect = _wrap_signal_func(GObjectModule.signal_handler_disconnect) - signal_handler_is_connected = _wrap_signal_func(GObjectModule.signal_handler_is_connected) - signal_stop_emission = _wrap_signal_func(GObjectModule.signal_stop_emission) - signal_stop_emission_by_name = _wrap_signal_func(GObjectModule.signal_stop_emission_by_name) - signal_has_handler_pending = _wrap_signal_func(GObjectModule.signal_has_handler_pending) - signal_get_invocation_hint = _wrap_signal_func(GObjectModule.signal_get_invocation_hint) - signal_connect_closure = _wrap_signal_func(GObjectModule.signal_connect_closure) - signal_connect_closure_by_id = _wrap_signal_func(GObjectModule.signal_connect_closure_by_id) - signal_handler_find = _wrap_signal_func(GObjectModule.signal_handler_find) - signal_handlers_destroy = _wrap_signal_func(GObjectModule.signal_handlers_destroy) - signal_handlers_block_matched = _wrap_signal_func(GObjectModule.signal_handlers_block_matched) - signal_handlers_unblock_matched = _wrap_signal_func(GObjectModule.signal_handlers_unblock_matched) - signal_handlers_disconnect_matched = _wrap_signal_func(GObjectModule.signal_handlers_disconnect_matched) - - __all__ += ['signal_handler_unblock', - 'signal_handler_disconnect', 'signal_handler_is_connected', - 'signal_stop_emission', 'signal_stop_emission_by_name', - 'signal_has_handler_pending', 'signal_get_invocation_hint', - 'signal_connect_closure', 'signal_connect_closure_by_id', - 'signal_handler_find', 'signal_handlers_destroy', - 'signal_handlers_block_matched', 'signal_handlers_unblock_matched', - 'signal_handlers_disconnect_matched'] -else: - # First signal arg is GObject.Object but we need these as globals for - # our GObject.Object class override below - signal_handler_disconnect = GObjectModule.signal_handler_disconnect - signal_handler_unblock = GObjectModule.signal_handler_unblock - signal_handler_disconnect = GObjectModule.signal_handler_disconnect - signal_handler_is_connected = GObjectModule.signal_handler_is_connected - signal_stop_emission_by_name = GObjectModule.signal_stop_emission_by_name - - def signal_parse_name(detailed_signal, itype, force_detail_quark): """Parse a detailed signal name into (signal_id, detail). @@ -661,12 +603,12 @@ class Object(GObjectModule.Object): # Aliases # - disconnect = _signalmethod(signal_handler_disconnect) - handler_block = _signalmethod(signal_handler_block) - handler_unblock = _signalmethod(signal_handler_unblock) - handler_disconnect = _signalmethod(signal_handler_disconnect) - handler_is_connected = _signalmethod(signal_handler_is_connected) - stop_emission_by_name = _signalmethod(signal_stop_emission_by_name) + handler_block = signal_handler_block + handler_unblock = _signalmethod(GObjectModule.signal_handler_unblock) + disconnect = _signalmethod(GObjectModule.signal_handler_disconnect) + handler_disconnect = _signalmethod(GObjectModule.signal_handler_disconnect) + handler_is_connected = _signalmethod(GObjectModule.signal_handler_is_connected) + stop_emission_by_name = _signalmethod(GObjectModule.signal_stop_emission_by_name) # # Deprecated Methods @@ -675,7 +617,7 @@ class Object(GObjectModule.Object): def stop_emission(self, detailed_signal): """Deprecated, please use stop_emission_by_name.""" warnings.warn(self.stop_emission.__doc__, PyGIDeprecationWarning, stacklevel=2) - return signal_stop_emission_by_name(self, detailed_signal) + return self.stop_emission_by_name(detailed_signal) emit_stop_by_name = stop_emission @@ -685,6 +627,25 @@ GObject = Object __all__ += ['Object', 'GObject'] +class Binding(GObjectModule.Binding): + def __call__(self): + warnings.warn('Using parentheses (binding()) to retrieve the Binding object is no ' + 'longer needed because the binding is returned directly from "bind_property.', + PyGIDeprecationWarning, stacklevel=2) + return self + + def unbind(self): + if hasattr(self, '_unbound'): + raise ValueError('binding has already been cleared out') + else: + setattr(self, '_unbound', True) + super(Binding, self).unbind() + + +Binding = override(Binding) +__all__.append('Binding') + + Property = propertyhelper.Property Signal = signalhelper.Signal SignalOverride = signalhelper.SignalOverride diff --git a/gi/overrides/Makefile.in b/gi/overrides/Makefile.in index e8a5bf3..7b2d5ab 100644 --- a/gi/overrides/Makefile.in +++ b/gi/overrides/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index 7d8a837..6378892 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -894,11 +894,13 @@ _pygi_argument_from_object (PyObject *object, { GIArgument arg; GITypeTag type_tag; + gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); - if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer) || + /* Ignores cleanup data for now. */ + if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data) || PyErr_Occurred()) { return arg; } @@ -1031,12 +1033,12 @@ array_success: &arg, NULL, /*arg_name*/ info, /*interface_info*/ - type_info, g_type, py_type, transfer, FALSE, /*copy_reference*/ - g_struct_info_is_foreign (info)); + g_struct_info_is_foreign (info), + g_type_info_is_pointer (type_info)); Py_DECREF (py_type); break; diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index 2f807f8..14d69b1 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -42,6 +42,7 @@ PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, PyGIDirection direction, gssize c_arg_index, gssize py_arg_index); + /* cleanup */ static void _pygi_arg_cache_free (PyGIArgCache *cache) @@ -103,23 +104,17 @@ _callback_cache_free_func (PyGICallbackCache *cache) void _pygi_callable_cache_free (PyGICallableCache *cache) { - gssize i; - if (cache == NULL) return; g_slist_free (cache->to_py_args); g_slist_free (cache->arg_name_list); g_hash_table_destroy (cache->arg_name_hash); + g_ptr_array_unref (cache->args_cache); - for (i = 0; i < cache->n_args; i++) { - PyGIArgCache *tmp = cache->args_cache[i]; - _pygi_arg_cache_free (tmp); - } if (cache->return_cache != NULL) _pygi_arg_cache_free (cache->return_cache); - g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache); g_slice_free (PyGICallableCache, cache); } @@ -299,45 +294,90 @@ _arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache, arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8; } -static gboolean -_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache, +static PyGIArgCache* +_arg_cache_array_len_arg_setup (PyGIArgCache *arg_cache, PyGICallableCache *callable_cache, - GITypeInfo *type_info, - GITransfer transfer, PyGIDirection direction, - gssize arg_index) + gssize arg_index, + gssize *py_arg_index) { PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - seq_cache->array_type = g_type_info_get_array_type (type_info); - - arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; + PyGIArgCache *child_cache = NULL; + child_cache = _pygi_callable_cache_get_arg (callable_cache, + seq_cache->len_arg_index); if (child_cache == NULL) { child_cache = _arg_cache_alloc (); - } else if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - return TRUE; + } else { + /* If the "length" arg cache already exists (the length comes before + * the array in the argument list), remove it from the to_py_args list + * because it does not belong in "to python" return tuple. The length + * will implicitly be a part of the returned Python list. + */ + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->to_py_args = + g_slist_remove (callable_cache->to_py_args, child_cache); + } + + /* This is a case where the arg cache already exists and has been + * setup by another array argument sharing the same length argument. + * See: gi_marshalling_tests_multi_array_key_value_in + */ + if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD) + return child_cache; } - if (seq_cache->len_arg_index < arg_index) - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE; - else - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; + /* There is a length argument for this array, so increment the number + * of "to python" child arguments when applicable. + */ + if (direction & PYGI_DIRECTION_TO_PYTHON) + callable_cache->n_to_py_child_args++; + child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; child_cache->direction = direction; child_cache->to_py_marshaller = NULL; child_cache->from_py_marshaller = NULL; - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; + /* ugly edge case code: + * + * When the length comes before the array parameter we need to update + * indexes of arguments after the index argument. + */ + if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) { + gssize i; + (*py_arg_index) -= 1; + callable_cache->n_py_args -= 1; + + for (i = seq_cache->len_arg_index + 1; + i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i); + if (update_cache == NULL) + break; + + update_cache->py_arg_index -= 1; + } + } + + _pygi_callable_cache_set_arg (callable_cache, seq_cache->len_arg_index, child_cache); + return child_cache; } - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; + return NULL; +} +static gboolean +_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache, + PyGICallableCache *callable_cache, + GITypeInfo *type_info, + GITransfer transfer, + PyGIDirection direction, + gssize arg_index) +{ + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + seq_cache->array_type = g_type_info_get_array_type (type_info); + arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; return TRUE; } @@ -350,35 +390,9 @@ _arg_cache_to_py_array_setup (PyGIArgCache *arg_cache, gssize arg_index) { PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + seq_cache->array_type = g_type_info_get_array_type (type_info); arg_cache->to_py_marshaller = _pygi_marshal_to_py_array; arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array; - - seq_cache->array_type = g_type_info_get_array_type (type_info); - - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = callable_cache->args_cache[seq_cache->len_arg_index]; - if (seq_cache->len_arg_index < arg_index) - callable_cache->n_to_py_child_args++; - - if (child_cache != NULL) { - callable_cache->to_py_args = - g_slist_remove (callable_cache->to_py_args, child_cache); - - if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) - return TRUE; - } else { - child_cache = _arg_cache_alloc (); - } - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - child_cache->direction = direction; - child_cache->to_py_marshaller = NULL; - child_cache->from_py_marshaller = NULL; - - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; - } - return TRUE; } @@ -509,14 +523,17 @@ _arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache, PyGIArgCache *user_data_arg_cache = _arg_cache_alloc (); user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG; user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache; + user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */ + _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index, + user_data_arg_cache); } if (callback_cache->destroy_notify_index >= 0) { PyGIArgCache *destroy_arg_cache = _arg_cache_alloc (); destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache; + _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index, + destroy_arg_cache); } arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback; arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback; @@ -589,31 +606,31 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, switch (info_type) { case GI_INFO_TYPE_UNION: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_union_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_interface_union_setup (arg_cache, transfer); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_struct_setup (arg_cache, iface_info, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_interface_struct_setup (arg_cache, iface_info, transfer); break; case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_object_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_interface_object_setup (arg_cache, transfer); break; @@ -621,7 +638,7 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, { PyGICallbackCache *callback_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + if (direction & PYGI_DIRECTION_TO_PYTHON) { _arg_cache_to_py_interface_callback_setup (); return NULL; } @@ -635,24 +652,24 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, if (arg_cache == NULL) return NULL; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache); break; } case GI_INFO_TYPE_ENUM: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_enum_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_interface_enum_setup (arg_cache, transfer); break; case GI_INFO_TYPE_FLAGS: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_interface_flags_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_interface_flags_setup (arg_cache, transfer); break; @@ -676,10 +693,30 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, return arg_cache; } +/* _arg_info_default_value + * info: + * arg: (out): GIArgument to fill in with default value. + * + * This is currently a place holder API which only supports "allow-none" pointer args. + * Once defaults are part of the GI API, we can replace this with: g_arg_info_default_value + * https://bugzilla.gnome.org/show_bug.cgi?id=558620 + * + * Returns: TRUE if the given argument supports a default value and was filled in. + */ +static gboolean +_arg_info_default_value (GIArgInfo *info, GIArgument *arg) +{ + if (g_arg_info_may_be_null (info)) { + arg->v_pointer = NULL; + return TRUE; + } + return FALSE; +} + PyGIArgCache * _arg_cache_new (GITypeInfo *type_info, PyGICallableCache *callable_cache, - GIArgInfo *arg_info, + GIArgInfo *arg_info, /* may be null */ GITransfer transfer, PyGIDirection direction, gssize c_arg_index, @@ -702,10 +739,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_void_setup (arg_cache); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_void_setup (arg_cache); break; @@ -726,10 +763,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_basic_type_setup (arg_cache); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_basic_type_setup (arg_cache); break; @@ -739,10 +776,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_utf8_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_utf8_setup (arg_cache, transfer); break; @@ -758,7 +795,7 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_array_setup (arg_cache, callable_cache, type_info, @@ -766,7 +803,7 @@ _arg_cache_new (GITypeInfo *type_info, direction, c_arg_index); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_array_setup (arg_cache, callable_cache, type_info, @@ -774,31 +811,11 @@ _arg_cache_new (GITypeInfo *type_info, direction, c_arg_index); - /* ugly edge case code: - * - * length can come before the array parameter which means we - * need to update indexes if this happens - */ - if (seq_cache->len_arg_index > -1 && - callable_cache->args_cache[seq_cache->len_arg_index]->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - gssize i; - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - py_arg_index -= 1; - callable_cache->n_py_args -= 1; - - for (i = seq_cache->len_arg_index + 1; - i < callable_cache->n_args; - i++) { - PyGIArgCache *update_cache = callable_cache->args_cache[i]; - if (update_cache == NULL) - break; - - update_cache->py_arg_index -= 1; - } - } + _arg_cache_array_len_arg_setup (arg_cache, + callable_cache, + direction, + c_arg_index, + &py_arg_index); break; } @@ -814,10 +831,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_glist_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_glist_setup (arg_cache, transfer); @@ -835,10 +852,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_gslist_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_gslist_setup (arg_cache, transfer); break; @@ -852,10 +869,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_ghash_setup (arg_cache); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + if (direction & PYGI_DIRECTION_TO_PYTHON) { _arg_cache_to_py_ghash_setup (arg_cache); } @@ -879,10 +896,10 @@ _arg_cache_new (GITypeInfo *type_info, if (arg_cache == NULL) break; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_FROM_PYTHON) _arg_cache_from_py_gerror_setup (arg_cache); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + if (direction & PYGI_DIRECTION_TO_PYTHON) _arg_cache_to_py_gerror_setup (arg_cache); break; @@ -897,43 +914,41 @@ _arg_cache_new (GITypeInfo *type_info, arg_cache->is_pointer = g_type_info_is_pointer (type_info); g_base_info_ref ( (GIBaseInfo *) type_info); arg_cache->type_info = type_info; + + if (arg_info != NULL) { + if (!arg_cache->has_default) { + /* It is possible has_default was set somewhere else */ + arg_cache->has_default = _arg_info_default_value (arg_info, + &arg_cache->default_value); + } + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); + arg_cache->allow_none = g_arg_info_may_be_null (arg_info); + + if (type_tag == GI_TYPE_TAG_INTERFACE || type_tag == GI_TYPE_TAG_ARRAY) + arg_cache->is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); + else + arg_cache->is_caller_allocates = FALSE; + } } return arg_cache; } -static void -_arg_name_list_generate (PyGICallableCache *callable_cache) +static PyGIDirection +_pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) { - GSList * arg_name_list = NULL; - int i; - - if (callable_cache->arg_name_hash == NULL) { - callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); + /* For vfuncs and callbacks our marshalling directions are reversed */ + if (gi_direction == GI_DIRECTION_INOUT) { + return PYGI_DIRECTION_BIDIRECTIONAL; + } else if (gi_direction == GI_DIRECTION_IN) { + if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) + return PYGI_DIRECTION_TO_PYTHON; + return PYGI_DIRECTION_FROM_PYTHON; } else { - g_hash_table_remove_all (callable_cache->arg_name_hash); - } - - for (i=0; i < callable_cache->n_args; i++) { - PyGIArgCache *arg_cache = NULL; - - arg_cache = callable_cache->args_cache[i]; - - if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && - arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && - (arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON || - arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL)) { - - gpointer arg_name = (gpointer)arg_cache->arg_name; - - arg_name_list = g_slist_prepend (arg_name_list, arg_name); - if (arg_name != NULL) { - g_hash_table_insert (callable_cache->arg_name_hash, arg_name, arg_name); - } - } + if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) + return PYGI_DIRECTION_FROM_PYTHON; + return PYGI_DIRECTION_TO_PYTHON; } - - callable_cache->arg_name_list = g_slist_reverse (arg_name_list); } /* Generate the cache for the callable's arguments */ @@ -948,11 +963,8 @@ _args_cache_generate (GICallableInfo *callable_info, PyGIArgCache *return_cache; PyGIDirection return_direction; - /* determine if we are marshalling the return to or from python */ - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - return_direction = PYGI_DIRECTION_FROM_PYTHON; - else - return_direction = PYGI_DIRECTION_TO_PYTHON; + /* Return arguments are always considered out */ + return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); /* cache the return arg */ return_info = @@ -979,10 +991,6 @@ _args_cache_generate (GICallableInfo *callable_info, callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { GIInterfaceInfo *interface_info; PyGIArgCache *instance_cache; - PyGIDirection instance_direction; - - instance_direction = PYGI_DIRECTION_FROM_PYTHON; - interface_info = g_base_info_get_container ( (GIBaseInfo *)callable_info); @@ -991,18 +999,20 @@ _args_cache_generate (GICallableInfo *callable_info, callable_cache, NULL, GI_TRANSFER_NOTHING, - instance_direction, + PYGI_DIRECTION_FROM_PYTHON, arg_index, 0); - /* FIXME: marshal interfaces from_py */ - instance_cache->from_py_marshaller = _pygi_marshal_from_py_interface_instance; g_base_info_unref ( (GIBaseInfo *)interface_info); if (instance_cache == NULL) return FALSE; - callable_cache->args_cache[arg_index] = instance_cache; + /* Because we are not supplied a GITypeInfo for instance arguments, + * assume some defaults. */ + instance_cache->is_pointer = TRUE; + + _pygi_callable_cache_set_arg (callable_cache, arg_index, instance_cache); arg_index++; callable_cache->n_from_py_args++; @@ -1010,130 +1020,153 @@ _args_cache_generate (GICallableInfo *callable_info, } - for (i=0; arg_index < callable_cache->n_args; arg_index++, i++) { + for (i=0; arg_index < _pygi_callable_cache_args_len (callable_cache); arg_index++, i++) { PyGIArgCache *arg_cache = NULL; GIArgInfo *arg_info; - GITypeInfo *type_info; - GIDirection gi_direction; PyGIDirection direction; - GITransfer transfer; - GITypeTag type_tag; - gboolean is_caller_allocates = FALSE; - gssize py_arg_index = -1; arg_info = g_callable_info_get_arg (callable_info, i); if (g_arg_info_get_closure (arg_info) == i) { arg_cache = _arg_cache_alloc (); - callable_cache->args_cache[arg_index] = arg_cache; + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; + direction = PYGI_DIRECTION_FROM_PYTHON; + arg_cache->direction = direction; arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; arg_cache->c_arg_index = i; callable_cache->n_from_py_args++; - g_base_info_unref ( (GIBaseInfo *)arg_info); + } else { + GITypeInfo *type_info; + + direction = _pygi_get_direction (callable_cache, + g_arg_info_get_direction (arg_info)); + type_info = g_arg_info_get_type (arg_info); + + /* must be an child arg filled in by its owner + * and continue + * fill in it's c_arg_index, add to the in count + */ + arg_cache = _pygi_callable_cache_get_arg (callable_cache, arg_index); + if (arg_cache != NULL) { + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) { + arg_cache->py_arg_index = callable_cache->n_py_args; + callable_cache->n_py_args++; + } - continue; - } + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_cache->c_arg_index = callable_cache->n_from_py_args; + callable_cache->n_from_py_args++; + } - /* For vfuncs and callbacks our marshalling directions - are reversed */ - gi_direction = g_arg_info_get_direction (arg_info); - if (gi_direction == GI_DIRECTION_INOUT) { - direction = PYGI_DIRECTION_BIDIRECTIONAL; - } else if (gi_direction == GI_DIRECTION_IN) { - direction = PYGI_DIRECTION_FROM_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_TO_PYTHON; - } else { - direction = PYGI_DIRECTION_TO_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_FROM_PYTHON; - } + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; + } - transfer = g_arg_info_get_ownership_transfer (arg_info); - type_info = g_arg_info_get_type (arg_info); - type_tag = g_type_info_get_tag (type_info); + arg_cache->type_tag = g_type_info_get_tag (type_info); - if (type_tag == GI_TYPE_TAG_INTERFACE || type_tag == GI_TYPE_TAG_ARRAY) - is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); + } else { + GITransfer transfer; + gssize py_arg_index = -1; + transfer = g_arg_info_get_ownership_transfer (arg_info); - /* must be an child arg filled in by its owner - * and continue - * fill in it's c_arg_index, add to the in count - */ - if (callable_cache->args_cache[arg_index] != NULL) { - arg_cache = callable_cache->args_cache[arg_index]; - if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) { - arg_cache->py_arg_index = callable_cache->n_py_args; - callable_cache->n_py_args++; - } + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + py_arg_index = callable_cache->n_py_args; + callable_cache->n_from_py_args++; + callable_cache->n_py_args++; + } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - arg_cache->c_arg_index = callable_cache->n_from_py_args; - callable_cache->n_from_py_args++; - } + arg_cache = + _arg_cache_new (type_info, + callable_cache, + arg_info, + transfer, + direction, + arg_index, + py_arg_index); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; - callable_cache->n_to_py_child_args++; - } + if (arg_cache == NULL) { + g_base_info_unref( (GIBaseInfo *)type_info); + g_base_info_unref( (GIBaseInfo *)arg_info); + return FALSE; + } - arg_cache->type_tag = g_type_info_get_tag (type_info); + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; + + callable_cache->to_py_args = + g_slist_append (callable_cache->to_py_args, arg_cache); + } + + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); + } g_base_info_unref (type_info); - g_base_info_unref ( (GIBaseInfo *)arg_info); - continue; } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - py_arg_index = callable_cache->n_py_args; - callable_cache->n_from_py_args++; - callable_cache->n_py_args++; - } + /* Ensure arguments always have a name when available */ + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache = - _arg_cache_new (type_info, - callable_cache, - arg_info, - transfer, - direction, - arg_index, - py_arg_index); + g_base_info_unref ( (GIBaseInfo *)arg_info); - if (arg_cache == NULL) - goto arg_err; + } - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->allow_none = g_arg_info_may_be_null(arg_info); - arg_cache->is_caller_allocates = is_caller_allocates; + if (callable_cache->arg_name_hash == NULL) { + callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); + } else { + g_hash_table_remove_all (callable_cache->arg_name_hash); + } + callable_cache->n_py_required_args = 0; + callable_cache->user_data_varargs_index = -1; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; + gssize last_explicit_arg_index = -1; - if (arg_cache == NULL) - goto arg_err; + /* Reverse loop through all the arguments to setup arg_name_list/hash + * and find the number of required arguments */ + for (i=((gssize)_pygi_callable_cache_args_len (callable_cache))-1; i >= 0; i--) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, i); - callable_cache->to_py_args = - g_slist_append (callable_cache->to_py_args, arg_cache); - } + if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && + arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { - callable_cache->args_cache[arg_index] = arg_cache; - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); + /* Setup arg_name_list and arg_name_hash */ + gpointer arg_name = (gpointer)arg_cache->arg_name; + callable_cache->arg_name_list = g_slist_prepend (callable_cache->arg_name_list, + arg_name); + if (arg_name != NULL) { + g_hash_table_insert (callable_cache->arg_name_hash, + arg_name, + GINT_TO_POINTER(i)); + } - continue; -arg_err: - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); - return FALSE; - } + /* The first tail argument without a default will force all the preceding + * argument defaults off. This limits support of default args to the + * tail of an args list. + */ + if (callable_cache->n_py_required_args > 0) { + arg_cache->has_default = FALSE; + callable_cache->n_py_required_args += 1; + } else if (!arg_cache->has_default) { + callable_cache->n_py_required_args += 1; + } + + if (last_explicit_arg_index == -1) { + last_explicit_arg_index = i; - _arg_name_list_generate (callable_cache); + /* If the last "from python" argument in the args list is a child + * with pyarg (currently only callback user_data). Set it to eat + * variable args in the callable cache. + */ + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) + callable_cache->user_data_varargs_index = i; + } + } + } return TRUE; } @@ -1141,6 +1174,7 @@ arg_err: PyGICallableCache * _pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) { + gint n_args; PyGICallableCache *cache; GIInfoType type = g_base_info_get_type ( (GIBaseInfo *)callable_info); @@ -1185,15 +1219,17 @@ _pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) cache->function_type = PYGI_FUNCTION_TYPE_METHOD; } - cache->n_args = g_callable_info_get_n_args (callable_info); + n_args = g_callable_info_get_n_args (callable_info); /* if we are a method or vfunc make sure the instance parameter is counted */ if (cache->function_type == PYGI_FUNCTION_TYPE_METHOD || cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) - cache->n_args++; + n_args++; - if (cache->n_args > 0) - cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *)); + if (n_args >= 0) { + cache->args_cache = g_ptr_array_new_full (n_args, (GDestroyNotify) _pygi_arg_cache_free); + g_ptr_array_set_size (cache->args_cache, n_args); + } if (!_args_cache_generate (callable_info, cache)) goto err; diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h index 6e5e0ab..745d0a1 100644 --- a/gi/pygi-cache.h +++ b/gi/pygi-cache.h @@ -36,7 +36,8 @@ typedef gboolean (*PyGIMarshalFromPyFunc) (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); typedef PyObject *(*PyGIMarshalToPyFunc) (PyGIInvokeState *state, PyGICallableCache *callable_cache, @@ -45,6 +46,7 @@ typedef PyObject *(*PyGIMarshalToPyFunc) (PyGIInvokeState *state, typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, /* always NULL for to_py cleanup */ gpointer data, gboolean was_processed); @@ -56,10 +58,6 @@ typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, * - PYGI_META_ARG_TYPE_CHILD - Children without python argument are * ignored by the marshallers and handled directly by their parents * marshaller. - * - PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE -Sometimes children arguments - * come before the parent. In these cases they need to be flagged - * so that the argument list counts must be updated for the cache to - * be valid * - Children with pyargs (PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) are processed * the same as other child args but also have an index into the * python parameters passed to the invoker @@ -67,7 +65,6 @@ typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, typedef enum { PYGI_META_ARG_TYPE_PARENT, PYGI_META_ARG_TYPE_CHILD, - PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE, PYGI_META_ARG_TYPE_CHILD_WITH_PYARG, PYGI_META_ARG_TYPE_CLOSURE, } PyGIMetaArgType; @@ -95,9 +92,9 @@ typedef enum { * marshalled into Python or from Python. */ typedef enum { - PYGI_DIRECTION_TO_PYTHON, - PYGI_DIRECTION_FROM_PYTHON, - PYGI_DIRECTION_BIDIRECTIONAL + PYGI_DIRECTION_TO_PYTHON = 1 << 0, + PYGI_DIRECTION_FROM_PYTHON = 1 << 1, + PYGI_DIRECTION_BIDIRECTIONAL = PYGI_DIRECTION_TO_PYTHON | PYGI_DIRECTION_FROM_PYTHON } PyGIDirection; @@ -110,6 +107,7 @@ struct _PyGIArgCache gboolean is_caller_allocates; gboolean is_skipped; gboolean allow_none; + gboolean has_default; PyGIDirection direction; GITransfer transfer; @@ -126,6 +124,9 @@ struct _PyGIArgCache gssize c_arg_index; gssize py_arg_index; + + /* Set when has_default is true. */ + GIArgument default_value; }; typedef struct _PyGISequenceCache @@ -172,18 +173,34 @@ struct _PyGICallableCache PyGIFunctionType function_type; PyGIArgCache *return_cache; - PyGIArgCache **args_cache; + GPtrArray *args_cache; GSList *to_py_args; GSList *arg_name_list; /* for keyword arg matching */ GHashTable *arg_name_hash; - /* counts */ + /* Index of user_data arg that can eat variable args passed to a callable. */ + gssize user_data_varargs_index; + + /* Number of in args passed to g_function_info_invoke. + * This is used for the length of PyGIInvokeState.in_args */ gssize n_from_py_args; + + /* Number of out args passed to g_function_info_invoke. + * This is used for the length of PyGIInvokeState.out_values */ gssize n_to_py_args; + + /* Number of out args for g_function_info_invoke that will be skipped + * when marshaling to Python due to them being implicitly available + * (list/array length). + */ gssize n_to_py_child_args; - gssize n_args; + /* Number of Python arguments expected for invoking the gi function. */ gssize n_py_args; + + /* Minimum number of args required to call the callable from Python. + * This count does not include args with defaults. */ + gssize n_py_required_args; }; void _pygi_arg_cache_clear (PyGIArgCache *cache); @@ -192,6 +209,18 @@ void _pygi_callable_cache_free (PyGICallableCache *cache); PyGICallableCache *_pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback); +#define _pygi_callable_cache_args_len(cache) ((cache)->args_cache)->len + +inline static PyGIArgCache * +_pygi_callable_cache_get_arg (PyGICallableCache *cache, guint index) { + return (PyGIArgCache *) g_ptr_array_index (cache->args_cache, index); +} + +inline static void +_pygi_callable_cache_set_arg (PyGICallableCache *cache, guint index, PyGIArgCache *arg_cache) { + cache->args_cache->pdata[index] = arg_cache; +} + G_END_DECLS #endif /* __PYGI_CACHE_H__ */ diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c index 2f5548a..5df4713 100644 --- a/gi/pygi-closure.c +++ b/gi/pygi-closure.c @@ -369,11 +369,33 @@ _pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args, g_type_info_is_pointer (&arg_type)) { if (user_data == NULL) { + /* user_data can be NULL for connect functions which don't accept + * user_data or as the default for user_data in the middle of function + * arguments. + */ Py_INCREF (Py_None); value = Py_None; } else { - value = user_data; - Py_INCREF (value); + /* Extend the callbacks args with user_data as variable args. */ + int j, user_data_len; + PyObject *py_user_data = user_data; + + if (!PyTuple_Check (py_user_data)) { + PyErr_SetString (PyExc_TypeError, "expected tuple for callback user_data"); + goto error; + } + + user_data_len = PyTuple_Size (py_user_data); + _PyTuple_Resize (py_args, n_args + user_data_len - 1); + for (j = 0; j < user_data_len; j++, n_in_args++) { + value = PyTuple_GetItem (py_user_data, j); + Py_INCREF (value); + PyTuple_SET_ITEM (*py_args, n_in_args, value); + } + /* We can assume user_data args are never going to be inout, + * so just continue here. + */ + continue; } } else if (direction == GI_DIRECTION_IN && arg_tag == GI_TYPE_TAG_INTERFACE) { @@ -631,10 +653,10 @@ _pygi_make_native_closure (GICallableInfo* info, closure = g_slice_new0 (PyGICClosure); closure->info = (GICallableInfo *) g_base_info_ref ( (GIBaseInfo *) info); closure->function = py_function; - closure->user_data = py_user_data ? py_user_data : Py_None; + closure->user_data = py_user_data; Py_INCREF (py_function); - Py_INCREF (closure->user_data); + Py_XINCREF (closure->user_data); fficlosure = g_callable_info_prepare_closure (info, &closure->cif, _pygi_closure_handle, diff --git a/gi/pygi-info.c b/gi/pygi-info.c index 7164ff9..0dd67b7 100644 --- a/gi/pygi-info.c +++ b/gi/pygi-info.c @@ -2,6 +2,7 @@ * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin + * Copyright (C) 2013 Simon Feltman * * pygi-info.c: GI.*Info wrappers. * @@ -53,9 +54,121 @@ _generate_doc_string(PyGIBaseInfo *self) return PyObject_CallFunctionObjArgs (_py_generate_doc_string, self, NULL); } +static PyObject * +_get_info_string (PyGIBaseInfo *self, + const gchar* (*get_info_string)(GIBaseInfo*)) +{ + const gchar *value = get_info_string ((GIBaseInfo*)self->info); + if (value == NULL) { + Py_RETURN_NONE; + } + return PYGLIB_PyUnicode_FromString (value); +} + +static PyObject * +_get_child_info (PyGIBaseInfo *self, + GIBaseInfo* (*get_child_info)(GIBaseInfo*)) +{ + GIBaseInfo *info; + PyObject *py_info; + + info = get_child_info ((GIBaseInfo*)self->info); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + + +static PyObject * +_get_child_info_by_name (PyGIBaseInfo *self, PyObject *py_name, + GIBaseInfo* (*get_child_info_by_name)(GIBaseInfo*, const gchar*)) +{ + GIBaseInfo *info; + PyObject *py_info; + char *name; + + if (!PYGLIB_PyUnicode_Check (py_name)) { + PyErr_SetString (PyExc_TypeError, "expected string name"); + return NULL; + } + + name = PYGLIB_PyUnicode_AsString (py_name); + info = get_child_info_by_name ((GIObjectInfo*)self->info, name); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + + +/* _make_infos_tuple + * + * Build a tuple from the common API pattern in GI of having a + * function which returns a count and an indexed GIBaseInfo + * in the range of 0 to count; + */ +static PyObject * +_make_infos_tuple (PyGIBaseInfo *self, + gint (*get_n_infos)(GIBaseInfo*), + GIBaseInfo* (*get_info)(GIBaseInfo*, gint)) +{ + gint n_infos; + PyObject *infos; + gint i; + + n_infos = get_n_infos ( (GIBaseInfo *) self->info); + + infos = PyTuple_New (n_infos); + if (infos == NULL) { + return NULL; + } + + for (i = 0; i < n_infos; i++) { + GIBaseInfo *info; + PyObject *py_info; + + info = (GIBaseInfo *) get_info (self->info, i); + g_assert (info != NULL); + + py_info = _pygi_info_new (info); + + g_base_info_unref (info); + + if (py_info == NULL) { + Py_CLEAR (infos); + break; + } + + PyTuple_SET_ITEM (infos, i, py_info); + } + + return infos; +} + /* BaseInfo */ +/* We need to be careful about calling g_base_info_get_name because + * calling it with a GI_INFO_TYPE_TYPE will crash. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=709456 + */ +static const char * +_safe_base_info_get_name (GIBaseInfo *info) +{ + if (g_base_info_get_type (info) == GI_INFO_TYPE_TYPE) { + return "type_type_instance"; + } else { + return g_base_info_get_name (info); + } +} + static void _base_info_dealloc (PyGIBaseInfo *self) { @@ -72,32 +185,48 @@ _base_info_dealloc (PyGIBaseInfo *self) static PyObject * _base_info_repr (PyGIBaseInfo *self) { + return PYGLIB_PyUnicode_FromFormat ("<%s object (%s) at 0x%p>", - Py_TYPE( (PyObject *) self)->tp_name, - g_base_info_get_name (self->info), + Py_TYPE( (PyObject *) self)->tp_name, + _safe_base_info_get_name (self->info), (void *) self); } static PyObject * -_base_info_richcompare (PyGIBaseInfo *self, PyObject *other, int op) +_wrap_g_base_info_equal (PyGIBaseInfo *self, PyObject *other) { - PyObject *res; GIBaseInfo *other_info; - if (!PyObject_TypeCheck(other, &PyGIBaseInfo_Type)) { - Py_INCREF(Py_NotImplemented); + if (!PyObject_TypeCheck (other, &PyGIBaseInfo_Type)) { + Py_INCREF (Py_NotImplemented); return Py_NotImplemented; } other_info = ((PyGIBaseInfo *)other)->info; + if (g_base_info_equal (self->info, other_info)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +static PyObject * +_base_info_richcompare (PyGIBaseInfo *self, PyObject *other, int op) +{ + PyObject *res; switch (op) { case Py_EQ: - res = g_base_info_equal (self->info, other_info) ? Py_True : Py_False; - break; + return _wrap_g_base_info_equal (self, other); case Py_NE: - res = g_base_info_equal (self->info, other_info) ? Py_False : Py_True; - break; + res = _wrap_g_base_info_equal (self, other); + if (res == Py_True) { + Py_DECREF (res); + Py_RETURN_FALSE; + } else { + Py_DECREF (res); + Py_RETURN_TRUE; + } default: res = Py_NotImplemented; break; @@ -144,12 +273,18 @@ _pygi_is_python_keyword (const gchar *name) return FALSE; } +static PyObject * +_wrap_g_base_info_get_type (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_base_info_get_type (self->info)); +} + static PyObject * _wrap_g_base_info_get_name (PyGIBaseInfo *self) { const gchar *name; - name = g_base_info_get_name (self->info); + name = _safe_base_info_get_name (self->info); /* escape keywords */ if (_pygi_is_python_keyword (name)) { @@ -165,18 +300,49 @@ _wrap_g_base_info_get_name (PyGIBaseInfo *self) static PyObject * _wrap_g_base_info_get_name_unescaped (PyGIBaseInfo *self) { - return PYGLIB_PyUnicode_FromString (g_base_info_get_name (self->info)); + return _get_info_string (self, _safe_base_info_get_name); } static PyObject * _wrap_g_base_info_get_namespace (PyGIBaseInfo *self) { - return PYGLIB_PyUnicode_FromString (g_base_info_get_namespace (self->info)); + return _get_info_string (self, g_base_info_get_namespace); +} + +static PyObject * +_wrap_g_base_info_is_deprecated (PyGIBaseInfo *self) +{ + if (g_base_info_is_deprecated (self->info)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject * +_wrap_g_base_info_get_attribute (PyGIBaseInfo *self, PyObject *arg) +{ + char *name; + const char *value; + + if (!PYGLIB_PyUnicode_Check (arg)) { + PyErr_SetString (PyExc_TypeError, "expected string name"); + return NULL; + } + + name = PYGLIB_PyUnicode_AsString (arg); + value = g_base_info_get_attribute (self->info, name); + if (value == NULL) { + Py_RETURN_NONE; + } + return PYGLIB_PyUnicode_FromString (value); } static PyObject * _wrap_g_base_info_get_container (PyGIBaseInfo *self) { + /* Note: don't use _get_child_info because g_base_info_get_container + * is marked as [transfer none] and therefore returns a borrowed ref. + */ GIBaseInfo *info; info = g_base_info_get_container (self->info); @@ -190,10 +356,14 @@ _wrap_g_base_info_get_container (PyGIBaseInfo *self) static PyMethodDef _PyGIBaseInfo_methods[] = { + { "get_type", (PyCFunction) _wrap_g_base_info_get_type, METH_NOARGS }, { "get_name", (PyCFunction) _wrap_g_base_info_get_name, METH_NOARGS }, { "get_name_unescaped", (PyCFunction) _wrap_g_base_info_get_name_unescaped, METH_NOARGS }, { "get_namespace", (PyCFunction) _wrap_g_base_info_get_namespace, METH_NOARGS }, + { "is_deprecated", (PyCFunction) _wrap_g_base_info_is_deprecated, METH_NOARGS }, + { "get_attribute", (PyCFunction) _wrap_g_base_info_get_attribute, METH_O }, { "get_container", (PyCFunction) _wrap_g_base_info_get_container, METH_NOARGS }, + { "equal", (PyCFunction) _wrap_g_base_info_equal, METH_O }, { NULL, NULL, 0 } }; @@ -359,43 +529,6 @@ out: /* CallableInfo */ PYGLIB_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGICallableInfo); -static PyObject * -_wrap_g_callable_info_get_arguments (PyGIBaseInfo *self) -{ - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_callable_info_get_n_args ( (GICallableInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_callable_info_get_arg ( (GICallableInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; -} - - /* _callable_info_call: * * Shared wrapper for invoke which can be bound (instance method or class constructor) @@ -478,11 +611,11 @@ _function_info_call (PyGICallableInfo *self, PyObject *args, PyObject *kwargs) str_name = PyBytes_AsString (py_str_name); #endif - if (strcmp (str_name, g_base_info_get_name (container_info))) { + if (strcmp (str_name, _safe_base_info_get_name (container_info))) { PyErr_Format (PyExc_TypeError, "%s constructor cannot be used to create instances of " "a subclass %s", - g_base_info_get_name (container_info), + _safe_base_info_get_name (container_info), str_name); Py_DECREF (py_str_name); return NULL; @@ -572,9 +705,61 @@ _callable_info_dealloc (PyGICallableInfo *self) PyGIBaseInfo_Type.tp_dealloc ((PyObject *) self); } +static PyObject * +_wrap_g_callable_info_get_arguments (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_callable_info_get_n_args, g_callable_info_get_arg); +} + +static PyObject * +_wrap_g_callable_info_get_return_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_callable_info_get_return_type); +} + +static PyObject * +_wrap_g_callable_info_get_caller_owns (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_callable_info_get_caller_owns (self->info) ); +} + +static PyObject * +_wrap_g_callable_info_may_return_null (PyGIBaseInfo *self) +{ + return PyBool_FromLong ( + g_callable_info_may_return_null (self->info) ); +} + +static PyObject * +_wrap_g_callable_info_get_return_attribute (PyGIBaseInfo *self, PyObject *py_name) +{ + gchar *name; + const gchar *attr; + + if (!PYGLIB_PyUnicode_Check (py_name)) { + PyErr_SetString (PyExc_TypeError, "expected string name"); + return NULL; + } + + name = PYGLIB_PyUnicode_AsString (py_name); + attr = g_callable_info_get_return_attribute (self->info, name); + if (attr) { + return PYGLIB_PyUnicode_FromString ( + g_callable_info_get_return_attribute (self->info, name)); + } else { + PyErr_Format(PyExc_AttributeError, "return attribute %s not found", name); + return NULL; + } +} + static PyMethodDef _PyGICallableInfo_methods[] = { { "invoke", (PyCFunction) _wrap_g_callable_info_invoke, METH_VARARGS | METH_KEYWORDS }, { "get_arguments", (PyCFunction) _wrap_g_callable_info_get_arguments, METH_NOARGS }, + { "get_return_type", (PyCFunction) _wrap_g_callable_info_get_return_type, METH_NOARGS }, + { "get_caller_owns", (PyCFunction) _wrap_g_callable_info_get_caller_owns, METH_NOARGS }, + { "may_return_null", (PyCFunction) _wrap_g_callable_info_may_return_null, METH_NOARGS }, + { "get_return_attribute", (PyCFunction) _wrap_g_callable_info_get_return_attribute, METH_O }, { NULL, NULL, 0 } }; @@ -600,16 +785,62 @@ static PyMethodDef _PyGIErrorDomainInfo_methods[] = { }; /* SignalInfo */ -PYGLIB_DEFINE_TYPE ("gi.SignalInfo", PyGISignalInfo_Type, PyGIBaseInfo); +PYGLIB_DEFINE_TYPE ("gi.SignalInfo", PyGISignalInfo_Type, PyGICallableInfo); + +static PyObject * +_wrap_g_signal_info_get_flags (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_signal_info_get_flags ((GISignalInfo *)self->info) ); +} + +static PyObject * +_wrap_g_signal_info_get_class_closure (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_signal_info_get_class_closure); +} + +static PyObject * +_wrap_g_signal_info_true_stops_emit (PyGIBaseInfo *self) +{ + return PyBool_FromLong ( + g_signal_info_true_stops_emit ((GISignalInfo *)self->info) ); +} static PyMethodDef _PyGISignalInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_signal_info_get_flags, METH_NOARGS }, + { "get_class_closure", (PyCFunction) _wrap_g_signal_info_get_class_closure, METH_NOARGS }, + { "true_stops_emit", (PyCFunction) _wrap_g_signal_info_true_stops_emit, METH_NOARGS }, { NULL, NULL, 0 } }; /* PropertyInfo */ PYGLIB_DEFINE_TYPE ("gi.PropertyInfo", PyGIPropertyInfo_Type, PyGIBaseInfo); +static PyObject * +_wrap_g_property_info_get_flags (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_property_info_get_flags ((GIPropertyInfo *)self->info) ); +} + +static PyObject * +_wrap_g_property_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_property_info_get_type); +} + +static PyObject * +_wrap_g_property_info_get_ownership_transfer (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_property_info_get_ownership_transfer ((GIPropertyInfo *)self->info) ); +} + static PyMethodDef _PyGIPropertyInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_property_info_get_flags, METH_NOARGS }, + { "get_type", (PyCFunction) _wrap_g_property_info_get_type, METH_NOARGS }, + { "get_ownership_transfer", (PyCFunction) _wrap_g_property_info_get_ownership_transfer, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -620,7 +851,7 @@ PYGLIB_DEFINE_TYPE ("gi.ArgInfo", PyGIArgInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_arg_info_get_direction (PyGIBaseInfo *self) { - return PyLong_FromLong ( + return PYGLIB_PyLong_FromLong ( g_arg_info_get_direction ((GIArgInfo*)self->info) ); } @@ -652,6 +883,40 @@ _wrap_g_arg_info_may_be_null (PyGIBaseInfo *self) g_arg_info_may_be_null ((GIArgInfo*)self->info) ); } +static PyObject * +_wrap_g_arg_info_get_ownership_transfer (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_arg_info_get_ownership_transfer ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_scope (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_arg_info_get_scope ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_closure (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_arg_info_get_closure ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_destroy (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong ( + g_arg_info_get_destroy ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_arg_info_get_type); +} + /* _g_arg_get_pytype_hint * * Returns new value reference to a string hinting at the python type @@ -682,7 +947,7 @@ _g_arg_get_pytype_hint (PyGIBaseInfo *self) GIBaseInfo *iface = g_type_info_get_interface(&type_info); gchar *name; - info_name = g_base_info_get_name (iface); + info_name = _safe_base_info_get_name (iface); if (info_name == NULL) { g_base_info_unref (iface); return PYGLIB_PyUnicode_FromString(g_type_tag_to_string(type_tag)); @@ -706,6 +971,11 @@ static PyMethodDef _PyGIArgInfo_methods[] = { { "is_return_value", (PyCFunction) _wrap_g_arg_info_is_return_value, METH_NOARGS }, { "is_optional", (PyCFunction) _wrap_g_arg_info_is_optional, METH_NOARGS }, { "may_be_null", (PyCFunction) _wrap_g_arg_info_may_be_null, METH_NOARGS }, + { "get_ownership_transfer", (PyCFunction) _wrap_g_arg_info_get_ownership_transfer, METH_NOARGS }, + { "get_scope", (PyCFunction) _wrap_g_arg_info_get_scope, METH_NOARGS }, + { "get_closure", (PyCFunction) _wrap_g_arg_info_get_closure, METH_NOARGS }, + { "get_destroy", (PyCFunction) _wrap_g_arg_info_get_destroy, METH_NOARGS }, + { "get_type", (PyCFunction) _wrap_g_arg_info_get_type, METH_NOARGS }, { "get_pytype_hint", (PyCFunction) _g_arg_get_pytype_hint, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -714,45 +984,126 @@ static PyMethodDef _PyGIArgInfo_methods[] = { /* TypeInfo */ PYGLIB_DEFINE_TYPE ("gi.TypeInfo", PyGITypeInfo_Type, PyGIBaseInfo); -static PyMethodDef _PyGITypeInfo_methods[] = { - { NULL, NULL, 0 } -}; - - -/* FunctionInfo */ -PYGLIB_DEFINE_TYPE ("gi.FunctionInfo", PyGIFunctionInfo_Type, PyGICallableInfo); - static PyObject * -_wrap_g_function_info_is_constructor (PyGIBaseInfo *self) +_wrap_g_type_info_is_pointer (PyGIBaseInfo *self) { - GIFunctionInfoFlags flags; - gboolean is_constructor; - - flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); - is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR; - - return PyBool_FromLong (is_constructor); + return PyBool_FromLong (g_type_info_is_pointer (self->info)); } static PyObject * -_wrap_g_function_info_is_method (PyGIBaseInfo *self) +_wrap_g_type_info_get_tag (PyGIBaseInfo *self) { - GIFunctionInfoFlags flags; - gboolean is_method; - - flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); - is_method = flags & GI_FUNCTION_IS_METHOD; + return PYGLIB_PyLong_FromLong (g_type_info_get_tag (self->info)); +} - return PyBool_FromLong (is_method); +static PyObject * +_wrap_g_type_info_get_tag_as_string (PyGIBaseInfo *self) +{ + GITypeTag tag = g_type_info_get_tag (self->info); + return PYGLIB_PyUnicode_FromString (g_type_tag_to_string(tag)); } -gsize -_pygi_g_type_tag_size (GITypeTag type_tag) +static PyObject * +_wrap_g_type_info_get_param_type (PyGIBaseInfo *self, PyObject *py_n) { - gsize size = 0; + GIBaseInfo *info; + PyObject *py_info; + gint n; - switch (type_tag) { - case GI_TYPE_TAG_BOOLEAN: + if (!PYGLIB_PyLong_Check (py_n)) { + PyErr_SetString(PyExc_TypeError, "expected integer value"); + return NULL; + } + + n = PYGLIB_PyLong_AsLong (py_n); + info = (GIBaseInfo *) g_type_info_get_param_type ( (GITypeInfo *) self->info, n); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + +static PyObject * +_wrap_g_type_info_get_interface (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_type_info_get_interface); +} + +static PyObject * +_wrap_g_type_info_get_array_length (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_type_info_get_array_length (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_array_fixed_size (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_type_info_get_array_fixed_size (self->info)); +} + +static PyObject * +_wrap_g_type_info_is_zero_terminated (PyGIBaseInfo *self) +{ + return PyBool_FromLong (g_type_info_is_zero_terminated (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_array_type (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_type_info_get_array_type (self->info)); +} + +static PyMethodDef _PyGITypeInfo_methods[] = { + { "is_pointer", (PyCFunction) _wrap_g_type_info_is_pointer, METH_NOARGS }, + { "get_tag", (PyCFunction) _wrap_g_type_info_get_tag, METH_NOARGS }, + { "get_tag_as_string", (PyCFunction) _wrap_g_type_info_get_tag_as_string, METH_NOARGS }, + { "get_param_type", (PyCFunction) _wrap_g_type_info_get_param_type, METH_O }, + { "get_interface", (PyCFunction) _wrap_g_type_info_get_interface, METH_NOARGS }, + { "get_array_length", (PyCFunction) _wrap_g_type_info_get_array_length, METH_NOARGS }, + { "get_array_fixed_size", (PyCFunction) _wrap_g_type_info_get_array_fixed_size, METH_NOARGS }, + { "is_zero_terminated", (PyCFunction) _wrap_g_type_info_is_zero_terminated, METH_NOARGS }, + { "get_array_type", (PyCFunction) _wrap_g_type_info_get_array_type, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* FunctionInfo */ +PYGLIB_DEFINE_TYPE ("gi.FunctionInfo", PyGIFunctionInfo_Type, PyGICallableInfo); + +static PyObject * +_wrap_g_function_info_is_constructor (PyGIBaseInfo *self) +{ + GIFunctionInfoFlags flags; + gboolean is_constructor; + + flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); + is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR; + + return PyBool_FromLong (is_constructor); +} + +static PyObject * +_wrap_g_function_info_is_method (PyGIBaseInfo *self) +{ + GIFunctionInfoFlags flags; + gboolean is_method; + + flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); + is_method = flags & GI_FUNCTION_IS_METHOD; + + return PyBool_FromLong (is_method); +} + +gsize +_pygi_g_type_tag_size (GITypeTag type_tag) +{ + gsize size = 0; + + switch (type_tag) { + case GI_TYPE_TAG_BOOLEAN: size = sizeof (gboolean); break; case GI_TYPE_TAG_INT8: @@ -900,15 +1251,55 @@ _pygi_g_type_info_size (GITypeInfo *type_info) return size; } +static PyObject * +_wrap_g_function_info_get_symbol (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_function_info_get_symbol); +} + +static PyObject * +_wrap_g_function_info_get_flags (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_function_info_get_flags (self->info)); +} + +static PyObject * +_wrap_g_function_info_get_property (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_function_info_get_property); +} + +static PyObject * +_wrap_g_function_info_get_vfunc (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_function_info_get_vfunc); +} + static PyMethodDef _PyGIFunctionInfo_methods[] = { { "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS }, { "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS }, + { "get_symbol", (PyCFunction) _wrap_g_function_info_get_symbol, METH_NOARGS }, + { "get_flags", (PyCFunction) _wrap_g_function_info_get_flags, METH_NOARGS }, + { "get_property", (PyCFunction) _wrap_g_function_info_get_property, METH_NOARGS }, + { "get_vfunc", (PyCFunction) _wrap_g_function_info_get_vfunc, METH_NOARGS }, { NULL, NULL, 0 } }; /* RegisteredTypeInfo */ PYGLIB_DEFINE_TYPE ("gi.RegisteredTypeInfo", PyGIRegisteredTypeInfo_Type, PyGIBaseInfo); +static PyObject * +_wrap_g_registered_type_info_get_type_name (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_registered_type_info_get_type_name); +} + +static PyObject * +_wrap_g_registered_type_info_get_type_init (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_registered_type_info_get_type_init); +} + static PyObject * _wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) { @@ -920,6 +1311,8 @@ _wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) } static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = { + { "get_type_name", (PyCFunction) _wrap_g_registered_type_info_get_type_name, METH_NOARGS }, + { "get_type_init", (PyCFunction) _wrap_g_registered_type_info_get_type_init, METH_NOARGS }, { "get_g_type", (PyCFunction) _wrap_g_registered_type_info_get_g_type, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -929,236 +1322,48 @@ static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = { PYGLIB_DEFINE_TYPE ("StructInfo", PyGIStructInfo_Type, PyGIBaseInfo); static PyObject * -_get_fields (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - n_infos = g_struct_info_get_n_fields ( (GIStructInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_fields ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - info = (GIBaseInfo *) g_struct_info_get_field ( (GIStructInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_field ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_struct_info_get_n_fields, g_struct_info_get_field); } static PyObject * -_get_methods (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - n_infos = g_struct_info_get_n_methods ( (GIStructInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_methods ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - info = (GIBaseInfo *) g_struct_info_get_method ( (GIStructInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_method ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_struct_info_get_n_methods, g_struct_info_get_method); } static PyObject * -_get_constants (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_size (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - n_infos = g_interface_info_get_n_constants ( (GIInterfaceInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_constants ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - info = (GIBaseInfo *) g_interface_info_get_constant ( (GIInterfaceInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_constant ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return PYGLIB_PyLong_FromSize_t (g_struct_info_get_size (self->info)); } static PyObject * -_get_vfuncs (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_alignment (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - n_infos = g_interface_info_get_n_vfuncs ( (GIInterfaceInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_vfuncs ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - info = (GIBaseInfo *) g_interface_info_get_vfunc ( (GIInterfaceInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_vfunc ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return PYGLIB_PyLong_FromSize_t (g_struct_info_get_alignment (self->info)); } static PyObject * -_wrap_g_struct_info_get_fields (PyGIBaseInfo *self) +_wrap_g_struct_info_is_gtype_struct (PyGIBaseInfo *self) { - return _get_fields (self, GI_INFO_TYPE_STRUCT); + return PyBool_FromLong (g_struct_info_is_gtype_struct (self->info)); } static PyObject * -_wrap_g_struct_info_get_methods (PyGIBaseInfo *self) +_wrap_g_struct_info_is_foreign (PyGIBaseInfo *self) { - return _get_methods (self, GI_INFO_TYPE_STRUCT); + return PyBool_FromLong (g_struct_info_is_foreign (self->info)); } static PyMethodDef _PyGIStructInfo_methods[] = { { "get_fields", (PyCFunction) _wrap_g_struct_info_get_fields, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_struct_info_get_methods, METH_NOARGS }, + { "get_size", (PyCFunction) _wrap_g_struct_info_get_size, METH_NOARGS }, + { "get_alignment", (PyCFunction) _wrap_g_struct_info_get_alignment, METH_NOARGS }, + { "is_gtype_struct", (PyCFunction) _wrap_g_struct_info_is_gtype_struct, METH_NOARGS }, + { "is_foreign", (PyCFunction) _wrap_g_struct_info_is_foreign, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1261,55 +1466,25 @@ pygi_g_struct_info_is_simple (GIStructInfo *struct_info) } g_base_info_unref (info); - break; - } - } - - g_base_info_unref ( (GIBaseInfo *) field_type_info); - g_base_info_unref ( (GIBaseInfo *) field_info); - } - - return is_simple; -} - - -/* EnumInfo */ -PYGLIB_DEFINE_TYPE ("gi.EnumInfo", PyGIEnumInfo_Type, PyGIBaseInfo); - -static PyObject * -_wrap_g_enum_info_get_values (PyGIBaseInfo *self) -{ - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_enum_info_get_n_values ( (GIEnumInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_enum_info_get_value ( (GIEnumInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; + break; + } } - PyTuple_SET_ITEM (infos, i, py_info); + g_base_info_unref ( (GIBaseInfo *) field_type_info); + g_base_info_unref ( (GIBaseInfo *) field_info); } - return infos; + return is_simple; +} + + +/* EnumInfo */ +PYGLIB_DEFINE_TYPE ("gi.EnumInfo", PyGIEnumInfo_Type, PyGIBaseInfo); + +static PyObject * +_wrap_g_enum_info_get_values (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_enum_info_get_n_values, g_enum_info_get_value); } static PyObject * @@ -1326,9 +1501,23 @@ _wrap_g_enum_info_is_flags (PyGIBaseInfo *self) } } +static PyObject * +_wrap_g_enum_info_get_methods (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_enum_info_get_n_methods, g_enum_info_get_method); +} + +static PyObject * +_wrap_g_enum_info_get_storage_type (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_enum_info_get_storage_type ((GIBaseInfo *) self->info)); +} + static PyMethodDef _PyGIEnumInfo_methods[] = { { "get_values", (PyCFunction) _wrap_g_enum_info_get_values, METH_NOARGS }, { "is_flags", (PyCFunction) _wrap_g_enum_info_is_flags, METH_NOARGS }, + { "get_methods", (PyCFunction) _wrap_g_enum_info_get_methods, METH_NOARGS }, + { "get_storage_type", (PyCFunction) _wrap_g_enum_info_get_storage_type, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1339,80 +1528,55 @@ PYGLIB_DEFINE_TYPE ("ObjectInfo", PyGIObjectInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_object_info_get_parent (PyGIBaseInfo *self) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_object_info_get_parent ( (GIObjectInfo*) self->info); - - if (info == NULL) { - Py_RETURN_NONE; - } - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - return py_info; + return _get_child_info (self, g_object_info_get_parent); } static PyObject * _wrap_g_object_info_get_methods (PyGIBaseInfo *self) { - return _get_methods (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_methods, g_object_info_get_method); } static PyObject * -_wrap_g_object_info_get_fields (PyGIBaseInfo *self) +_wrap_g_object_info_find_method (PyGIBaseInfo *self, PyObject *py_name) { - return _get_fields (self, GI_INFO_TYPE_OBJECT); + return _get_child_info_by_name (self, py_name, g_object_info_find_method); } static PyObject * -_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self) +_wrap_g_object_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_object_info_get_n_interfaces ( (GIObjectInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_object_info_get_interface ( (GIObjectInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); + return _make_infos_tuple (self, g_object_info_get_n_fields, g_object_info_get_field); +} - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } +static PyObject * +_wrap_g_object_info_get_properties (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_properties, g_object_info_get_property); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_object_info_get_signals (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_signals, g_object_info_get_signal); +} - return infos; +static PyObject * +_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_interfaces, g_object_info_get_interface); } static PyObject * _wrap_g_object_info_get_constants (PyGIBaseInfo *self) { - return _get_constants (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_constants, g_object_info_get_constant); } static PyObject * _wrap_g_object_info_get_vfuncs (PyGIBaseInfo *self) { - return _get_vfuncs (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_vfuncs, g_object_info_get_vfunc); } static PyObject * @@ -1422,29 +1586,80 @@ _wrap_g_object_info_get_abstract (PyGIBaseInfo *self) return PyBool_FromLong (is_abstract); } +static PyObject * +_wrap_g_object_info_get_type_name (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_type_name); +} + +static PyObject * +_wrap_g_object_info_get_type_init (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_type_init); +} + +static PyObject * +_wrap_g_object_info_get_fundamental (PyGIBaseInfo *self) +{ + return PyBool_FromLong (g_object_info_get_fundamental ( (GIObjectInfo*) self->info)); +} + static PyObject * _wrap_g_object_info_get_class_struct (PyGIBaseInfo *self) { - GIBaseInfo *info; + return _get_child_info (self, g_object_info_get_class_struct); +} - info = g_object_info_get_class_struct ((GIObjectInfo*)self->info); +static PyObject * +_wrap_g_object_info_find_vfunc (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_object_info_find_vfunc); +} - if (info == NULL) { - Py_RETURN_NONE; - } +static PyObject * +_wrap_g_object_info_get_unref_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_unref_function); +} - return _pygi_info_new (info); +static PyObject * +_wrap_g_object_info_get_ref_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_ref_function); +} + +static PyObject * +_wrap_g_object_info_get_set_value_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_set_value_function); +} + +static PyObject * +_wrap_g_object_info_get_get_value_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_get_value_function); } static PyMethodDef _PyGIObjectInfo_methods[] = { { "get_parent", (PyCFunction) _wrap_g_object_info_get_parent, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_object_info_get_methods, METH_NOARGS }, + { "find_method", (PyCFunction) _wrap_g_object_info_find_method, METH_O }, { "get_fields", (PyCFunction) _wrap_g_object_info_get_fields, METH_NOARGS }, + { "get_properties", (PyCFunction) _wrap_g_object_info_get_properties, METH_NOARGS }, + { "get_signals", (PyCFunction) _wrap_g_object_info_get_signals, METH_NOARGS }, { "get_interfaces", (PyCFunction) _wrap_g_object_info_get_interfaces, METH_NOARGS }, { "get_constants", (PyCFunction) _wrap_g_object_info_get_constants, METH_NOARGS }, { "get_vfuncs", (PyCFunction) _wrap_g_object_info_get_vfuncs, METH_NOARGS }, + { "find_vfunc", (PyCFunction) _wrap_g_object_info_find_vfunc, METH_O }, { "get_abstract", (PyCFunction) _wrap_g_object_info_get_abstract, METH_NOARGS }, + { "get_type_name", (PyCFunction) _wrap_g_object_info_get_type_name, METH_NOARGS }, + { "get_type_init", (PyCFunction) _wrap_g_object_info_get_type_init, METH_NOARGS }, + { "get_fundamental", (PyCFunction) _wrap_g_object_info_get_fundamental, METH_NOARGS }, { "get_class_struct", (PyCFunction) _wrap_g_object_info_get_class_struct, METH_NOARGS }, + { "get_unref_function", (PyCFunction) _wrap_g_object_info_get_unref_function, METH_NOARGS }, + { "get_ref_function", (PyCFunction) _wrap_g_object_info_get_ref_function, METH_NOARGS }, + { "get_set_value_function", (PyCFunction) _wrap_g_object_info_get_set_value_function, METH_NOARGS }, + { "get_get_value_function", (PyCFunction) _wrap_g_object_info_get_get_value_function, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1455,55 +1670,74 @@ PYGLIB_DEFINE_TYPE ("InterfaceInfo", PyGIInterfaceInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_interface_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_interface_info_get_n_methods ( (GIInterfaceInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } + return _make_infos_tuple (self, g_interface_info_get_n_methods, g_interface_info_get_method); +} - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; +static PyObject * +_wrap_g_interface_info_find_method (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_interface_info_find_method); +} - info = (GIBaseInfo *) g_interface_info_get_method ( (GIInterfaceInfo *) self->info, i); - g_assert (info != NULL); +static PyObject * +_wrap_g_interface_info_get_constants (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_constants, g_interface_info_get_constant); +} - py_info = _pygi_info_new (info); +static PyObject * +_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_vfuncs, g_interface_info_get_vfunc); +} - g_base_info_unref (info); +static PyObject * +_wrap_g_interface_info_find_vfunc (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_interface_info_find_vfunc); +} - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } +static PyObject * +_wrap_g_interface_info_get_prerequisites (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_prerequisites, g_interface_info_get_prerequisite); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_interface_info_get_properties (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_properties, g_interface_info_get_property); +} - return infos; +static PyObject * +_wrap_g_interface_info_get_iface_struct (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_interface_info_get_iface_struct); } static PyObject * -_wrap_g_interface_info_get_constants (PyGIBaseInfo *self) +_wrap_g_interface_info_get_signals (PyGIBaseInfo *self) { - return _get_constants (self, GI_INFO_TYPE_INTERFACE); + return _make_infos_tuple (self, g_interface_info_get_n_signals, g_interface_info_get_signal); } static PyObject * -_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self) +_wrap_g_interface_info_find_signal (PyGIBaseInfo *self, PyObject *py_name) { - return _get_vfuncs (self, GI_INFO_TYPE_INTERFACE); + return _get_child_info_by_name (self, py_name, g_interface_info_find_signal); } static PyMethodDef _PyGIInterfaceInfo_methods[] = { + { "get_prerequisites", (PyCFunction) _wrap_g_interface_info_get_prerequisites, METH_NOARGS }, + { "get_properties", (PyCFunction) _wrap_g_interface_info_get_properties, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_interface_info_get_methods, METH_NOARGS }, - { "get_constants", (PyCFunction) _wrap_g_interface_info_get_constants, METH_NOARGS }, + { "find_method", (PyCFunction) _wrap_g_interface_info_find_method, METH_O }, + { "get_signals", (PyCFunction) _wrap_g_interface_info_get_signals, METH_NOARGS }, + { "find_signal", (PyCFunction) _wrap_g_interface_info_find_signal, METH_O }, { "get_vfuncs", (PyCFunction) _wrap_g_interface_info_get_vfuncs, METH_NOARGS }, + { "get_constants", (PyCFunction) _wrap_g_interface_info_get_constants, METH_NOARGS }, + { "get_iface_struct", (PyCFunction) _wrap_g_interface_info_get_iface_struct, METH_NOARGS }, + { "find_vfunc", (PyCFunction) _wrap_g_interface_info_find_vfunc, METH_O }, { NULL, NULL, 0 } }; @@ -1828,9 +2062,37 @@ out: return retval; } +static PyObject * +_wrap_g_field_info_get_flags (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_field_info_get_flags (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_size (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_field_info_get_size (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_offset (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_field_info_get_offset (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_field_info_get_type); +} + static PyMethodDef _PyGIFieldInfo_methods[] = { { "get_value", (PyCFunction) _wrap_g_field_info_get_value, METH_VARARGS }, { "set_value", (PyCFunction) _wrap_g_field_info_set_value, METH_VARARGS }, + { "get_flags", (PyCFunction) _wrap_g_field_info_get_flags, METH_VARARGS }, + { "get_size", (PyCFunction) _wrap_g_field_info_get_size, METH_VARARGS }, + { "get_offset", (PyCFunction) _wrap_g_field_info_get_offset, METH_VARARGS }, + { "get_type", (PyCFunction) _wrap_g_field_info_get_type, METH_VARARGS }, { NULL, NULL, 0 } }; @@ -1846,21 +2108,33 @@ static PyMethodDef _PyGIUnresolvedInfo_methods[] = { PYGLIB_DEFINE_TYPE ("gi.VFuncInfo", PyGIVFuncInfo_Type, PyGICallableInfo); static PyObject * -_wrap_g_vfunc_info_get_invoker (PyGIBaseInfo *self) +_wrap_g_vfunc_info_get_flags (PyGIBaseInfo *self) { - PyObject *result = Py_None; - GIBaseInfo *info; + return PYGLIB_PyLong_FromLong (g_vfunc_info_get_flags ((GIVFuncInfo *) self->info)); +} - info = (GIBaseInfo *) g_vfunc_info_get_invoker ( (GIVFuncInfo *) self->info ); - if (info) - result = _pygi_info_new(info); - else - Py_INCREF(Py_None); +static PyObject * +_wrap_g_vfunc_info_get_offset (PyGIBaseInfo *self) +{ + return PYGLIB_PyLong_FromLong (g_vfunc_info_get_offset ((GIVFuncInfo *) self->info)); +} - return result; +static PyObject * +_wrap_g_vfunc_info_get_signal (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_vfunc_info_get_signal); +} + +static PyObject * +_wrap_g_vfunc_info_get_invoker (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_vfunc_info_get_invoker); } static PyMethodDef _PyGIVFuncInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_vfunc_info_get_flags, METH_NOARGS }, + { "get_offset", (PyCFunction) _wrap_g_vfunc_info_get_offset, METH_NOARGS }, + { "get_signal", (PyCFunction) _wrap_g_vfunc_info_get_signal, METH_NOARGS }, { "get_invoker", (PyCFunction) _wrap_g_vfunc_info_get_invoker, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1872,73 +2146,13 @@ PYGLIB_DEFINE_TYPE ("gi.UnionInfo", PyGIUnionInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_union_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_union_info_get_n_fields ( (GIUnionInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_union_info_get_field ( (GIUnionInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_union_info_get_n_fields, g_union_info_get_field); } static PyObject * _wrap_g_union_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_union_info_get_n_methods ( (GIUnionInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_union_info_get_method ( (GIUnionInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_union_info_get_n_methods, g_union_info_get_method); } static PyMethodDef _PyGIUnionInfo_methods[] = { @@ -1959,12 +2173,12 @@ _pygi_g_base_info_get_fullname (GIBaseInfo *info) if (container_info != NULL) { fullname = g_strdup_printf ("%s.%s.%s", g_base_info_get_namespace (container_info), - g_base_info_get_name (container_info), - g_base_info_get_name (info)); + _safe_base_info_get_name (container_info), + _safe_base_info_get_name (info)); } else { fullname = g_strdup_printf ("%s.%s", g_base_info_get_namespace (info), - g_base_info_get_name (info)); + _safe_base_info_get_name (info)); } if (fullname == NULL) { @@ -1974,6 +2188,7 @@ _pygi_g_base_info_get_fullname (GIBaseInfo *info) return fullname; } + void _pygi_info_register_types (PyObject *m) { @@ -2004,13 +2219,6 @@ _pygi_info_register_types (PyObject *m) if (PyModule_AddObject(m, "BaseInfo", (PyObject *)&PyGIBaseInfo_Type)) return; - if (PyModule_AddObject(m, "DIRECTION_IN", PyLong_FromLong(GI_DIRECTION_IN))) - return; - if (PyModule_AddObject(m, "DIRECTION_OUT", PyLong_FromLong(GI_DIRECTION_OUT))) - return; - if (PyModule_AddObject(m, "DIRECTION_INOUT", PyLong_FromLong(GI_DIRECTION_INOUT))) - return; - _PyGI_REGISTER_TYPE (m, PyGICallableInfo_Type, CallableInfo, PyGIBaseInfo_Type); PyGICallableInfo_Type.tp_call = (ternaryfunc) _callable_info_call; @@ -2025,6 +2233,9 @@ _pygi_info_register_types (PyObject *m) PyGICallableInfo_Type); PyGIVFuncInfo_Type.tp_descr_get = (descrgetfunc) _vfunc_info_descr_get; + _PyGI_REGISTER_TYPE (m, PyGISignalInfo_Type, SignalInfo, + PyGICallableInfo_Type); + _PyGI_REGISTER_TYPE (m, PyGIUnresolvedInfo_Type, UnresolvedInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGICallbackInfo_Type, CallbackInfo, @@ -2051,8 +2262,6 @@ _pygi_info_register_types (PyObject *m) PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIErrorDomainInfo_Type, ErrorDomainInfo, PyGIBaseInfo_Type); - _PyGI_REGISTER_TYPE (m, PyGISignalInfo_Type, SignalInfo, - PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIPropertyInfo_Type, PropertyInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIArgInfo_Type, ArgInfo, @@ -2060,6 +2269,147 @@ _pygi_info_register_types (PyObject *m) _PyGI_REGISTER_TYPE (m, PyGITypeInfo_Type, TypeInfo, PyGIBaseInfo_Type); - #undef _PyGI_REGISTER_TYPE + +#define _PyGI_ENUM_BEGIN(name) \ + { \ + const char *__enum_name = #name; \ + PyObject *__enum_value = NULL; \ + PyObject *__new_enum_cls = NULL; \ + PyObject *__enum_instance_dict = PyDict_New(); \ + PyObject *__module_name = PyObject_GetAttrString (m, "__name__"); \ + PyDict_SetItemString (__enum_instance_dict, "__module__", __module_name); \ + Py_DECREF (__module_name); + +#define _PyGI_ENUM_ADD_VALUE(prefix, name) \ + __enum_value = PYGLIB_PyLong_FromLong (prefix##_##name); \ + if (PyDict_SetItemString(__enum_instance_dict, #name, __enum_value)) { \ + Py_DECREF (__enum_instance_dict); \ + Py_DECREF (__enum_value); \ + return; \ + } \ + Py_DECREF (__enum_value); + +#define _PyGI_ENUM_END \ + __new_enum_cls = PyObject_CallFunction ((PyObject *)&PyType_Type, "s(O)O", \ + __enum_name, (PyObject *)&PyType_Type, \ + __enum_instance_dict); \ + Py_DECREF (__enum_instance_dict); \ + PyModule_AddObject (m, __enum_name, __new_enum_cls); /* steals ref */ \ + } + + + /* GIDirection */ + _PyGI_ENUM_BEGIN (Direction) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, IN) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, OUT) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, INOUT) + _PyGI_ENUM_END + + + /* GITransfer */ + _PyGI_ENUM_BEGIN (Transfer) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, NOTHING) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, CONTAINER) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, EVERYTHING) + _PyGI_ENUM_END + + /* GIArrayType */ + _PyGI_ENUM_BEGIN (ArrayType) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, C) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, PTR_ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, BYTE_ARRAY) + _PyGI_ENUM_END + + /* GIScopeType */ + _PyGI_ENUM_BEGIN (ScopeType) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, INVALID) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, CALL) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, ASYNC) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, NOTIFIED) + _PyGI_ENUM_END + + /* GIVFuncInfoFlags */ + _PyGI_ENUM_BEGIN (VFuncInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, CHAIN_UP) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, OVERRIDE) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, NOT_OVERRIDE) + _PyGI_ENUM_END + + /* GIFieldInfoFlags */ + _PyGI_ENUM_BEGIN (FieldInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_FIELD, IS_READABLE) + _PyGI_ENUM_ADD_VALUE (GI_FIELD, IS_WRITABLE) + _PyGI_ENUM_END + + /* GIFunctionInfoFlags */ + _PyGI_ENUM_BEGIN (FunctionInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_METHOD) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_CONSTRUCTOR) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_GETTER) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_SETTER) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, WRAPS_VFUNC) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, THROWS) + _PyGI_ENUM_END + + /* GITypeTag */ + _PyGI_ENUM_BEGIN (TypeTag) + /* Basic types */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, VOID) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, BOOLEAN) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT16) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT16) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT32) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT32) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT64) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT64) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, FLOAT) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, DOUBLE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GTYPE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UTF8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, FILENAME) + + /* Non-basic types; compare with G_TYPE_TAG_IS_BASIC */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INTERFACE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GLIST) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GSLIST) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GHASH) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, ERROR) + + /* Another basic type */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UNICHAR) + _PyGI_ENUM_END + + /* GIInfoType */ + _PyGI_ENUM_BEGIN (InfoType) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INVALID) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FUNCTION) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, CALLBACK) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, STRUCT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, BOXED) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, ENUM) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FLAGS) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, OBJECT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INTERFACE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, CONSTANT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INVALID_0) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, UNION) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, VALUE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, SIGNAL) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, VFUNC) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, PROPERTY) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FIELD) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, ARG) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, TYPE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, UNRESOLVED) + _PyGI_ENUM_END + +#undef _PyGI_ENUM_BEGIN +#undef _PyGI_ENUM_ADD_VALUE +#undef _PyGI_ENUM_END + } diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h index 1d9e49c..139b878 100644 --- a/gi/pygi-invoke-state-struct.h +++ b/gi/pygi-invoke-state-struct.h @@ -18,9 +18,10 @@ typedef struct _PyGIInvokeState GIArgument **args; GIArgument *in_args; - /* Generic array allocated to the same length as args - * for use as extra per-arg state data. */ - gpointer *args_data; + /* Array of pointers allocated to the same length as args which holds from_py + * marshaler cleanup data. + */ + gpointer *args_cleanup_data; /* Out args and out values * In order to pass a parameter and get something back out in C diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index 17cd278..675b0ef 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -120,7 +120,11 @@ _check_for_unexpected_kwargs (const gchar *function_name, } } - if (g_hash_table_lookup (arg_name_hash, PyBytes_AsString(key)) == NULL) { + /* Use extended lookup because it returns whether or not the key actually + * exists in the hash table. g_hash_table_lookup returns NULL for keys not + * found which maps to index 0 for our hash lookup. + */ + if (!g_hash_table_lookup_extended (arg_name_hash, PyBytes_AsString(key), NULL, NULL)) { PyErr_Format (PyExc_TypeError, "%.200s() got an unexpected keyword argument '%.400s'", function_name, @@ -161,12 +165,12 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, /* Fast path, we already have the exact number of args and not kwargs. */ n_expected_args = g_slist_length (cache->arg_name_list); - if (n_py_kwargs == 0 && n_py_args == n_expected_args) { + if (n_py_kwargs == 0 && n_py_args == n_expected_args && cache->user_data_varargs_index < 0) { Py_INCREF (py_args); return py_args; } - if (n_expected_args < n_py_args) { + if (cache->user_data_varargs_index < 0 && n_expected_args < n_py_args) { PyErr_Format (PyExc_TypeError, "%.200s() takes exactly %d %sargument%s (%zd given)", function_name, @@ -177,6 +181,13 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, return NULL; } + if (cache->user_data_varargs_index >= 0 && n_py_kwargs > 0 && n_expected_args < n_py_args) { + PyErr_Format (PyExc_TypeError, + "%.200s() cannot use variable user data arguments with keyword arguments", + function_name); + return NULL; + } + if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (function_name, cache->arg_name_hash, py_kwargs)) { @@ -187,39 +198,73 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, * when they are combined into a single tuple */ combined_py_args = PyTuple_New (n_expected_args); - for (i = 0; i < n_py_args; i++) { - PyObject *item = PyTuple_GET_ITEM (py_args, i); - Py_INCREF (item); - PyTuple_SET_ITEM (combined_py_args, i, item); - } - for (i = 0, l = cache->arg_name_list; i < n_expected_args && l; i++, l = l->next) { - PyObject *py_arg_item, *kw_arg_item = NULL; + PyObject *py_arg_item = NULL; + PyObject *kw_arg_item = NULL; const gchar *arg_name = l->data; + int arg_cache_index = -1; + gboolean is_varargs_user_data = FALSE; + + if (arg_name != NULL) + arg_cache_index = GPOINTER_TO_INT (g_hash_table_lookup (cache->arg_name_hash, arg_name)); + + is_varargs_user_data = cache->user_data_varargs_index >= 0 && + arg_cache_index == cache->user_data_varargs_index; if (n_py_kwargs > 0 && arg_name != NULL) { /* NULL means this argument has no keyword name */ /* ex. the first argument to a method or constructor */ kw_arg_item = PyDict_GetItemString (py_kwargs, arg_name); } - py_arg_item = PyTuple_GET_ITEM (combined_py_args, i); - if (kw_arg_item != NULL && py_arg_item == NULL) { - Py_INCREF (kw_arg_item); - PyTuple_SET_ITEM (combined_py_args, i, kw_arg_item); + /* use a bounded retrieval of the original input */ + if (i < n_py_args) + py_arg_item = PyTuple_GET_ITEM (py_args, i); + + if (kw_arg_item == NULL && py_arg_item != NULL) { + if (is_varargs_user_data) { + /* For tail end user_data varargs, pull a slice off and we are done. */ + PyObject *user_data = PyTuple_GetSlice (py_args, i, PY_SSIZE_T_MAX); + PyTuple_SET_ITEM (combined_py_args, i, user_data); + return combined_py_args; + } else { + Py_INCREF (py_arg_item); + PyTuple_SET_ITEM (combined_py_args, i, py_arg_item); + } + } else if (kw_arg_item != NULL && py_arg_item == NULL) { + if (is_varargs_user_data) { + /* Special case where user_data is passed as a keyword argument (user_data=foo) + * Wrap the value in a tuple to represent variable args for marshaling later on. + */ + PyObject *user_data = Py_BuildValue("(O)", kw_arg_item, NULL); + PyTuple_SET_ITEM (combined_py_args, i, user_data); + } else { + Py_INCREF (kw_arg_item); + PyTuple_SET_ITEM (combined_py_args, i, kw_arg_item); + } } else if (kw_arg_item == NULL && py_arg_item == NULL) { - PyErr_Format (PyExc_TypeError, - "%.200s() takes exactly %d %sargument%s (%zd given)", - function_name, - n_expected_args, - n_py_kwargs > 0 ? "non-keyword " : "", - n_expected_args == 1 ? "" : "s", - n_py_args); - - Py_DECREF (combined_py_args); - return NULL; - + if (is_varargs_user_data) { + /* For varargs user_data, pass an empty tuple when nothing is given. */ + PyTuple_SET_ITEM (combined_py_args, i, PyTuple_New (0)); + } else if (arg_cache_index >= 0 && _pygi_callable_cache_get_arg (cache, arg_cache_index)->has_default) { + /* If the argument supports a default, use a place holder in the + * argument tuple, this will be checked later during marshaling. + */ + Py_INCREF (_PyGIDefaultArgPlaceholder); + PyTuple_SET_ITEM (combined_py_args, i, _PyGIDefaultArgPlaceholder); + } else { + PyErr_Format (PyExc_TypeError, + "%.200s() takes exactly %d %sargument%s (%zd given)", + function_name, + n_expected_args, + n_py_kwargs > 0 ? "non-keyword " : "", + n_expected_args == 1 ? "" : "s", + n_py_args); + + Py_DECREF (combined_py_args); + return NULL; + } } else if (kw_arg_item != NULL && py_arg_item != NULL) { PyErr_Format (PyExc_TypeError, "%.200s() got multiple values for keyword argument '%.200s'", @@ -299,14 +344,14 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state, } state->n_py_in_args = PyTuple_Size (state->py_in_args); - state->args = g_slice_alloc0 (cache->n_args * sizeof (GIArgument *)); - if (state->args == NULL && cache->n_args != 0) { + state->args = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (GIArgument *)); + if (state->args == NULL && _pygi_callable_cache_args_len (cache) != 0) { PyErr_NoMemory(); return FALSE; } - state->args_data = g_slice_alloc0 (cache->n_args * sizeof (gpointer)); - if (state->args_data == NULL && cache->n_args != 0) { + state->args_cleanup_data = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (gpointer)); + if (state->args_cleanup_data == NULL && _pygi_callable_cache_args_len (cache) != 0) { PyErr_NoMemory(); return FALSE; } @@ -337,8 +382,8 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state, static inline void _invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache) { - g_slice_free1 (cache->n_args * sizeof(GIArgument *), state->args); - g_slice_free1 (cache->n_args * sizeof(gpointer), state->args_data); + g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(GIArgument *), state->args); + g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(gpointer), state->args_cleanup_data); g_slice_free1 (cache->n_from_py_args * sizeof(GIArgument), state->in_args); g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_args); g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_values); @@ -408,9 +453,9 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) return FALSE; } - for (i = 0; i < cache->n_args; i++) { + for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { GIArgument *c_arg; - PyGIArgCache *arg_cache = cache->args_cache[i]; + PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); PyObject *py_arg = NULL; switch (arg_cache->direction) { @@ -490,8 +535,12 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) } c_arg = state->args[i]; - if (arg_cache->from_py_marshaller != NULL) { + if (py_arg == _PyGIDefaultArgPlaceholder) { + *c_arg = arg_cache->default_value; + } else if (arg_cache->from_py_marshaller != NULL) { gboolean success; + gpointer cleanup_data = NULL; + if (!arg_cache->allow_none && py_arg == Py_None) { PyErr_Format (PyExc_TypeError, "Argument %zd does not allow None as a value", @@ -503,10 +552,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) return FALSE; } success = arg_cache->from_py_marshaller (state, - cache, - arg_cache, - py_arg, - c_arg); + cache, + arg_cache, + py_arg, + c_arg, + &cleanup_data); + state->args_cleanup_data[i] = cleanup_data; + if (!success) { pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, @@ -563,6 +615,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) if (to_py_cleanup != NULL) to_py_cleanup ( state, cache->return_cache, + NULL, &state->return_arg, FALSE); } @@ -652,9 +705,9 @@ pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, if (!_invoke_callable (&state, cache, info, function_ptr)) goto err; + ret = _invoke_marshal_out_args (&state, cache); pygi_marshal_cleanup_args_from_py_marshal_success (&state, cache); - ret = _invoke_marshal_out_args (&state, cache); if (ret) pygi_marshal_cleanup_args_to_py_marshal_success (&state, cache); err: diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c index c197bab..33d0339 100644 --- a/gi/pygi-marshal-cleanup.c +++ b/gi/pygi-marshal-cleanup.c @@ -24,6 +24,7 @@ static inline void _cleanup_caller_allocates (PyGIInvokeState *state, PyGIArgCache *cache, + PyObject *py_obj, gpointer data, gboolean was_processed) { @@ -93,20 +94,23 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, { gssize i; - /* For in success, call cleanup for all GI_DIRECTION_IN values only. */ - for (i = 0; i < cache->n_args; i++) { - PyGIArgCache *arg_cache = cache->args_cache[i]; + for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; - - if (cleanup_func && - arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON && - state->args[i]->v_pointer != NULL) - cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE); - - if (cleanup_func && - arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL && - state->args_data[i] != NULL) { - cleanup_func (state, arg_cache, state->args_data[i], TRUE); + PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, + arg_cache->py_arg_index); + gpointer cleanup_data = state->args_cleanup_data[i]; + + /* Only cleanup using args_cleanup_data when available. + * It is the responsibility of the various "from_py" marshalers to return + * cleanup_data which is then passed into their respective cleanup function. + * PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args) + * for the duration of the invoke up until this point. + */ + if (cleanup_func && cleanup_data != NULL && + arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE); + state->args_cleanup_data[i] = NULL; } } } @@ -122,6 +126,7 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, if (cleanup_func && state->return_arg.v_pointer != NULL) cleanup_func (state, cache->return_cache, + NULL, state->return_arg.v_pointer, TRUE); } @@ -136,11 +141,13 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, if (cleanup_func != NULL && data != NULL) cleanup_func (state, arg_cache, + NULL, data, TRUE); else if (arg_cache->is_caller_allocates && data != NULL) { _cleanup_caller_allocates (state, arg_cache, + NULL, data, TRUE); } @@ -158,22 +165,26 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, state->failed = TRUE; - for (i = 0; i < cache->n_args && i <= failed_arg_index; i++) { - PyGIArgCache *arg_cache = cache->args_cache[i]; + for (i = 0; i < _pygi_callable_cache_args_len (cache) && i <= failed_arg_index; i++) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; gpointer data = state->args[i]->v_pointer; + PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, + arg_cache->py_arg_index); if (cleanup_func && arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON && data != NULL) { cleanup_func (state, arg_cache, + py_arg, data, i < failed_arg_index); } else if (arg_cache->is_caller_allocates && data != NULL) { _cleanup_caller_allocates (state, arg_cache, + py_arg, data, FALSE); } @@ -198,18 +209,19 @@ pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { - /* We strdup strings so always free if we have processed this - parameter for input */ - if (was_processed) + /* We strdup strings so free unless ownership is transferred to C. */ + if (was_processed && arg_cache->transfer == GI_TRANSFER_NOTHING) g_free (data); } void _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { @@ -223,6 +235,7 @@ _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { @@ -236,6 +249,7 @@ _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, void _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { @@ -249,28 +263,31 @@ _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache; if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) { - _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]); - state->args_data[arg_cache->c_arg_index] = NULL; + _pygi_invoke_closure_free (data); } } void _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { - if (was_processed) { - PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, - arg_cache->py_arg_index); + /* Note py_arg can be NULL for hash table which is a bug. */ + if (was_processed && py_arg != NULL) { GType py_object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE); + /* When a GValue was not passed, it means the marshalers created a new + * one to pass in, clean this up. + */ if (py_object_type != G_TYPE_VALUE) { g_value_unset ((GValue *) data); g_slice_free (GValue, data); @@ -281,6 +298,7 @@ _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { @@ -293,6 +311,7 @@ _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { @@ -336,6 +355,7 @@ _wrap_c_array (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { @@ -344,15 +364,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, GPtrArray *ptr_array_ = NULL; PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - /* If this isn't a garray create one to help process variable sized - array elements */ - if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { - array_ = _wrap_c_array (state, sequence_cache, data); - - if (array_ == NULL) - return; - - } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { + if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { ptr_array_ = (GPtrArray *) data; } else { array_ = (GArray *) data; @@ -367,6 +379,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, for (i = 0; i < len; i++) { gpointer item; + PyObject *py_item = NULL; /* case 1: GPtrArray */ if (ptr_array_ != NULL) @@ -387,19 +400,23 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, } } - cleanup_func (state, sequence_cache->item_cache, item, TRUE); + py_item = PySequence_GetItem (py_arg, i); + cleanup_func (state, sequence_cache->item_cache, py_item, item, TRUE); + Py_XDECREF (py_item); } } /* Only free the array when we didn't transfer ownership */ if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { + /* always free the GArray wrapper created in from_py marshaling and + * passed back as cleanup_data + */ g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING); - } else if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING) { + } else { if (array_ != NULL) - g_array_free (array_, TRUE); + g_array_unref (array_); else - g_ptr_array_free (ptr_array_, TRUE); + g_ptr_array_unref (ptr_array_); } } } @@ -407,6 +424,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, void _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { @@ -438,6 +456,7 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, for (i = 0; i < len; i++) { cleanup_func (state, sequence_cache->item_cache, + NULL, (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i), was_processed); } @@ -453,6 +472,7 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { @@ -467,28 +487,26 @@ _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->from_py_cleanup; GSList *node = list_; + gsize i = 0; while (node != NULL) { + PyObject *py_item = PySequence_GetItem (py_arg, i); cleanup_func (state, sequence_cache->item_cache, + py_item, node->data, TRUE); + Py_XDECREF (py_item); node = node->next; + i++; } } - if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) { - switch (arg_cache->type_tag) { - case GI_TYPE_TAG_GLIST: - g_list_free ( (GList *)list_); - break; - case GI_TYPE_TAG_GSLIST: - g_slist_free (list_); - break; - default: - g_assert_not_reached(); - } + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); } } } @@ -496,11 +514,11 @@ _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, void _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER) { GSList *list_ = (GSList *)data; @@ -513,23 +531,19 @@ _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, while (node != NULL) { cleanup_func (state, sequence_cache->item_cache, + NULL, node->data, was_processed); node = node->next; } } - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) { - switch (arg_cache->type_tag) { - case GI_TYPE_TAG_GLIST: - g_list_free ( (GList *)list_); - break; - case GI_TYPE_TAG_GSLIST: - g_slist_free (list_); - break; - default: - g_assert_not_reached(); - } + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); } } } @@ -537,6 +551,7 @@ _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed) { @@ -566,27 +581,26 @@ _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, if (key != NULL && key_cleanup_func != NULL) key_cleanup_func (state, hash_cache->key_cache, + NULL, key, TRUE); if (value != NULL && value_cleanup_func != NULL) value_cleanup_func (state, hash_cache->value_cache, + NULL, value, TRUE); } } - if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) - g_hash_table_destroy (hash_); - + g_hash_table_unref (hash_); } } void _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed) { @@ -594,6 +608,6 @@ _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, return; /* assume hashtable has boxed key and value */ - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_hash_table_destroy ( (GHashTable *)data); + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER) + g_hash_table_unref ( (GHashTable *)data); } diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h index 234e49c..3acfbeb 100644 --- a/gi/pygi-marshal-cleanup.h +++ b/gi/pygi-marshal-cleanup.h @@ -42,58 +42,72 @@ void pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, void _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); void _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *dummy, gpointer data, gboolean was_processed); G_END_DECLS diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c index 57b4126..7bcba66 100644 --- a/gi/pygi-marshal-from-py.c +++ b/gi/pygi-marshal-from-py.c @@ -247,7 +247,8 @@ _pygi_marshal_from_py_void (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING); @@ -255,23 +256,16 @@ _pygi_marshal_from_py_void (PyGIInvokeState *state, arg->v_pointer = NULL; } else if (PYGLIB_CPointer_Check(py_arg)) { arg->v_pointer = PYGLIB_CPointer_GetPointer (py_arg, NULL); + } else if (PYGLIB_PyLong_Check(py_arg) || PyLong_Check(py_arg)) { + arg->v_pointer = PyLong_AsVoidPtr (py_arg); } else { - /* NOTE: This will change to only allow integers and the deprecation - * warning will become a runtime exception. Using the following: - * arg->v_pointer = PyLong_AsVoidPtr (py_arg); - * See: https://bugzilla.gnome.org/show_bug.cgi?id=688081 - */ - - if (!PYGLIB_PyLong_Check(py_arg) && !PyLong_Check(py_arg)) { - if (PyErr_WarnEx(PyGIDeprecationWarning, - "Pointer arguments will be restricted to integers, capsules, and None. " - "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599", - 1)) - return FALSE; - } - arg->v_pointer = py_arg; + PyErr_SetString(PyExc_ValueError, + "Pointer arguments are restricted to integers, capsules, and None. " + "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599"); + return FALSE; } + *cleanup_data = arg->v_pointer; return TRUE; } @@ -416,7 +410,8 @@ _pygi_marshal_from_py_gtype (PyObject *py_arg, static gboolean _pygi_marshal_from_py_utf8 (PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { gchar *string_; @@ -445,12 +440,14 @@ _pygi_marshal_from_py_utf8 (PyObject *py_arg, } arg->v_string = string_; + *cleanup_data = arg->v_string; return TRUE; } static gboolean _pygi_marshal_from_py_filename (PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { gchar *string_; GError *error = NULL; @@ -484,6 +481,7 @@ _pygi_marshal_from_py_filename (PyObject *py_arg, return FALSE; } + *cleanup_data = arg->v_string; return TRUE; } @@ -634,7 +632,8 @@ gboolean _pygi_marshal_from_py_basic_type (PyObject *object, /* in */ GIArgument *arg, /* out */ GITypeTag type_tag, - GITransfer transfer) + GITransfer transfer, + gpointer *cleanup_data /* out */) { switch (type_tag) { case GI_TYPE_TAG_VOID: @@ -647,6 +646,7 @@ _pygi_marshal_from_py_basic_type (PyObject *object, /* in */ "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599"); } else { arg->v_pointer = PyLong_AsVoidPtr (object); + *cleanup_data = arg->v_pointer; } break; case GI_TYPE_TAG_INT8: @@ -690,10 +690,10 @@ _pygi_marshal_from_py_basic_type (PyObject *object, /* in */ return _pygi_marshal_from_py_unichar (object, arg); case GI_TYPE_TAG_UTF8: - return _pygi_marshal_from_py_utf8 (object, arg); + return _pygi_marshal_from_py_utf8 (object, arg, cleanup_data); case GI_TYPE_TAG_FILENAME: - return _pygi_marshal_from_py_filename (object, arg); + return _pygi_marshal_from_py_filename (object, arg, cleanup_data); default: return FALSE; @@ -710,12 +710,14 @@ _pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { return _pygi_marshal_from_py_basic_type (py_arg, arg, arg_cache->type_tag, - arg_cache->transfer); + arg_cache->transfer, + cleanup_data); } gboolean @@ -723,10 +725,12 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyGIMarshalFromPyFunc from_py_marshaller; int i = 0; + int success_count = 0; Py_ssize_t length; gssize item_size; gboolean is_ptr_array; @@ -760,10 +764,10 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, item_size = sequence_cache->item_size; is_ptr_array = (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY); if (is_ptr_array) { - array_ = (GArray *)g_ptr_array_new (); + array_ = (GArray *)g_ptr_array_sized_new (length); } else { array_ = g_array_sized_new (sequence_cache->is_zero_terminated, - FALSE, + TRUE, item_size, length); } @@ -786,8 +790,9 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, } from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; - for (i = 0; i < length; i++) { - GIArgument item; + for (i = 0, success_count = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; PyObject *py_item = PySequence_GetItem (py_arg, i); if (py_item == NULL) goto err; @@ -796,8 +801,26 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, callable_cache, sequence_cache->item_cache, py_item, - &item)) + &item, + &item_cleanup_data)) { + Py_DECREF (py_item); + goto err; + } + Py_DECREF (py_item); + + if (item_cleanup_data != NULL && item_cleanup_data != item.v_pointer) { + /* We only support one level of data discrepancy between an items + * data and its cleanup data. This is because we only track a single + * extra cleanup data pointer per-argument and cannot track the entire + * array of items differing data and cleanup_data. + * For example, this would fail if trying to marshal an array of + * callback closures marked with SCOPE call type where the cleanup data + * is different from the items v_pointer, likewise an array of arrays. + */ + PyErr_SetString(PyExc_RuntimeError, "Cannot cleanup item data for array due to " + "the items data its cleanup data being different."); goto err; + } /* FIXME: it is much more efficent to have seperate marshaller * for ptr arrays than doing the evaluation @@ -805,7 +828,12 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, */ if (is_ptr_array) { g_ptr_array_add((GPtrArray *)array_, item.v_pointer); + } else if (sequence_cache->item_cache->is_pointer) { + /* if the item is a pointer, simply copy the pointer */ + g_assert (item_size == sizeof (item.v_pointer)); + g_array_insert_val (array_, i, item); } else if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_INTERFACE) { + /* Special case handling of flat arrays of gvalue/boxed/struct */ PyGIInterfaceCache *item_iface_cache = (PyGIInterfaceCache *) sequence_cache->item_cache; GIBaseInfo *base_info = (GIBaseInfo *) item_iface_cache->interface_info; GIInfoType info_type = g_base_info_get_type (base_info); @@ -816,58 +844,41 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, { PyGIArgCache *item_arg_cache = (PyGIArgCache *)item_iface_cache; PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup; - gboolean is_boxed = g_type_is_a (item_iface_cache->g_type, G_TYPE_BOXED); - gboolean is_gvalue = item_iface_cache->g_type == G_TYPE_VALUE; - gboolean is_gvariant = item_iface_cache->g_type == G_TYPE_VARIANT; - - if (is_gvariant) { - /* Item size will always be that of a pointer, - * since GVariants are opaque hence always passed by ref */ - g_assert (item_size == sizeof (item.v_pointer)); - g_array_insert_val (array_, i, item.v_pointer); - } else if (is_gvalue) { + + if (g_type_is_a (item_iface_cache->g_type, G_TYPE_VALUE)) { + /* Special case GValue flat arrays to properly init and copy the contents. */ GValue* dest = (GValue*) (array_->data + (i * item_size)); - memset (dest, 0, item_size); if (item.v_pointer != NULL) { + memset (dest, 0, item_size); g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer)); g_value_copy ((GValue*) item.v_pointer, dest); } - /* we free the original copy already, the new one is a plain struct - * in an array. _pygi_marshal_cleanup_from_py_array() does not free it again */ - if (from_py_cleanup) - from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE); - } else if (!is_boxed) { - /* HACK: Gdk.Atom is merely an integer wrapped in a pointer, - * so we must not dereference it; just copy the pointer - * value, and don't attempt to free it. TODO: find out - * if there are other data types with similar behaviour - * and generalize. */ - if (g_strcmp0 (item_iface_cache->type_name, "Gdk.Atom") == 0) { - g_assert (item_size == sizeof (item.v_pointer)); - memcpy (array_->data + (i * item_size), &item.v_pointer, item_size); - } else { - memcpy (array_->data + (i * item_size), item.v_pointer, item_size); - - if (from_py_cleanup) - from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE); - } - } else if (is_boxed && !item_iface_cache->arg_cache.is_pointer) { - /* The array elements are not expected to be pointers, but the - * elements obtained are boxed pointers themselves, so insert - * the pointed to data. - */ - g_array_insert_vals (array_, i, item.v_pointer, 1); + /* Manually increment the length because we are manually setting the memory. */ + array_->len++; + } else { - g_array_insert_val (array_, i, item); + /* Handles flat arrays of boxed or struct types. */ + g_array_insert_vals (array_, i, item.v_pointer, 1); } + + /* Cleanup any memory left by the per-item marshaler because + * _pygi_marshal_cleanup_from_py_array will not know about this + * due to "item" being a temporarily marshaled value done on the stack. + */ + if (from_py_cleanup) + from_py_cleanup (state, item_arg_cache, py_item, item_cleanup_data, TRUE); + break; } default: g_array_insert_val (array_, i, item); } } else { + /* default value copy of a simple type */ g_array_insert_val (array_, i, item); } + + success_count++; continue; err: if (sequence_cache->item_cache->from_py_cleanup != NULL) { @@ -875,11 +886,19 @@ err: PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->from_py_cleanup; - for(j = 0; j < i; j++) { - cleanup_func (state, - sequence_cache->item_cache, - g_array_index (array_, gpointer, j), - TRUE); + /* Only attempt per item cleanup on pointer items */ + if (sequence_cache->item_cache->is_pointer) { + for(j = 0; j < success_count; j++) { + PyObject *py_item = PySequence_GetItem (py_arg, j); + cleanup_func (state, + sequence_cache->item_cache, + py_item, + is_ptr_array ? + g_ptr_array_index ((GPtrArray *)array_, j) : + g_array_index (array_, gpointer, j), + TRUE); + Py_DECREF (py_item); + } } } @@ -895,7 +914,7 @@ array_success: if (sequence_cache->len_arg_index >= 0) { /* we have an child arg to handle */ PyGIArgCache *child_cache = - callable_cache->args_cache[sequence_cache->len_arg_index]; + _pygi_callable_cache_get_arg (callable_cache, sequence_cache->len_arg_index); if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) { gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer; @@ -919,14 +938,34 @@ array_success: } if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { + /* In the case of GI_ARRAY_C, we give the data directly as the argument + * but keep the array_ wrapper as cleanup data so we don't have to find + * it's length again. + */ arg->v_pointer = array_->data; - g_array_free (array_, FALSE); - /* remember the originally allocated array in args_data, as args and - * in_args get changed for (inout) arguments */ - if (arg_cache->transfer == GI_TRANSFER_NOTHING) - state->args_data[arg_cache->c_arg_index] = arg->v_pointer; + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) { + g_array_free (array_, FALSE); + *cleanup_data = NULL; + } else { + *cleanup_data = array_; + } } else { arg->v_pointer = array_; + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = array_; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = is_ptr_array ? + (gpointer)g_ptr_array_ref ((GPtrArray *)array_) : + (gpointer)g_array_ref (array_); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } } return TRUE; @@ -937,7 +976,8 @@ _pygi_marshal_from_py_glist (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyGIMarshalFromPyFunc from_py_marshaller; int i; @@ -971,7 +1011,8 @@ _pygi_marshal_from_py_glist (PyGIInvokeState *state, from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; for (i = 0; i < length; i++) { - GIArgument item; + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; PyObject *py_item = PySequence_GetItem (py_arg, i); if (py_item == NULL) goto err; @@ -980,9 +1021,11 @@ _pygi_marshal_from_py_glist (PyGIInvokeState *state, callable_cache, sequence_cache->item_cache, py_item, - &item)) + &item, + &item_cleanup_data)) goto err; + Py_DECREF (py_item); list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); continue; err: @@ -991,12 +1034,25 @@ err: PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; } */ + Py_DECREF (py_item); g_list_free (list_); _PyGI_ERROR_PREFIX ("Item %i: ", i); return FALSE; } arg->v_pointer = g_list_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_list_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } return TRUE; } @@ -1005,7 +1061,8 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyGIMarshalFromPyFunc from_py_marshaller; int i; @@ -1038,7 +1095,8 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState *state, from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; for (i = 0; i < length; i++) { - GIArgument item; + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; PyObject *py_item = PySequence_GetItem (py_arg, i); if (py_item == NULL) goto err; @@ -1047,9 +1105,11 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState *state, callable_cache, sequence_cache->item_cache, py_item, - &item)) + &item, + &item_cleanup_data)) goto err; + Py_DECREF (py_item); list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); continue; err: @@ -1059,12 +1119,26 @@ err: } */ + Py_DECREF (py_item); g_slist_free (list_); _PyGI_ERROR_PREFIX ("Item %i: ", i); return FALSE; } arg->v_pointer = g_slist_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_slist_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + return TRUE; } @@ -1073,7 +1147,8 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyGIMarshalFromPyFunc key_from_py_marshaller; PyGIMarshalFromPyFunc value_from_py_marshaller; @@ -1136,6 +1211,8 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState *state, for (i = 0; i < length; i++) { GIArgument key, value; + gpointer key_cleanup_data = NULL; + gpointer value_cleanup_data = NULL; PyObject *py_key = PyList_GET_ITEM (py_keys, i); PyObject *py_value = PyList_GET_ITEM (py_values, i); if (py_key == NULL || py_value == NULL) @@ -1145,14 +1222,16 @@ _pygi_marshal_from_py_ghash (PyGIInvokeState *state, callable_cache, hash_cache->key_cache, py_key, - &key)) + &key, + &key_cleanup_data)) goto err; if (!value_from_py_marshaller ( state, callable_cache, hash_cache->value_cache, py_value, - &value)) + &value, + &value_cleanup_data)) goto err; g_hash_table_insert (hash_, @@ -1171,6 +1250,21 @@ err: } arg->v_pointer = hash_; + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_hash_table_ref (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. + * Note that the keys and values will leak for transfer everything because + * we do not use g_hash_table_new_full and set key/value_destroy_func. */ + *cleanup_data = NULL; + } + return TRUE; } @@ -1179,7 +1273,8 @@ _pygi_marshal_from_py_gerror (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyErr_Format (PyExc_NotImplementedError, "Marshalling for GErrors is not implemented"); @@ -1245,7 +1340,8 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { GICallableInfo *callable_info; PyGICClosure *closure; @@ -1257,12 +1353,17 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, callback_cache = (PyGICallbackCache *)arg_cache; if (callback_cache->user_data_index > 0) { - user_data_cache = callable_cache->args_cache[callback_cache->user_data_index]; + user_data_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->user_data_index); if (user_data_cache->py_arg_index < state->n_py_in_args) { /* py_user_data is a borrowed reference. */ py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index); if (!py_user_data) return FALSE; + /* NULL out user_data if it was not supplied and the default arg placeholder + * was used instead. + */ + if (py_user_data == _PyGIDefaultArgPlaceholder) + py_user_data = NULL; } } @@ -1305,7 +1406,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, * later on in _pygi_destroy_notify_callback_closure. */ if (callback_cache->destroy_notify_index > 0) { - destroy_cache = callable_cache->args_cache[callback_cache->destroy_notify_index]; + destroy_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->destroy_notify_index); } if (destroy_cache) { @@ -1327,10 +1428,8 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, } } - /* Store the PyGIClosure as extra args data so _pygi_marshal_cleanup_from_py_interface_callback - * can clean it up later for GI_SCOPE_TYPE_CALL based closures. - */ - state->args_data[arg_cache->c_arg_index] = closure; + /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */ + *cleanup_data = closure; return TRUE; } @@ -1340,7 +1439,8 @@ _pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyObject *py_long; long c_long; @@ -1408,7 +1508,8 @@ _pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyObject *py_long; long c_long; @@ -1455,20 +1556,27 @@ _pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - return _pygi_marshal_from_py_interface_struct (py_arg, - arg, - arg_cache->arg_name, - iface_cache->interface_info, - arg_cache->type_info, - iface_cache->g_type, - iface_cache->py_type, - arg_cache->transfer, - TRUE, /*copy_reference*/ - iface_cache->is_foreign); + gboolean res = _pygi_marshal_from_py_interface_struct (py_arg, + arg, + arg_cache->arg_name, + iface_cache->interface_info, + iface_cache->g_type, + iface_cache->py_type, + arg_cache->transfer, + TRUE, /*copy_reference*/ + iface_cache->is_foreign, + arg_cache->is_pointer); + + /* Assume struct marshaling is always a pointer and assign cleanup_data + * here rather than passing it further down the chain. + */ + *cleanup_data = arg->v_pointer; + return res; } gboolean @@ -1476,7 +1584,8 @@ _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyErr_Format (PyExc_NotImplementedError, "Marshalling for this type is not implemented yet"); @@ -1488,8 +1597,11 @@ _pygi_marshal_from_py_interface_object (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { + gboolean res = FALSE; + if (py_arg == Py_None) { arg->v_pointer = NULL; return TRUE; @@ -1509,7 +1621,9 @@ _pygi_marshal_from_py_interface_object (PyGIInvokeState *state, return FALSE; } - return _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer); + res = _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer); + *cleanup_data = arg->v_pointer; + return res; } gboolean @@ -1517,90 +1631,14 @@ _pygi_marshal_from_py_interface_union (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg) + GIArgument *arg, + gpointer *cleanup_data) { PyErr_Format(PyExc_NotImplementedError, "Marshalling for this type is not implemented yet"); return FALSE; } -gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - GIInfoType info_type; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - - info_type = g_base_info_get_type (iface_cache->interface_info); - switch (info_type) { - case GI_INFO_TYPE_UNION: - case GI_INFO_TYPE_STRUCT: - { - GType type = iface_cache->g_type; - - if (!PyObject_IsInstance (py_arg, iface_cache->py_type)) { - /* wait, we might be a member of a union so manually check */ - if (!_is_union_member (iface_cache->interface_info, py_arg)) { - if (!PyErr_Occurred()) { - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - PyErr_Format (PyExc_TypeError, - "argument %s: Expected a %s, but got %s%s%s", - arg_cache->arg_name ? arg_cache->arg_name : "self", - iface_cache->type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - } - return FALSE; - } - } - - if (g_type_is_a (type, G_TYPE_BOXED)) { - arg->v_pointer = pyg_boxed_get (py_arg, void); - } else if (g_type_is_a (type, G_TYPE_POINTER) || - g_type_is_a (type, G_TYPE_VARIANT) || - type == G_TYPE_NONE) { - arg->v_pointer = pyg_pointer_get (py_arg, void); - } else { - PyErr_Format (PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name (type)); - return FALSE; - } - - break; - } - case GI_INFO_TYPE_OBJECT: - case GI_INFO_TYPE_INTERFACE: - arg->v_pointer = pygobject_get (py_arg); - if (arg->v_pointer != NULL) { - GType obj_type = G_OBJECT_TYPE (( GObject *)arg->v_pointer); - GType expected_type = iface_cache->g_type; - - if (!g_type_is_a (obj_type, expected_type)) { - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", - arg_cache->arg_name ? arg_cache->arg_name : "self", - iface_cache->type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - return FALSE; - } - } - break; - default: - /* Other types don't have methods. */ - g_assert_not_reached (); - } - - return TRUE; -} - /* _pygi_marshal_from_py_gobject: * py_arg: (in): * arg: (out): @@ -1773,12 +1811,12 @@ _pygi_marshal_from_py_interface_struct (PyObject *py_arg, GIArgument *arg, const gchar *arg_name, GIBaseInfo *interface_info, - GITypeInfo *type_info, GType g_type, PyObject *py_type, GITransfer transfer, gboolean copy_reference, - gboolean is_foreign) + gboolean is_foreign, + gboolean is_pointer) { gboolean is_union = FALSE; @@ -1834,7 +1872,7 @@ _pygi_marshal_from_py_interface_struct (PyObject *py_arg, } else if (g_type_is_a (g_type, G_TYPE_POINTER) || g_type_is_a (g_type, G_TYPE_VARIANT) || g_type == G_TYPE_NONE) { - g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING); + g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !is_pointer || transfer == GI_TRANSFER_NOTHING); if (g_type_is_a (g_type, G_TYPE_VARIANT) && pyg_type_from_object (py_arg) != G_TYPE_VARIANT) { @@ -1842,6 +1880,9 @@ _pygi_marshal_from_py_interface_struct (PyObject *py_arg, return FALSE; } arg->v_pointer = pyg_pointer_get (py_arg, void); + if (transfer == GI_TRANSFER_EVERYTHING) { + g_variant_ref ((GVariant *)arg->v_pointer); + } } else { PyErr_Format (PyExc_NotImplementedError, diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h index 9f56a6f..f8e4699 100644 --- a/gi/pygi-marshal-from-py.h +++ b/gi/pygi-marshal-from-py.h @@ -37,88 +37,93 @@ gboolean _pygi_marshal_from_py_void (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_array (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_glist (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_gslist (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_ghash (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_gerror (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_interface(PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_object (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); /* Simplified marshalers shared between vfunc/closure and direct function calls. */ gboolean _pygi_marshal_from_py_basic_type (PyObject *object, /* in */ GIArgument *arg, /* out */ GITypeTag type_tag, - GITransfer transfer); + GITransfer transfer, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); gboolean _pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/ GIArgument *arg, /*out*/ @@ -139,12 +144,12 @@ gboolean _pygi_marshal_from_py_interface_struct (PyObject *py_arg, GIArgument *arg, const gchar *arg_name, GIBaseInfo *interface_info, - GITypeInfo *type_info, GType g_type, PyObject *py_type, GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign); + gboolean is_allocated, + gboolean is_foreign, + gboolean is_pointer); G_END_DECLS diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c index 7c260f7..2c7a8de 100644 --- a/gi/pygi-marshal-to-py.c +++ b/gi/pygi-marshal-to-py.c @@ -117,20 +117,10 @@ _pygi_marshal_to_py_void (PyGIInvokeState *state, PyGIArgCache *arg_cache, GIArgument *arg) { - PyObject *py_obj = NULL; if (arg_cache->is_pointer) { - /* NOTE: This will change to interpret pointers as integer values - * by using the following: - * py_obj = PyLong_FromVoidPtr (arg->v_pointer); - * See: https://bugzilla.gnome.org/show_bug.cgi?id=688081 - */ - py_obj = arg->v_pointer; - } else { - py_obj = Py_None; + return PyLong_FromVoidPtr (arg->v_pointer); } - - Py_XINCREF (py_obj); - return py_obj; + Py_RETURN_NONE; } static PyObject * @@ -306,10 +296,10 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state, } } else { GIArgument *len_arg = state->args[seq_cache->len_arg_index]; + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, + seq_cache->len_arg_index); - if (!gi_argument_to_gsize (len_arg, - &len, - callable_cache->args_cache[seq_cache->len_arg_index]->type_tag)) { + if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) { return NULL; } } @@ -361,36 +351,35 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state, item_size = g_array_get_element_size (array_); for (i = 0; i < array_->len; i++) { - GIArgument item_arg; + GIArgument item_arg = {0}; PyObject *py_item; + /* If we are receiving an array of pointers, simply assign the pointer + * and move on, letting the per-item marshaler deal with the + * various transfer modes and ref counts (e.g. g_variant_ref_sink). + */ if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i); + + } else if (item_arg_cache->is_pointer) { + item_arg.v_pointer = g_array_index (array_, gpointer, i); + } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache; - gboolean is_gvariant = iface_cache->g_type == G_TYPE_VARIANT; // FIXME: This probably doesn't work with boxed types or gvalues. See fx. _pygi_marshal_from_py_array() switch (g_base_info_get_type (iface_cache->interface_info)) { case GI_INFO_TYPE_STRUCT: - if (is_gvariant) { - g_assert (item_size == sizeof (gpointer)); - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - item_arg.v_pointer = g_variant_ref_sink (g_array_index (array_, gpointer, i)); - else - item_arg.v_pointer = g_array_index (array_, gpointer, i); - } else if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && !item_arg_cache->is_pointer && + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { /* array elements are structs */ gpointer *_struct = g_malloc (item_size); memcpy (_struct, array_->data + i * item_size, item_size); item_arg.v_pointer = _struct; - } else if (item_arg_cache->is_pointer) - /* array elements are pointers to values */ - item_arg.v_pointer = g_array_index (array_, gpointer, i); - else + } else { item_arg.v_pointer = array_->data + i * item_size; + } break; default: item_arg.v_pointer = g_array_index (array_, gpointer, i); @@ -435,6 +424,7 @@ err: for (j = processed_items; j < array_->len; j++) { cleanup_func (state, seq_cache->item_cache, + NULL, g_array_index (array_, gpointer, j), FALSE); } @@ -867,10 +857,13 @@ _pygi_marshal_to_py_interface_struct (GIArgument *arg, transfer == GI_TRANSFER_EVERYTHING); } } else if (g_type_is_a (g_type, G_TYPE_VARIANT)) { - /* Note we do not use transfer for the structs free_on_dealloc because - * GLib.Variant overrides __del__ to call "g_variant_unref". */ + /* Note: sink the variant (add a ref) only if we are not transfered ownership. + * GLib.Variant overrides __del__ which will then call "g_variant_unref" for + * cleanup in either case. */ if (py_type) { - g_variant_ref_sink (arg->v_pointer); + if (transfer == GI_TRANSFER_NOTHING) { + g_variant_ref_sink (arg->v_pointer); + } py_obj = _pygi_struct_new ((PyTypeObject *) py_type, arg->v_pointer, FALSE); diff --git a/gi/pygi.h b/gi/pygi.h index 3bf40bb..dcd91b3 100644 --- a/gi/pygi.h +++ b/gi/pygi.h @@ -33,6 +33,7 @@ #include "pygi-cache.h" extern PyObject *PyGIDeprecationWarning; +extern PyObject *_PyGIDefaultArgPlaceholder; typedef struct { PyObject_HEAD diff --git a/gi/repository/Makefile.in b/gi/repository/Makefile.in index aa8bef5..72cbd29 100644 --- a/gi/repository/Makefile.in +++ b/gi/repository/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. diff --git a/pygtkcompat/Makefile.in b/pygtkcompat/Makefile.in index dc9b80b..ab80a82 100644 --- a/pygtkcompat/Makefile.in +++ b/pygtkcompat/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. diff --git a/tests/Makefile.am b/tests/Makefile.am index b845e4b..a7b0323 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -110,6 +110,7 @@ EXTRA_DIST = \ test_atoms.py \ test_generictreemodel.py \ test_docstring.py \ + test_repository.py \ compat_test_pygtk.py \ gi/__init__.py \ gi/overrides/__init__.py \ @@ -152,4 +153,12 @@ check.nemiver: EXEC_NAME="nemiver" $(MAKE) check check.valgrind: - EXEC_NAME="valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + EXEC_NAME="G_SLICE=always-malloc valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + +check.valgrindlog: + mkdir -p $(top_builddir)/tmp + EXEC_NAME="G_SLICE=always-malloc valgrind --log-file=$(top_builddir)/tmp/`git rev-parse HEAD | cut -c1-8`-$$TEST_NAMES.log --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + +check.valgrindxml: + mkdir -p $(top_builddir)/tmp + EXEC_NAME="G_SLICE=always-malloc valgrind --xml=yes --xml-file=$(top_builddir)/tmp/`git rev-parse HEAD | cut -c1-8`-$$TEST_NAMES.xml --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check diff --git a/tests/Makefile.in b/tests/Makefile.in index 7eda339..fc936c6 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -410,6 +410,7 @@ EXTRA_DIST = \ test_atoms.py \ test_generictreemodel.py \ test_docstring.py \ + test_repository.py \ compat_test_pygtk.py \ gi/__init__.py \ gi/overrides/__init__.py \ @@ -494,14 +495,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -832,7 +833,15 @@ check.nemiver: EXEC_NAME="nemiver" $(MAKE) check check.valgrind: - EXEC_NAME="valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + EXEC_NAME="G_SLICE=always-malloc valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + +check.valgrindlog: + mkdir -p $(top_builddir)/tmp + EXEC_NAME="G_SLICE=always-malloc valgrind --log-file=$(top_builddir)/tmp/`git rev-parse HEAD | cut -c1-8`-$$TEST_NAMES.log --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check + +check.valgrindxml: + mkdir -p $(top_builddir)/tmp + EXEC_NAME="G_SLICE=always-malloc valgrind --xml=yes --xml-file=$(top_builddir)/tmp/`git rev-parse HEAD | cut -c1-8`-$$TEST_NAMES.xml --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/tests/test_docstring.py b/tests/test_docstring.py index 1628295..54349b8 100644 --- a/tests/test_docstring.py +++ b/tests/test_docstring.py @@ -2,6 +2,7 @@ import unittest import gi.docstring from gi.repository import GIMarshallingTests +from gi.repository import Gio class Test(unittest.TestCase): @@ -47,3 +48,12 @@ class Test(unittest.TestCase): def test_overridden_doc_is_not_clobbered(self): self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__, 'Overridden doc string.') + + def test_allow_none_with_user_data_defaults(self): + g_file_copy_doc = 'copy(self, destination:Gio.File, ' \ + 'flags:Gio.FileCopyFlags, ' \ + 'cancellable:Gio.Cancellable=None, ' \ + 'progress_callback:Gio.FileProgressCallback=None, ' \ + 'progress_callback_data=None)' + + self.assertEqual(Gio.File.copy.__doc__, g_file_copy_doc) diff --git a/tests/test_everything.py b/tests/test_everything.py index b2f0528..5c4ba6b 100644 --- a/tests/test_everything.py +++ b/tests/test_everything.py @@ -717,6 +717,51 @@ class TestCallbacks(unittest.TestCase): self.assertEqual(TestCallbacks.called, 100) + def test_callback_userdata_no_user_data(self): + TestCallbacks.called = 0 + + def callback(): + TestCallbacks.called += 1 + return TestCallbacks.called + + for i in range(100): + val = Everything.test_callback_user_data(callback) + self.assertEqual(val, i + 1) + + self.assertEqual(TestCallbacks.called, 100) + + def test_callback_userdata_varargs(self): + TestCallbacks.called = 0 + collected_user_data = [] + + def callback(a, b): + collected_user_data.extend([a, b]) + TestCallbacks.called += 1 + return TestCallbacks.called + + for i in range(10): + val = Everything.test_callback_user_data(callback, 1, 2) + self.assertEqual(val, i + 1) + + self.assertEqual(TestCallbacks.called, 10) + self.assertSequenceEqual(collected_user_data, [1, 2] * 10) + + def test_callback_userdata_as_kwarg_tuple(self): + TestCallbacks.called = 0 + collected_user_data = [] + + def callback(user_data): + collected_user_data.extend(user_data) + TestCallbacks.called += 1 + return TestCallbacks.called + + for i in range(10): + val = Everything.test_callback_user_data(callback, user_data=(1, 2)) + self.assertEqual(val, i + 1) + + self.assertEqual(TestCallbacks.called, 10) + self.assertSequenceEqual(collected_user_data, [1, 2] * 10) + def test_async_ready_callback(self): TestCallbacks.called = False TestCallbacks.main_loop = GLib.MainLoop() diff --git a/tests/test_gi.py b/tests/test_gi.py index da55187..43c226e 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -813,6 +813,15 @@ class TestArray(unittest.TestCase): GIMarshallingTests.array_struct_in([struct1, struct2, struct3]) + def test_array_boxed_struct_in_item_marshal_failure(self): + struct1 = GIMarshallingTests.BoxedStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.BoxedStruct() + struct2.long_ = 2 + + self.assertRaises(TypeError, GIMarshallingTests.array_struct_in, + [struct1, struct2, 'not_a_struct']) + def test_array_boxed_struct_value_in(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 @@ -823,6 +832,15 @@ class TestArray(unittest.TestCase): GIMarshallingTests.array_struct_value_in([struct1, struct2, struct3]) + def test_array_boxed_struct_value_in_item_marshal_failure(self): + struct1 = GIMarshallingTests.BoxedStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.BoxedStruct() + struct2.long_ = 2 + + self.assertRaises(TypeError, GIMarshallingTests.array_struct_value_in, + [struct1, struct2, 'not_a_struct']) + def test_array_boxed_struct_take_in(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 @@ -854,6 +872,15 @@ class TestArray(unittest.TestCase): GIMarshallingTests.array_simple_struct_in([struct1, struct2, struct3]) + def test_array_simple_struct_in_item_marshal_failure(self): + struct1 = GIMarshallingTests.SimpleStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.SimpleStruct() + struct2.long_ = 2 + + self.assertRaises(TypeError, GIMarshallingTests.array_simple_struct_in, + [struct1, struct2, 'not_a_struct']) + def test_array_multi_array_key_value_in(self): GIMarshallingTests.multi_array_key_value_in(["one", "two", "three"], [1, 2, 3]) @@ -1219,8 +1246,6 @@ class TestGValue(unittest.TestCase): value = GObject.Value(GObject.TYPE_INT, 42) GIMarshallingTests.gvalue_in(value) - @unittest.skipUnless(hasattr(GIMarshallingTests, 'gvalue_in_with_modification'), - 'Newer version of gi needed.') def test_gvalue_in_with_modification(self): value = GObject.Value(GObject.TYPE_INT, 42) GIMarshallingTests.gvalue_in_with_modification(value) @@ -1261,6 +1286,11 @@ class TestGValue(unittest.TestCase): # the function already asserts the correct values GIMarshallingTests.gvalue_flat_array([42, "42", True]) + def test_gvalue_flat_array_in_item_marshal_failure(self): + # Tests the failure to marshal 2^256 to a GValue mid-way through the array marshaling. + self.assertRaises(RuntimeError, GIMarshallingTests.gvalue_flat_array, + [42, 2 ** 256, True]) + def test_gvalue_flat_array_out(self): values = GIMarshallingTests.return_gvalue_flat_array() self.assertEqual(values, [42, '42', True]) @@ -1479,17 +1509,6 @@ class TestEnum(unittest.TestCase): self.assertEqual(GIMarshallingTests.Enum.__gtype__.name, 'PyGIMarshallingTestsEnum') - def test_enum_double_registration_error(self): - # a warning is printed for double registration and pygobject will - # also raise a RuntimeError. - old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR) - try: - self.assertRaises(RuntimeError, - gi._gi.enum_register_new_gtype_and_add, - GIMarshallingTests.Enum.__info__) - finally: - GLib.log_set_always_fatal(old_mask) - def test_enum_add_type_error(self): self.assertRaises(TypeError, gi._gi.enum_add, @@ -1648,17 +1667,6 @@ class TestNoTypeFlags(unittest.TestCase): self.assertEqual(GIMarshallingTests.NoTypeFlags.__gtype__.name, 'PyGIMarshallingTestsNoTypeFlags') - def test_flags_double_registration_error(self): - # a warning is printed for double registration and pygobject will - # also raise a RuntimeError. - old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR) - try: - self.assertRaises(RuntimeError, - gi._gi.flags_register_new_gtype_and_add, - GIMarshallingTests.NoTypeFlags.__info__) - finally: - GLib.log_set_always_fatal(old_mask) - class TestStructure(unittest.TestCase): @@ -1986,7 +1994,11 @@ class TestGObject(unittest.TestCase): GIMarshallingTests.Object.none_inout(GIMarshallingTests.SubObject(int=42)) + @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=709796 def test_object_full_inout(self): + # Using gimarshallingtests.c from GI versions > 1.38.0 will show this + # test as an "unexpected success" due to reference leak fixes in that file. + # TODO: remove the expectedFailure once PyGI relies on GI > 1.38.0. object_ = GIMarshallingTests.Object(int=42) new_object = GIMarshallingTests.Object.full_inout(object_) @@ -1994,7 +2006,7 @@ class TestGObject(unittest.TestCase): self.assertFalse(object_ is new_object) - self.assertEqual(object_.__grefcount__, 2) + self.assertEqual(object_.__grefcount__, 1) self.assertEqual(new_object.__grefcount__, 1) # FIXME: Doesn't actually return the same object. @@ -2642,6 +2654,36 @@ class TestKeywordArgs(unittest.TestCase): GIMarshallingTests.int_three_in_three_out(1, c=4, **d) self.assertEqual(d, d2) + @unittest.skipUnless(hasattr(GIMarshallingTests, 'int_one_in_utf8_two_in_one_allows_none'), + 'Requires newer GIMarshallingTests') + def test_allow_none_as_default(self): + GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3', '4') + GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3') + GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2) + GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, d='4') + + GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2]) + GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2], '2') + self.assertRaises(TypeError, + GIMarshallingTests.array_in_utf8_two_in_out_of_order, + [-1, 0, 1, 2], a='1') + self.assertRaises(TypeError, + GIMarshallingTests.array_in_utf8_two_in_out_of_order, + [-1, 0, 1, 2]) + + GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1', '2') + GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1') + GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2]) + GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], b='2') + + GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none(1, '2', '3') + self.assertRaises(TypeError, + GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none, + 1, '3') + self.assertRaises(TypeError, + GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none, + 1, c='3') + class TestPropertiesObject(unittest.TestCase): @@ -2851,6 +2893,20 @@ class TestPropertiesObject(unittest.TestCase): self.assertEqual(42, obj.props.some_int) self.assertEqual(54, obj.props.some_uchar) + def test_props_accessor_dir(self): + # Test class + props = dir(GIMarshallingTests.PropertiesObject.props) + self.assertTrue('some_float' in props) + self.assertTrue('some_double' in props) + self.assertTrue('some_variant' in props) + + # Test instance + obj = GIMarshallingTests.PropertiesObject() + props = dir(obj.props) + self.assertTrue('some_float' in props) + self.assertTrue('some_double' in props) + self.assertTrue('some_variant' in props) + class TestKeywords(unittest.TestCase): def test_method(self): @@ -2927,22 +2983,6 @@ class TestProjectVersion(unittest.TestCase): gi.check_version("3.3.5") -class TestObjectInfo(unittest.TestCase): - def test_get_abstract_with_abstract(self): - repo = gi.gi.Repository.get_default() - info = repo.find_by_name('GObject', 'TypeModule') - self.assertTrue(info.get_abstract()) - - def test_get_abstract_with_concrete(self): - repo = gi.gi.Repository.get_default() - info = repo.find_by_name('GObject', 'Object') - self.assertFalse(info.get_abstract()) - - def test_get_class_struct(self): - self.assertEqual(GObject.Object.__info__.get_class_struct(), - GObject.ObjectClass.__info__) - - class TestDeprecation(unittest.TestCase): def test_method(self): d = GLib.Date.new() diff --git a/tests/test_glib.py b/tests/test_glib.py index 3cde168..a01e83e 100644 --- a/tests/test_glib.py +++ b/tests/test_glib.py @@ -165,6 +165,27 @@ https://my.org/q?x=1&y=2 self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', 'moo'), (r, GLib.IOCondition.IN, b'b', 'moo')]) + def test_io_add_watch_with_multiple_data(self): + (r, w) = os.pipe() + call_data = [] + + def cb(fd, condition, *user_data): + call_data.append((fd, condition, os.read(fd, 1), user_data)) + return True + + # io_add_watch() takes an IOChannel, calling with an fd is deprecated + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo', 'foo') + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + ml = GLib.MainLoop() + GLib.timeout_add(10, lambda: os.write(w, b'a') and False) + GLib.timeout_add(100, ml.quit) + ml.run() + + self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', ('moo', 'foo'))]) + def test_io_add_watch_pyfile(self): call_data = [] diff --git a/tests/test_gobject.py b/tests/test_gobject.py index 57d3822..d49011f 100644 --- a/tests/test_gobject.py +++ b/tests/test_gobject.py @@ -415,6 +415,8 @@ class TestContextManagers(unittest.TestCase): self.assertEqual(self.tracking, [2]) +@unittest.skipUnless(hasattr(GObject.Binding, 'unbind'), + 'Requires newer GLib which has g_binding_unbind') class TestPropertyBindings(unittest.TestCase): class TestObject(GObject.GObject): int_prop = GObject.Property(default=0, type=int) @@ -509,8 +511,8 @@ class TestPropertyBindings(unittest.TestCase): GObject.BindingFlags.BIDIRECTIONAL, transform_to, transform_from, test_data) binding = binding # PyFlakes - binding_ref_count = sys.getrefcount(binding()) - binding_gref_count = binding().__grefcount__ + binding_ref_count = sys.getrefcount(binding) + binding_gref_count = binding.__grefcount__ self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) @@ -520,8 +522,8 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 2) self.assertEqual(self.target.int_prop, 4) - self.assertEqual(sys.getrefcount(binding()), binding_ref_count) - self.assertEqual(binding().__grefcount__, binding_gref_count) + self.assertEqual(sys.getrefcount(binding), binding_ref_count) + self.assertEqual(binding.__grefcount__, binding_gref_count) # test_data ref count increases by 2, once for each callback. self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2) @@ -530,9 +532,6 @@ class TestPropertyBindings(unittest.TestCase): # Unbind should clear out the binding and its transforms binding.unbind() - self.assertEqual(binding(), None) - del binding - gc.collect() # Setting source or target should not change the other. self.target.int_prop = 3 @@ -554,8 +553,9 @@ class TestPropertyBindings(unittest.TestCase): self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) + # unbind should clear out the bindings self reference binding.unbind() - self.assertEqual(binding(), None) + self.assertEqual(binding.__grefcount__, 1) self.source.int_prop = 10 self.assertEqual(self.source.int_prop, 10) @@ -572,7 +572,7 @@ class TestPropertyBindings(unittest.TestCase): # the act of binding and the ref incurred by using __call__ to generate # a wrapper from the weak binding ref within python. binding = self.source.bind_property('int_prop', self.target, 'int_prop') - self.assertEqual(binding().__grefcount__, 2) + self.assertEqual(binding.__grefcount__, 2) # Creating a binding does not inc refs on source and target (they are weak # on the binding object itself) @@ -581,18 +581,25 @@ class TestPropertyBindings(unittest.TestCase): # Use GObject.get_property because the "props" accessor leaks. # Note property names are canonicalized. - self.assertEqual(binding().get_property('source'), self.source) - self.assertEqual(binding().get_property('source_property'), 'int-prop') - self.assertEqual(binding().get_property('target'), self.target) - self.assertEqual(binding().get_property('target_property'), 'int-prop') - self.assertEqual(binding().get_property('flags'), GObject.BindingFlags.DEFAULT) - - # Delete reference to source or target and the binding should listen. + self.assertEqual(binding.get_property('source'), self.source) + self.assertEqual(binding.get_property('source_property'), 'int-prop') + self.assertEqual(binding.get_property('target'), self.target) + self.assertEqual(binding.get_property('target_property'), 'int-prop') + self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT) + + # Delete reference to source or target and the binding will remove its own + # "self reference". ref = self.source.weak_ref() del self.source gc.collect() self.assertEqual(ref(), None) - self.assertEqual(binding(), None) + self.assertEqual(binding.__grefcount__, 1) + + # Finally clear out the last ref held by the python wrapper + ref = binding.weak_ref() + del binding + gc.collect() + self.assertEqual(ref(), None) class TestGValue(unittest.TestCase): diff --git a/tests/test_repository.py b/tests/test_repository.py new file mode 100644 index 0000000..6fd7906 --- /dev/null +++ b/tests/test_repository.py @@ -0,0 +1,344 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2013 Simon Feltman +# +# test_repository.py: Test for the GIRepository module +# +# This library 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 2.1 of the License, or (at your option) any later version. +# +# This library 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 Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + +import unittest +import collections + +import gi._gi as GIRepository +from gi.module import repository as repo +from gi.repository import GObject +from gi.repository import GLib +from gi.repository import GIMarshallingTests + +try: + import cairo + cairo + has_cairo = True +except ImportError: + has_cairo = False + + +def find_child_info(info, getter_name, name): + getter = getattr(info, getter_name) + for child in getter(): + if child.get_name() == name: + return child + else: + raise ValueError('child info %s not found' % name) + + +class Test(unittest.TestCase): + def setUp(self): + repo.require('GObject') + repo.require('GIMarshallingTests') + + def test_arg_info(self): + func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') + args = func_info.get_arguments() + self.assertTrue(len(args), 1) + + arg = args[0] + self.assertEqual(arg.get_container(), func_info) + self.assertEqual(arg.get_direction(), GIRepository.Direction.OUT) + self.assertEqual(arg.get_name(), 'structs') + self.assertEqual(arg.get_namespace(), 'GIMarshallingTests') + self.assertEqual(arg.get_pytype_hint(), 'list') + self.assertFalse(arg.is_caller_allocates()) + self.assertFalse(arg.is_optional()) + self.assertFalse(arg.is_return_value()) + self.assertFalse(arg.may_be_null()) + self.assertEqual(arg.get_destroy(), -1) + self.assertEqual(arg.get_ownership_transfer(), GIRepository.Transfer.NOTHING) + self.assertEqual(arg.get_scope(), GIRepository.ScopeType.INVALID) + self.assertEqual(arg.get_type().get_tag(), GIRepository.TypeTag.ARRAY) + + def test_base_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + self.assertEqual(info.__name__, 'Object') + self.assertEqual(info.get_name(), 'Object') + self.assertEqual(info.__module__, 'gi.repository.GIMarshallingTests') + self.assertEqual(info.get_name_unescaped(), 'Object') + self.assertEqual(info.get_namespace(), 'GIMarshallingTests') + self.assertEqual(info.get_container(), None) + info2 = repo.find_by_name('GIMarshallingTests', 'Object') + self.assertFalse(info is info2) + self.assertEqual(info, info2) + self.assertTrue(info.equal(info2)) + + def test_object_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object')) + self.assertTrue(isinstance(info.get_methods(), collections.Iterable)) + self.assertTrue(isinstance(info.get_fields(), collections.Iterable)) + self.assertTrue(isinstance(info.get_interfaces(), collections.Iterable)) + self.assertTrue(isinstance(info.get_constants(), collections.Iterable)) + self.assertTrue(isinstance(info.get_vfuncs(), collections.Iterable)) + self.assertTrue(isinstance(info.get_properties(), collections.Iterable)) + self.assertFalse(info.get_abstract()) + self.assertEqual(info.get_class_struct(), repo.find_by_name('GIMarshallingTests', 'ObjectClass')) + self.assertEqual(info.get_type_name(), 'GIMarshallingTestsObject') + self.assertEqual(info.get_type_init(), 'gi_marshalling_tests_object_get_type') + self.assertFalse(info.get_fundamental()) + self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object')) + + def test_registered_type_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + # Call these from the class because GIObjectInfo overrides them + self.assertEqual(GIRepository.RegisteredTypeInfo.get_g_type(info), + GObject.type_from_name('GIMarshallingTestsObject')) + self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_name(info), + 'GIMarshallingTestsObject') + self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_init(info), + 'gi_marshalling_tests_object_get_type') + + @unittest.skipUnless(has_cairo, 'Regress needs cairo') + def test_fundamental_object_info(self): + repo.require('Regress') + info = repo.find_by_name('Regress', 'TestFundamentalObject') + self.assertTrue(info.get_abstract()) + self.assertTrue(info.get_fundamental()) + self.assertEqual(info.get_ref_function(), 'regress_test_fundamental_object_ref') + self.assertEqual(info.get_unref_function(), 'regress_test_fundamental_object_unref') + self.assertEqual(info.get_get_value_function(), 'regress_test_value_get_fundamental_object') + self.assertEqual(info.get_set_value_function(), 'regress_test_value_set_fundamental_object') + + def test_interface_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Interface') + self.assertTrue(isinstance(info.get_methods(), collections.Iterable)) + self.assertTrue(isinstance(info.get_vfuncs(), collections.Iterable)) + self.assertTrue(isinstance(info.get_constants(), collections.Iterable)) + self.assertTrue(isinstance(info.get_prerequisites(), collections.Iterable)) + self.assertTrue(isinstance(info.get_properties(), collections.Iterable)) + self.assertTrue(isinstance(info.get_signals(), collections.Iterable)) + + method = info.find_method('test_int8_in') + vfunc = info.find_vfunc('test_int8_in') + self.assertEqual(method.get_name(), 'test_int8_in') + self.assertEqual(vfunc.get_invoker(), method) + self.assertEqual(method.get_vfunc(), vfunc) + + iface = info.get_iface_struct() + self.assertEqual(iface, repo.find_by_name('GIMarshallingTests', 'InterfaceIface')) + + def test_struct_info(self): + info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface') + self.assertTrue(isinstance(info, GIRepository.StructInfo)) + self.assertTrue(isinstance(info.get_fields(), collections.Iterable)) + self.assertTrue(isinstance(info.get_methods(), collections.Iterable)) + self.assertTrue(isinstance(info.get_size(), int)) + self.assertTrue(isinstance(info.get_alignment(), int)) + self.assertTrue(info.is_gtype_struct()) + self.assertFalse(info.is_foreign()) + + def test_enum_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Enum') + self.assertTrue(isinstance(info, GIRepository.EnumInfo)) + self.assertTrue(isinstance(info.get_values(), collections.Iterable)) + self.assertTrue(isinstance(info.get_methods(), collections.Iterable)) + self.assertFalse(info.is_flags()) + self.assertTrue(info.get_storage_type() > 0) # might be platform dependent + + def test_union_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Union') + self.assertTrue(isinstance(info, GIRepository.UnionInfo)) + self.assertTrue(isinstance(info.get_fields(), collections.Iterable)) + self.assertTrue(isinstance(info.get_methods(), collections.Iterable)) + + def test_type_info(self): + func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') + arg_info, = func_info.get_arguments() + type_info = arg_info.get_type() + + self.assertTrue(type_info.is_pointer()) + self.assertEqual(type_info.get_tag(), GIRepository.TypeTag.ARRAY) + self.assertEqual(type_info.get_tag_as_string(), 'array') + self.assertEqual(type_info.get_param_type(0).get_tag(), + GIRepository.TypeTag.INTERFACE) + self.assertEqual(type_info.get_param_type(0).get_interface(), + repo.find_by_name('GIMarshallingTests', 'SimpleStruct')) + self.assertEqual(type_info.get_interface(), None) + self.assertEqual(type_info.get_array_length(), -1) + self.assertEqual(type_info.get_array_fixed_size(), 2) + self.assertFalse(type_info.is_zero_terminated()) + self.assertEqual(type_info.get_array_type(), GIRepository.ArrayType.C) + + def test_field_info(self): + info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface') + field = find_child_info(info, 'get_fields', 'test_int8_in') + self.assertEqual(field.get_name(), 'test_int8_in') + self.assertTrue(field.get_flags() & GIRepository.FieldInfoFlags.IS_READABLE) + self.assertFalse(field.get_flags() & GIRepository.FieldInfoFlags.IS_WRITABLE) + self.assertEqual(field.get_type().get_tag(), GIRepository.TypeTag.INTERFACE) + + # don't test actual values because that might fail with architecture differences + self.assertTrue(isinstance(field.get_size(), int)) + self.assertTrue(isinstance(field.get_offset(), int)) + + def test_property_info(self): + info = repo.find_by_name('GIMarshallingTests', 'PropertiesObject') + prop = find_child_info(info, 'get_properties', 'some-object') + + flags = GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT + self.assertEqual(prop.get_flags(), flags) + self.assertEqual(prop.get_type().get_tag(), GIRepository.TypeTag.INTERFACE) + self.assertEqual(prop.get_type().get_interface(), + repo.find_by_name('GObject', 'Object')) + self.assertEqual(prop.get_ownership_transfer(), GIRepository.Transfer.NOTHING) + + def test_callable_info(self): + func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') + self.assertTrue(hasattr(func_info, 'invoke')) + self.assertTrue(isinstance(func_info.get_arguments(), collections.Iterable)) + self.assertEqual(func_info.get_caller_owns(), GIRepository.Transfer.NOTHING) + self.assertFalse(func_info.may_return_null()) + self.assertEqual(func_info.get_return_type().get_tag(), GIRepository.TypeTag.VOID) + self.assertRaises(AttributeError, func_info.get_return_attribute, '_not_an_attr') + + @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=709462 + @unittest.skipUnless(has_cairo, 'Regress needs cairo') + def test_signal_info(self): + repo.require('Regress') + info = repo.find_by_name('Regress', 'TestObj') + sig_info = find_child_info(info, 'get_signals', 'test') + + sig_flags = GObject.SignalFlags.RUN_LAST | \ + GObject.SignalFlags.NO_RECURSE | GObject.SignalFlags.NO_HOOKS + + self.assertTrue(sig_info is not None) + self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo)) + self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo)) + self.assertEqual(sig_info.get_name(), 'test') + self.assertEqual(sig_info.get_class_closure(), None) + self.assertFalse(sig_info.true_stops_emit()) + self.assertEqual(sig_info.get_flags(), sig_flags) + + @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=709462 + @unittest.skipUnless(has_cairo, 'Regress needs cairo') + def test_notify_signal_info_with_obj(self): + repo.require('Regress') + info = repo.find_by_name('Regress', 'TestObj') + sig_info = find_child_info(info, 'get_signals', 'sig-with-array-prop') + + sig_flags = GObject.SignalFlags.RUN_LAST + + self.assertTrue(sig_info is not None) + self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo)) + self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo)) + self.assertEqual(sig_info.get_name(), 'sig-with-array-prop') + self.assertEqual(sig_info.get_class_closure(), None) + self.assertFalse(sig_info.true_stops_emit()) + self.assertEqual(sig_info.get_flags(), sig_flags) + + def test_object_constructor(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + method = find_child_info(info, 'get_methods', 'new') + + self.assertTrue(isinstance(method, GIRepository.CallableInfo)) + self.assertTrue(isinstance(method, GIRepository.FunctionInfo)) + self.assertTrue(method in info.get_methods()) + self.assertEqual(method.get_name(), 'new') + self.assertFalse(method.is_method()) + self.assertTrue(method.is_constructor()) + self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_new') + + flags = method.get_flags() + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_METHOD) + self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS) + + def test_method_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + method = find_child_info(info, 'get_methods', 'vfunc_return_value_only') + + self.assertTrue(isinstance(method, GIRepository.CallableInfo)) + self.assertTrue(isinstance(method, GIRepository.FunctionInfo)) + self.assertTrue(method in info.get_methods()) + self.assertEqual(method.get_name(), 'vfunc_return_value_only') + self.assertFalse(method.is_constructor()) + self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_vfunc_return_value_only') + self.assertTrue(method.is_method()) + + flags = method.get_flags() + self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_METHOD) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC) + self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS) + + def test_vfunc_info(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + invoker = find_child_info(info, 'get_methods', 'vfunc_return_value_only') + vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_return_value_only') + + self.assertTrue(isinstance(vfunc, GIRepository.CallableInfo)) + self.assertTrue(isinstance(vfunc, GIRepository.VFuncInfo)) + self.assertEqual(vfunc.get_name(), 'vfunc_return_value_only') + self.assertEqual(vfunc.get_invoker(), invoker) + self.assertEqual(invoker, info.find_method('vfunc_return_value_only')) + self.assertEqual(vfunc.get_flags(), 0) + self.assertEqual(vfunc.get_offset(), 0xFFFF) # unknown offset + self.assertEqual(vfunc.get_signal(), None) + + def test_flags_double_registration_error(self): + # a warning is printed for double registration and pygobject will + # also raise a RuntimeError. + GIMarshallingTests.NoTypeFlags # cause flags registration + info = repo.find_by_name('GIMarshallingTests', 'NoTypeFlags') + old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR) + try: + self.assertRaises(RuntimeError, + GIRepository.flags_register_new_gtype_and_add, + info) + finally: + GLib.log_set_always_fatal(old_mask) + + def test_enum_double_registration_error(self): + # a warning is printed for double registration and pygobject will + # also raise a RuntimeError. + GIMarshallingTests.Enum # cause enum registration + info = repo.find_by_name('GIMarshallingTests', 'Enum') + old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR) + try: + self.assertRaises(RuntimeError, + GIRepository.enum_register_new_gtype_and_add, + info) + finally: + GLib.log_set_always_fatal(old_mask) + + def test_enums(self): + self.assertTrue(hasattr(GIRepository, 'Direction')) + self.assertTrue(hasattr(GIRepository, 'Transfer')) + self.assertTrue(hasattr(GIRepository, 'ArrayType')) + self.assertTrue(hasattr(GIRepository, 'ScopeType')) + self.assertTrue(hasattr(GIRepository, 'VFuncInfoFlags')) + self.assertTrue(hasattr(GIRepository, 'FieldInfoFlags')) + self.assertTrue(hasattr(GIRepository, 'FunctionInfoFlags')) + self.assertTrue(hasattr(GIRepository, 'TypeTag')) + self.assertTrue(hasattr(GIRepository, 'InfoType')) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_signal.py b/tests/test_signal.py index ec13896..e90264a 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -327,9 +327,6 @@ class TestMatching(unittest.TestCase): self.assertEqual(obj.status, 2) def test_signal_handler_find(self): - def dummy(*args): - "Hack to work around: " - def foo(obj): obj.status += 1 @@ -340,7 +337,7 @@ class TestMatching(unittest.TestCase): found_id = GObject.signal_handler_find(obj, GObject.SignalMatchType.ID, signal_id=signal_id, detail=detail, - closure=None, func=dummy, data=dummy) + closure=None, func=0, data=0) self.assertEqual(handler_id, found_id) diff --git a/tests/test_source.py b/tests/test_source.py index d0e28e4..6f69927 100644 --- a/tests/test_source.py +++ b/tests/test_source.py @@ -128,13 +128,19 @@ class TestSource(unittest.TestCase): def test_remove(self): s = GLib.idle_add(dir) self.assertEqual(GLib.source_remove(s), True) - # s is now removed, should fail now - self.assertEqual(GLib.source_remove(s), False) - # accepts large source IDs (they are unsigned) - self.assertEqual(GLib.source_remove(GObject.G_MAXINT32), False) - self.assertEqual(GLib.source_remove(GObject.G_MAXINT32 + 1), False) - self.assertEqual(GLib.source_remove(GObject.G_MAXUINT32), False) + # Removing sources not found cause critical + old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR) + try: + # s is now removed, should fail now + self.assertEqual(GLib.source_remove(s), False) + + # accepts large source IDs (they are unsigned) + self.assertEqual(GLib.source_remove(GObject.G_MAXINT32), False) + self.assertEqual(GLib.source_remove(GObject.G_MAXINT32 + 1), False) + self.assertEqual(GLib.source_remove(GObject.G_MAXUINT32), False) + finally: + GLib.log_set_always_fatal(old_mask) def test_recurse_property(self): s = GLib.Idle() diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py index ef4c35e..6da8ad2 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -12,68 +12,58 @@ from gi import PyGIDeprecationWarning class TestProcess(unittest.TestCase): def test_deprecated_child_watch_no_data(self): - def cb(pid, status): - self.status = status - self.loop.quit() - - self.status = None - self.loop = GLib.MainLoop() - argv = [sys.executable, '-c', 'import sys'] - pid, stdin, stdout, stderr = GLib.spawn_async( - argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) - pid.close() + cb = lambda pid, status: None + pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') - GLib.child_watch_add(pid, cb) + res = GLib._child_watch_add_get_args(pid, cb) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) - self.loop.run() - self.assertEqual(self.status, 0) - def test_deprecated_child_watch_data_priority(self): - def cb(pid, status, data): - self.data = data - self.status = status - self.loop.quit() + self.assertEqual(len(res), 4) + self.assertEqual(res[0], GLib.PRIORITY_DEFAULT) + self.assertEqual(res[1], pid) + self.assertTrue(callable(cb)) + self.assertSequenceEqual(res[3], []) - self.status = None - self.data = None - self.loop = GLib.MainLoop() - argv = [sys.executable, '-c', 'import sys'] - pid, stdin, stdout, stderr = GLib.spawn_async( - argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) - pid.close() + def test_deprecated_child_watch_data_priority(self): + cb = lambda pid, status: None + pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') - id = GLib.child_watch_add(pid, cb, 12345, GLib.PRIORITY_HIGH) + res = GLib._child_watch_add_get_args(pid, cb, 12345, GLib.PRIORITY_HIGH) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) - self.assertEqual(self.loop.get_context().find_source_by_id(id).priority, - GLib.PRIORITY_HIGH) - self.loop.run() - self.assertEqual(self.data, 12345) - self.assertEqual(self.status, 0) - def test_deprecated_child_watch_data_priority_kwargs(self): - def cb(pid, status, data): - self.data = data - self.status = status - self.loop.quit() + self.assertEqual(len(res), 4) + self.assertEqual(res[0], GLib.PRIORITY_HIGH) + self.assertEqual(res[1], pid) + self.assertEqual(res[2], cb) + self.assertSequenceEqual(res[3], [12345]) - self.status = None - self.data = None - self.loop = GLib.MainLoop() - argv = [sys.executable, '-c', 'import sys'] - pid, stdin, stdout, stderr = GLib.spawn_async( - argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) - pid.close() + def test_deprecated_child_watch_data_priority_kwargs(self): + cb = lambda pid, status: None + pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') - id = GLib.child_watch_add(pid, cb, priority=GLib.PRIORITY_HIGH, data=12345) + res = GLib._child_watch_add_get_args(pid, cb, priority=GLib.PRIORITY_HIGH, data=12345) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) - self.assertEqual(self.loop.get_context().find_source_by_id(id).priority, - GLib.PRIORITY_HIGH) - self.loop.run() - self.assertEqual(self.data, 12345) - self.assertEqual(self.status, 0) + + self.assertEqual(len(res), 4) + self.assertEqual(res[0], GLib.PRIORITY_HIGH) + self.assertEqual(res[1], pid) + self.assertEqual(res[2], cb) + self.assertSequenceEqual(res[3], [12345]) + + @unittest.expectedFailure # using keyword args is fully supported by PyGObject machinery + def test_child_watch_all_kwargs(self): + cb = lambda pid, status: None + pid = object() + + res = GLib._child_watch_add_get_args(priority=GLib.PRIORITY_HIGH, pid=pid, function=cb, data=12345) + self.assertEqual(len(res), 4) + self.assertEqual(res[0], GLib.PRIORITY_HIGH) + self.assertEqual(res[1], pid) + self.assertEqual(res[2], cb) + self.assertSequenceEqual(res[3], [12345]) def test_child_watch_no_data(self): def cb(pid, status): -- 2.34.1