From f6c4d1d6a75fc86393b97d8957b10f5192379cd6 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 30 Oct 2018 10:27:26 +0900 Subject: [PATCH] Imported Upstream version 3.13.2 --- ChangeLog | 522 +++++++++++++++++++++++++++++++++++++ Makefile.am | 3 +- Makefile.in | 3 +- NEWS | 21 ++ PKG-INFO | 4 +- configure | 42 +-- configure.ac | 4 +- gi/Makefile.am | 3 + gi/Makefile.in | 6 +- gi/__init__.py | 28 ++ gi/_error.py | 54 ++++ gi/_option.py | 5 +- gi/gimodule.c | 17 +- gi/glibmodule.c | 19 -- gi/gobjectmodule.c | 54 +--- gi/overrides/GIMarshallingTests.py | 4 +- gi/overrides/GLib.py | 29 ++- gi/overrides/Gio.py | 4 +- gi/overrides/Gtk.py | 38 ++- gi/pygboxed.c | 21 +- gi/pygenum.c | 1 + gi/pygflags.c | 1 + gi/pygi-argument.c | 40 +-- gi/pygi-array.c | 2 +- gi/pygi-boxed.c | 6 +- gi/pygi-cache.c | 4 +- gi/pygi-error.c | 205 ++++++++++++++- gi/pygi-error.h | 21 +- gi/pygi-foreign-api.h | 85 ++++++ gi/pygi-foreign-cairo.c | 192 +++++++++++++- gi/pygi-foreign.c | 82 ++++-- gi/pygi-foreign.h | 20 +- gi/pygi-info.c | 14 +- gi/pygi-invoke.c | 5 +- gi/pygi-property.c | 8 +- gi/pygi-property.h | 14 +- gi/pygi-signal-closure.c | 12 +- gi/pygi-signal-closure.h | 15 +- gi/pygi-struct-marshal.c | 267 ++++++++++--------- gi/pygi-struct-marshal.h | 56 ++-- gi/pygi-struct.c | 6 +- gi/pygi-type.c | 4 +- gi/pygi-type.h | 3 +- gi/pygi-value.c | 2 +- gi/pygi.h | 107 -------- gi/pyglib-private.h | 1 - gi/pyglib.c | 199 -------------- gi/pyglib.h | 5 - gi/pygobject-private.h | 3 - gi/pygobject.c | 3 + gi/pygobject.h | 13 +- gi/pygoptioncontext.c | 3 +- gi/pygoptiongroup.c | 3 +- gi/pygparamspec.c | 22 +- gi/pygpointer.c | 15 +- gi/pygspawn.c | 3 +- gi/pygtype.c | 5 +- gi/types.py | 15 +- pygtkcompat/pygtkcompat.py | 8 +- tests/Makefile.am | 3 + tests/Makefile.in | 3 + tests/test_cairo.py | 141 ++++++++++ tests/test_error.py | 116 +++++++++ tests/test_everything.py | 44 +--- tests/test_gi.py | 59 +---- tests/test_gio.py | 6 +- tests/test_iochannel.py | 2 +- tests/test_option.py | 2 +- tests/test_overrides_gtk.py | 92 +++++++ tests/test_repository.py | 25 +- tests/test_signal.py | 28 +- tests/test_typeclass.py | 80 ++++++ 72 files changed, 2115 insertions(+), 837 deletions(-) create mode 100644 gi/_error.py create mode 100644 gi/pygi-foreign-api.h create mode 100644 tests/test_cairo.py create mode 100644 tests/test_error.py create mode 100644 tests/test_typeclass.py diff --git a/ChangeLog b/ChangeLog index fc22733..1998f37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,525 @@ +commit 32542a4ba24d413fb6e0d509bff05f4ac3f642a1 +Author: Simon Feltman +Date: Mon May 26 03:01:13 2014 -0700 + + Python 3.4 make check fixes + + Bump GI required version to 1.39.0. This is needed to get rid of + expectedFailures which pass when built with 1.39.0 (unexpected + successes + fail unittesting in Python 3.4). + Silence deprecation warning when using imp.reload. + + https://bugzilla.gnome.org/show_bug.cgi?id=730411 + + configure.ac | 2 +- + pygtkcompat/pygtkcompat.py | 4 +++- + tests/test_gi.py | 1 - + tests/test_repository.py | 2 -- + 4 files changed, 4 insertions(+), 5 deletions(-) + +commit dbdc662b5743bb54fcc3621db775a6e948ec360c +Author: Simon Feltman +Date: Mon May 26 01:53:14 2014 -0700 + + tests: Don't use deprecated positional argument for Gio.Settings + schema + + tests/test_gio.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +commit d0b23f08eebd4377f066a4483900fe6d09e3795e +Author: Simon Feltman +Date: Sun May 25 23:03:35 2014 -0700 + + overrides: Add Gtk.Container.child_get/set overrides + + Add overrides for child_get and child_set to Gtk.Container since these + are not introspectable methods. + + https://bugzilla.gnome.org/show_bug.cgi?id=685076 + + gi/overrides/Gtk.py | 10 ++++++++++ + tests/test_overrides_gtk.py | 16 ++++++++++++++++ + 2 files changed, 26 insertions(+) + +commit 45a5fb2b0d6c7f46d355c83c73d829532e5a72ce +Author: Simon Feltman +Date: Sun May 25 22:07:07 2014 -0700 + + overrides: Make value argument to Widget.style_get_property optional + + Override Gtk.Widget.style_get_property to optionally accept the + "value" + argument. If "value" is not supplied, the override will locate + the child + property value type and create the GValue. Additionally return + the resulting + GValue converted to a native Python value. + + https://bugzilla.gnome.org/show_bug.cgi?id=685076 + + gi/overrides/Gtk.py | 11 +++++++++++ + tests/test_overrides_gtk.py | 29 +++++++++++++++++++++++++++++ + 2 files changed, 40 insertions(+) + +commit 6f5a9a37bcdec5074332b1066396321d40b15d99 +Author: Simon Feltman +Date: Sun May 25 21:08:47 2014 -0700 + + overrides: Make value argument to Container.child_get_property + optional + + Override Gtk.Container.child_get_property to optionally accept the + "value" + argument. If "value" is not supplied, the override will locate + the child + property value type and create the GValue. Additionally return + the resulting + GValue converted to a native Python value. + + https://bugzilla.gnome.org/show_bug.cgi?id=685076 + + gi/overrides/Gtk.py | 11 +++++++++++ + tests/test_overrides_gtk.py | 47 + +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +commit bf84915f89fd5fd502b4fb162eef7bc0a48c8783 +Author: Johan Dahlin +Date: Mon Oct 1 06:42:24 2012 -0700 + + Add GTypeClass methods as Python GObject class methods + + Take all the methods from an objects type classs and add them + as class methods. For instance, GObject.ObjectClass.list_properties + is available as GObject.Object.list_properties(). + + Co-Authored-By: Simon Feltman + + https://bugzilla.gnome.org/show_bug.cgi?id=685218 + + gi/types.py | 13 +++++++++++++ + tests/test_typeclass.py | 13 +++++++++++++ + 2 files changed, 26 insertions(+) + +commit 778d05c93e079ba207a250b754bda9377cb47457 +Author: Simon Feltman +Date: Sun May 25 19:05:56 2014 -0700 + + Add marshalling coercion for Python classes and instances to + GTypeClass + + Automatically marshal Python GObject classes and instances to + GTypeClass + structs (GObjectClass). This allows usage of the GTypeClass methods by + passing a Python GObject class or instance to the GTypeClass method. + This is needed to support usage of GTypeClass methods since we don't + manually bind GTypeClasses and they are not very well supported with + introspection. + + https://bugzilla.gnome.org/show_bug.cgi?id=685218 + + gi/pygi-struct-marshal.c | 54 ++++++++++++++++++++++++++++++++++---- + tests/Makefile.am | 1 + + tests/test_typeclass.py | 67 + ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 117 insertions(+), 5 deletions(-) + +commit 1e606287e1244cba45e3bb174d27f1c01e4f9577 +Author: Simon Feltman +Date: Sun May 25 02:00:00 2014 -0700 + + Cleanup struct marshalling function names + + Use a consistent naming scheme for struct marshalling cache related + functions. This removes prefixed underscores from function names + as well as redundant wording. + + To ignore this commit with git blame use: + git blame ^ -- gi/pygi-struct-marshal.c + + https://bugzilla.gnome.org/show_bug.cgi?id=685218 + + gi/pygi-argument.c | 34 ++++---- + gi/pygi-array.c | 2 +- + gi/pygi-struct-marshal.c | 221 + ++++++++++++++++++++--------------------------- + gi/pygi-struct-marshal.h | 56 ++++++------ + 4 files changed, 142 insertions(+), 171 deletions(-) + +commit bbbfa967d06eb8fdef6d6ebe705cc8df2869ddf3 +Author: Simon Feltman +Date: Fri May 16 15:08:35 2014 -0700 + + Use accessors for getting and setting PyGParamSpec pointers + + Add pyg_param_spec_get and pyg_param_spec_set macros for getting and + setting the GParamSpec pointer field held by the Python wrapper. This + is preliminary cleanup work for supporting fundamental types. + + https://bugzilla.gnome.org/show_bug.cgi?id=631901 + + gi/pygi-value.c | 2 +- + gi/pygobject.h | 9 +++++++-- + gi/pygparamspec.c | 22 +++++++++++----------- + 3 files changed, 19 insertions(+), 14 deletions(-) + +commit b49179ba3b39576c0c8fe8586b7091dbbaef8046 +Author: Simon Feltman +Date: Fri May 16 14:50:57 2014 -0700 + + Use accessors for getting and setting PyGPointer fields + + Add pyg_pointer_get_ptr and pyg_pointer_set_ptr macros for getting and + setting the pointer field. This is preliminary cleanup work for + supporting + fundamental types. + + https://bugzilla.gnome.org/show_bug.cgi?id=631901 + + gi/gimodule.c | 2 +- + gi/pygi-struct.c | 6 +++--- + gi/pygobject.h | 2 ++ + gi/pygpointer.c | 14 +++++++------- + 4 files changed, 13 insertions(+), 11 deletions(-) + +commit 92fe52243d819ffe91597744a6a1c2362a295bce +Author: Simon Feltman +Date: Fri May 16 14:19:47 2014 -0700 + + Use accessors for getting and setting PyGBoxed pointers + + Add pyg_boxed_get_ptr and pyg_boxed_set_ptr macros for getting + and setting + the boxed pointer field. This is preliminary cleanup work for + supporting + fundamental types. + + https://bugzilla.gnome.org/show_bug.cgi?id=631901 + + gi/pygboxed.c | 20 ++++++++++---------- + gi/pygi-boxed.c | 6 +++--- + gi/pygobject.h | 2 ++ + gi/pygtype.c | 3 ++- + 4 files changed, 17 insertions(+), 14 deletions(-) + +commit 0a4f13a571cb9bd110f435f8b23ed942e3b007b0 +Author: Simon Feltman +Date: Sun May 11 16:04:55 2014 -0700 + + tests: Use assertRaises as a context manager for GError test + + Simplify tests/test_error.py:TestMarshalling.test_exception so that + it no longer needs to pull exception information out of sys.exc_info. + + tests/test_error.py | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +commit bc7b0b69f651a118a053106fcae2d7c0f2173430 +Author: Andrew Grigorev +Date: Sun May 11 23:54:46 2014 +0400 + + Replace direct parent class call by super() + + Super works, it just needs the correct class. + + https://bugzilla.gnome.org/show_bug.cgi?id=729970 + + demos/gtk-demo/gtk-demo.py | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +commit de827d00762f2a741f90bc38f8b55518593f4509 +Author: Simon Feltman +Date: Sun Mar 23 01:59:00 2014 -0700 + + Add cairo marshaling support for non-introspected signals + + Add link dependency of cairo-gobject to _gi_cairo_la needed for + retrieving + the GTypes of cairo classes. + Add GValue marshalers for cairo Context, Surface, FontFace, + ScaledFont, + and Pattern classes. + + https://bugzilla.gnome.org/show_bug.cgi?id=694604 + + gi/Makefile.am | 2 + + gi/pygi-foreign-cairo.c | 186 + ++++++++++++++++++++++++++++++++++++++++++++++++ + gi/pygi-type.h | 1 + + gi/pygtype.c | 2 + + tests/test_cairo.py | 65 +++++++++++++++++ + 5 files changed, 256 insertions(+) + +commit 22a952ec532cc83c8227861a7d5bfa2957608c3f +Author: Simon Feltman +Date: Mon May 5 19:37:18 2014 -0700 + + [New API] Add gi.require_foreign + + Add gi.require_foreign(namespace, symbol=None) API for determining + if a foreign marshaling module is available. This can be used in an + applications import statement block to verify the existence of a + specific foreign marshaling module (cairo). + Additionally it forces loading of the foreign marshaling module as + well as the GI repository module. This allows non-introspected signal + closures to correctly marshal their arguments (bug 694604). + + https://bugzilla.gnome.org/show_bug.cgi?id=707735 + + gi/__init__.py | 28 +++++++++++++++++++++++++ + gi/gimodule.c | 2 ++ + gi/pygi-foreign.c | 60 + ++++++++++++++++++++++++++++++++++++++++++++++------- + gi/pygi-foreign.h | 4 ++++ + tests/test_cairo.py | 9 ++++++++ + 5 files changed, 95 insertions(+), 8 deletions(-) + +commit 4ee91a4cd0018d069c7aaf66d83e2f8235f2262a +Author: Simon Feltman +Date: Mon May 5 19:48:06 2014 -0700 + + tests: Move cairo tests into test_cairo.py + + Move cairo related tests from test_everything.py into test_cairo.py + + https://bugzilla.gnome.org/show_bug.cgi?id=694604 + + tests/Makefile.am | 1 + + tests/test_cairo.py | 67 + ++++++++++++++++++++++++++++++++++++++++++++++++ + tests/test_everything.py | 43 +------------------------------ + 3 files changed, 69 insertions(+), 42 deletions(-) + +commit 31ecd935564984068e6646676392122bdc03e42e +Author: Simon Feltman +Date: Mon May 5 19:42:59 2014 -0700 + + Initialize the foreign API at PyGI load time + + Initialize the foreign struct list at gi._gi module load time. This + ensures + we always have a valid (non-null) list of foreign marshalers outside + of the + context of marshaling. + + https://bugzilla.gnome.org/show_bug.cgi?id=694604 + + gi/gimodule.c | 3 ++- + gi/pygi-foreign.c | 12 ++++++++---- + gi/pygi-foreign.h | 2 ++ + 3 files changed, 12 insertions(+), 5 deletions(-) + +commit def47144b63a1492ebf47a4eadb535f45253ff3a +Author: Simon Feltman +Date: Sat Mar 22 14:13:01 2014 -0700 + + Move pygi foreign API into pygi-foreign-api.h + + Move limited set of APIs necessary for registering foreign marshalers + into + pygi-foreign-api.h. Remove "_real" from internally used APIs and + add necessary + includes to the rest of pygobject for calling directly (instead of + going through + the PyCapsule API within PyGI itself). + This is needed to avoid compilation errors when including pygobject.h + in + foreign marshaling plugins which conflicts with pygobject-private.h. + + https://bugzilla.gnome.org/show_bug.cgi?id=694604 + + gi/Makefile.am | 1 + + gi/gimodule.c | 6 +-- + gi/pygboxed.c | 1 + + gi/pygenum.c | 1 + + gi/pygflags.c | 1 + + gi/pygi-foreign-api.h | 85 +++++++++++++++++++++++++++++++++++++ + gi/pygi-foreign-cairo.c | 8 ++-- + gi/pygi-foreign.c | 10 ++--- + gi/pygi-foreign.h | 14 +++---- + gi/pygi-property.c | 8 ++-- + gi/pygi-property.h | 14 ++++--- + gi/pygi-signal-closure.c | 12 +++--- + gi/pygi-signal-closure.h | 15 +++---- + gi/pygi-type.c | 4 +- + gi/pygi-type.h | 2 +- + gi/pygi.h | 107 + ----------------------------------------------- + gi/pygobject.c | 3 ++ + gi/pygpointer.c | 1 + + 18 files changed, 139 insertions(+), 154 deletions(-) + +commit 4c2e6914bf0277ebc3a6a4426f33a1b378a04b00 +Author: Simon Feltman +Date: Sun May 4 23:19:30 2014 -0700 + + Clobber GLib.Error with custom implementation + + Clobber the introspection GLib.Error class with the custom Python + implementation found in gi._error.GError. Update references to + GLib.GError + to use GLib.Error. + + https://bugzilla.gnome.org/show_bug.cgi?id=712519 + + gi/_error.py | 3 ++- + gi/overrides/GLib.py | 9 ++++++--- + gi/pygi-error.c | 10 +++++----- + tests/test_error.py | 24 ++++++++++++------------ + 4 files changed, 25 insertions(+), 21 deletions(-) + +commit f80f5ec434ed868ab1f35d6a81537384e753b09d +Author: Simon Feltman +Date: Sun May 4 23:43:50 2014 -0700 + + Simplify pygi_error_marshal to use GError initializer arguments + + https://bugzilla.gnome.org/show_bug.cgi?id=712519 + + gi/pygi-error.c | 25 ++++++------------------- + 1 file changed, 6 insertions(+), 19 deletions(-) + +commit 3083daf420ac1900bb20604c22fd61e5187b4ae8 +Author: Simon Feltman +Date: Sun May 4 04:13:46 2014 -0700 + + Add Python implementation of GError + + Add internally used gi/_error.py module as a basis for implementing + a unified GError between introspection and static bindings. Patch + Python + implementations of GError.matches and GError.new_literal in the GLib + overrides + + https://bugzilla.gnome.org/show_bug.cgi?id=712519 + + Makefile.am | 3 ++- + gi/_error.py | 53 + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + gi/_option.py | 3 ++- + gi/overrides/GLib.py | 25 ++++++++++++++++++++++++- + gi/pygi-error.c | 18 +++++++----------- + tests/test_error.py | 37 ++++++++++++++++++++++++++++++++++++ + 6 files changed, 125 insertions(+), 14 deletions(-) + +commit 664bfa6fdf2196a0d1449baaca62a9a496121f67 +Author: Simon Feltman +Date: Sun May 4 23:14:27 2014 -0700 + + tests: Move GError tests into test_error.py + + https://bugzilla.gnome.org/show_bug.cgi?id=712519 + + tests/Makefile.am | 1 + + tests/test_error.py | 81 + +++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/test_gi.py | 49 -------------------------------- + 3 files changed, 82 insertions(+), 49 deletions(-) + +commit 649895d83a90cd3a370da215a6f98a606b987419 +Author: Simon Feltman +Date: Sun May 4 00:18:41 2014 -0700 + + Consolidate GError related code into pygi-error + + Rename all pyglib_error_* functions to pygi_error_* and move them into + pygi-error.[h|c]. + Register GError as part of the gi._gi module instead of gi._gi._glib. + Update all code to use new naming. + + https://bugzilla.gnome.org/show_bug.cgi?id=712519 + + gi/_option.py | 6 +- + gi/gimodule.c | 4 +- + gi/glibmodule.c | 19 ----- + gi/gobjectmodule.c | 54 +----------- + gi/overrides/GLib.py | 3 +- + gi/pygi-argument.c | 6 +- + gi/pygi-cache.c | 4 +- + gi/pygi-error.c | 222 + ++++++++++++++++++++++++++++++++++++++++++++++++- + gi/pygi-error.h | 21 ++++- + gi/pygi-invoke.c | 5 +- + gi/pyglib-private.h | 1 - + gi/pyglib.c | 199 -------------------------------------------- + gi/pyglib.h | 5 -- + gi/pygobject-private.h | 3 - + gi/pygoptioncontext.c | 3 +- + gi/pygoptiongroup.c | 3 +- + gi/pygspawn.c | 3 +- + 17 files changed, 262 insertions(+), 299 deletions(-) + +commit 9080215e862a73ddcce16476f4dc4492a88dd3f2 +Author: Simon Feltman +Date: Sat May 3 22:56:49 2014 -0700 + + Add gi.CallableInfo.can_throw_gerror() + + Add static binding for g_callable_info_can_throw_gerror. + + gi/pygi-info.c | 10 ++++++++++ + tests/test_repository.py | 16 ++++++++++++++++ + 2 files changed, 26 insertions(+) + +commit f129e78d579b7897cb86111c524d87b5b12019ad +Author: Simon Feltman +Date: Sat May 3 22:56:03 2014 -0700 + + Derive PyCallbackInfo from PyCallableInfo + + Update the static GI bindings for PyGICallbackInfo to derive + from PyGICallableInfo. This makes all the gi.CallableInfo methods + available to gi.CallbackInfo for use from Python. + + gi/pygi-info.c | 4 ++-- + tests/test_repository.py | 7 +++++++ + 2 files changed, 9 insertions(+), 2 deletions(-) + +commit 833f96807037e85445ac103d6fb6ad9c4fab65e4 +Author: Simon Feltman +Date: Fri May 2 21:36:25 2014 -0700 + + PEP8 fixes + + Use infix 'not' instead of prefixed. + Don't use double comments (##). + Use space between comment and text. + Un-comment tests that now work. + Move broken (and won't fix) implicit int64 signal tests into + a new skipped test function. + + gi/overrides/GIMarshallingTests.py | 4 ++-- + gi/overrides/Gio.py | 4 ++-- + gi/overrides/Gtk.py | 6 +++--- + gi/types.py | 2 +- + pygtkcompat/pygtkcompat.py | 4 ++-- + tests/test_everything.py | 1 - + tests/test_gi.py | 9 +++------ + tests/test_iochannel.py | 2 +- + tests/test_option.py | 2 +- + tests/test_signal.py | 28 +++++++++++++--------------- + 10 files changed, 28 insertions(+), 34 deletions(-) + +commit 07af141dd8dcac551cb2e962f6bf338b3485006b +Author: Simon Feltman +Date: Mon Apr 28 14:06:30 2014 -0700 + + configure.ac: post release version bump to 3.13.2 + + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit ba652c1fd9dbef6d3ff57e39b400ea827374a95e +Author: Simon Feltman +Date: Mon Apr 28 14:00:59 2014 -0700 + + release 3.13.1 + + NEWS | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + commit 3a2bfc8bf01fcae386355bc3652780e198e54d49 Author: Christoph Reiter Date: Mon Apr 14 23:33:52 2014 +0200 diff --git a/Makefile.am b/Makefile.am index 208ed13..968b6c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,7 +65,8 @@ nobase_pyexec_PYTHON = \ gi/_constants.py \ gi/_propertyhelper.py \ gi/_signalhelper.py \ - gi/_option.py + gi/_option.py \ + gi/_error.py # if we build in a separate tree, we need to symlink the *.py files from the # source tree; Python does not accept the extensions and modules in different diff --git a/Makefile.in b/Makefile.in index ff37526..dba6bc8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -463,7 +463,8 @@ nobase_pyexec_PYTHON = \ gi/_constants.py \ gi/_propertyhelper.py \ gi/_signalhelper.py \ - gi/_option.py + gi/_option.py \ + gi/_error.py # pkg-config files diff --git a/NEWS b/NEWS index a7eef2c..81a9090 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,24 @@ +3.13.2 26-May-2014 + - Python 3.4 make check fixes (Simon Feltman) (#730411) + - overrides: Add Gtk.Container.child_get/set overrides (Simon Feltman) + (#685076) + - overrides: Make value argument to Widget.style_get_property optional + (Simon Feltman) (#685076) + - overrides: Make value argument to Container.child_get_property optional + (Simon Feltman) (#685076) + - Add GTypeClass methods as Python GObject class methods + (Johan Dahlin) (#685218) + - Add marshalling coercion for Python classes and instances to GTypeClass + (Simon Feltman) (#685218) + - Replace direct parent class call by super() (Andrew Grigorev) (#729970) + - Add cairo marshaling support for non-introspected signals + (Simon Feltman) (#694604) + - [New API] Add gi.require_foreign (Simon Feltman) (#707735) + - Initialize the foreign API at PyGI load time (Simon Feltman) (#694604) + - Move pygi foreign API into pygi-foreign-api.h (Simon Feltman) (#694604) + - Unify GLib.GError and GLib.Error (Simon Feltman) (#712519) + - PEP8 fixes (Simon Feltman) + 3.13.1 28-Apr-2014 - Raise TypeError if arguments are passed to Boxed.__init__ (Christoph Reiter) (#727810) diff --git a/PKG-INFO b/PKG-INFO index f1eca4b..397928c 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: PyGObject -Version: 3.13.1 +Version: 3.13.2 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.13/pygobject-3.13.1.tar.gz +Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.13/pygobject-3.13.2.tar.gz Description: Python bindings for GLib and GObject Platform: POSIX, Windows Classifier: Development Status :: 5 - Production/Stable diff --git a/configure b/configure index eca8ab5..c83c26e 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.13.1. +# Generated by GNU Autoconf 2.69 for pygobject 3.13.2. # # Report bugs to . # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pygobject' PACKAGE_TARNAME='pygobject' -PACKAGE_VERSION='3.13.1' -PACKAGE_STRING='pygobject 3.13.1' +PACKAGE_VERSION='3.13.2' +PACKAGE_STRING='pygobject 3.13.2' PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject' PACKAGE_URL='https://wiki.gnome.org/Projects/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.13.1 to adapt to many kinds of systems. +\`configure' configures pygobject 3.13.2 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.13.1:";; + short | recursive ) echo "Configuration of pygobject 3.13.2:";; esac cat <<\_ACEOF @@ -1603,7 +1603,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pygobject configure 3.13.1 +pygobject configure 3.13.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1881,7 +1881,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.13.1, which was +It was created by pygobject $as_me 3.13.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2245,9 +2245,9 @@ $as_echo "#define PYGOBJECT_MINOR_VERSION 13" >>confdefs.h PYGOBJECT_MINOR_VERSION=13 -$as_echo "#define PYGOBJECT_MICRO_VERSION 1" >>confdefs.h +$as_echo "#define PYGOBJECT_MICRO_VERSION 2" >>confdefs.h -PYGOBJECT_MICRO_VERSION=1 +PYGOBJECT_MICRO_VERSION=2 ac_config_headers="$ac_config_headers config.h" @@ -2767,7 +2767,7 @@ fi # Define the identity of the package. PACKAGE='pygobject' - VERSION='3.13.1' + VERSION='3.13.2' cat >>confdefs.h <<_ACEOF @@ -13840,16 +13840,16 @@ if test -n "$GI_CFLAGS"; then 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.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 \""; } >&5 ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.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.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 " 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else @@ -13863,16 +13863,16 @@ if test -n "$GI_LIBS"; then 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.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 \""; } >&5 ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.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.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 " 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else @@ -13895,18 +13895,18 @@ else fi if test $_pkg_short_errors_supported = yes; then GI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 " 2>&1` else GI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.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.38.0 - gobject-introspection-1.0 >= 1.38.0 + gobject-introspection-1.0 >= 1.39.0 ) were not met: $GI_PKG_ERRORS @@ -15370,7 +15370,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.13.1, which was +This file was extended by pygobject $as_me 3.13.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15437,7 +15437,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.13.1 +pygobject config.status 3.13.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index a21c489..77fe449 100644 --- a/configure.ac +++ b/configure.ac @@ -18,11 +18,11 @@ m4_define(python3_min_ver, 3.1) dnl the pygobject version number m4_define(pygobject_major_version, 3) m4_define(pygobject_minor_version, 13) -m4_define(pygobject_micro_version, 1) +m4_define(pygobject_micro_version, 2) 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.38.0) +m4_define(introspection_required_version, 1.39.0) m4_define(py2cairo_required_version, 1.2.0) m4_define(py3cairo_required_version, 1.10.0) m4_define(glib_required_version, 2.38.0) diff --git a/gi/Makefile.am b/gi/Makefile.am index b00d30a..6fb1c5d 100644 --- a/gi/Makefile.am +++ b/gi/Makefile.am @@ -71,6 +71,7 @@ _gi_la_SOURCES = \ pygi-info.h \ pygi-foreign.c \ pygi-foreign.h \ + pygi-foreign-api.h \ pygi-struct.c \ pygi-struct.h \ pygi-source.c \ @@ -139,12 +140,14 @@ _gi_cairo_la_SOURCES = \ pygi-foreign-cairo.c _gi_cairo_la_CFLAGS = \ $(GI_CFLAGS) \ + $(CAIRO_CFLAGS) \ $(PYCAIRO_CFLAGS) _gi_cairo_la_CPPFLAGS = \ $(extension_cppflags) _gi_cairo_la_LIBADD = \ $(extension_libadd) \ $(GI_LIBS) \ + $(CAIRO_LIBS) \ $(PYCAIRO_LIBS) _gi_cairo_la_LDFLAGS = \ $(extension_ldflags) \ diff --git a/gi/Makefile.in b/gi/Makefile.in index 82ee5e7..256b41a 100644 --- a/gi/Makefile.in +++ b/gi/Makefile.in @@ -155,7 +155,8 @@ _gi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(_gi_la_CFLAGS) $(CFLAGS) \ $(_gi_la_LDFLAGS) $(LDFLAGS) -o $@ _gi_cairo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am__gi_cairo_la_OBJECTS = _gi_cairo_la-pygi-foreign-cairo.lo _gi_cairo_la_OBJECTS = $(am__gi_cairo_la_OBJECTS) _gi_cairo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -492,6 +493,7 @@ _gi_la_SOURCES = \ pygi-info.h \ pygi-foreign.c \ pygi-foreign.h \ + pygi-foreign-api.h \ pygi-struct.c \ pygi-struct.h \ pygi-source.c \ @@ -561,6 +563,7 @@ _gi_cairo_la_SOURCES = \ _gi_cairo_la_CFLAGS = \ $(GI_CFLAGS) \ + $(CAIRO_CFLAGS) \ $(PYCAIRO_CFLAGS) _gi_cairo_la_CPPFLAGS = \ @@ -569,6 +572,7 @@ _gi_cairo_la_CPPFLAGS = \ _gi_cairo_la_LIBADD = \ $(extension_libadd) \ $(GI_LIBS) \ + $(CAIRO_LIBS) \ $(PYCAIRO_LIBS) _gi_cairo_la_LDFLAGS = \ diff --git a/gi/__init__.py b/gi/__init__.py index 7c1a279..df6843c 100644 --- a/gi/__init__.py +++ b/gi/__init__.py @@ -26,6 +26,7 @@ __path__ = extend_path(__path__, __name__) import sys import os +import importlib # we can't have pygobject 2 loaded at the same time we load the internal _gobject if 'gobject' in sys.modules: @@ -33,6 +34,7 @@ if 'gobject' in sys.modules: 'modules like "gobject". Please change all occurrences ' 'of "import gobject" to "from gi.repository import GObject".') +from . import _gi from ._gi import _gobject from ._gi import _API from ._gi import Repository @@ -87,3 +89,29 @@ def require_version(namespace, version): def get_required_version(namespace): return _versions.get(namespace, None) + + +def require_foreign(namespace, symbol=None): + """Ensure the given foreign marshaling module is available and loaded. + + :param str namespace: + Introspection namespace of the foreign module (e.g. "cairo") + :param symbol: + Optional symbol typename to ensure a converter exists. + :type symbol: str or None + :raises: ImportError + + :Example: + + .. code-block:: python + + import gi + import cairo + gi.require_foreign('cairo') + + """ + try: + _gi.require_foreign(namespace, symbol) + except Exception as e: + raise ImportError(str(e)) + importlib.import_module('gi.repository', namespace) diff --git a/gi/_error.py b/gi/_error.py new file mode 100644 index 0000000..6b684ce --- /dev/null +++ b/gi/_error.py @@ -0,0 +1,54 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2014 Simon Feltman +# +# _error.py: GError Python implementation +# +# 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 + + +# NOTE: This file should not have any dependencies on introspection libs +# like gi.repository.GLib because it would cause a circular dependency. +# Developers wanting to use the GError class in their applications should +# use gi.repository.GLib.GError + + +class GError(RuntimeError): + def __init__(self, message='unknown error', domain='pygi-error', code=0): + super(GError, self).__init__(message) + self.message = message + self.domain = domain + self.code = code + + def __str__(self): + return "%s: %s (%d)" % (self.domain, self.message, self.code) + + def __repr__(self): + return "%s.%s('%s', '%s', %d)" % (GError.__module__, GError.__name__, + self.message, self.domain, self.code) + + def copy(self): + return GError(self.message, self.domain, self.code) + + def matches(self, domain, code): + """Placeholder that will be monkey patched in GLib overrides.""" + raise NotImplementedError + + @staticmethod + def new_literal(domain, message, code): + """Placeholder that will be monkey patched in GLib overrides.""" + raise NotImplementedError diff --git a/gi/_option.py b/gi/_option.py index 422c53f..2d30abf 100644 --- a/gi/_option.py +++ b/gi/_option.py @@ -41,6 +41,7 @@ else: _bytes = str from gi._gi import _glib +from gi._error import GError GLib = get_introspection_module('GLib') OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark()) @@ -202,7 +203,7 @@ class OptionGroup(optparse.OptionGroup): opt.process(option_name, option_value, self.values, parser) except OptionValueError: error = sys.exc_info()[1] - gerror = _glib.GError(str(error)) + gerror = GError(str(error)) gerror.domain = OPTION_CONTEXT_ERROR_QUARK gerror.code = GLib.OptionError.BAD_VALUE gerror.message = str(error) @@ -347,7 +348,7 @@ class OptionParser(optparse.OptionParser): try: options, args = optparse.OptionParser.parse_args( self, args, values) - except _glib.GError: + except GError: error = sys.exc_info()[1] if error.domain != OPTION_CONTEXT_ERROR_QUARK: raise diff --git a/gi/gimodule.c b/gi/gimodule.c index 25fc3d6..44a8fbd 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -27,6 +27,8 @@ #include "pygi-private.h" #include "pygi.h" #include "pyglib.h" +#include "pygi-error.h" +#include "pygi-foreign.h" #include @@ -494,7 +496,7 @@ _wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args) return NULL; } - values[i] = (GVariant *) ( (PyGPointer *) value)->pointer; + values[i] = pyg_pointer_get (value, GVariant); } variant = g_variant_new_tuple (values, PyTuple_Size (py_values)); @@ -584,7 +586,7 @@ pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs) status = g_io_channel_read_chars (iochannel, buf, buf_size, &single_read, &error); Py_END_ALLOW_THREADS; - if (pyglib_error_check(&error)) + if (pygi_error_check (&error)) goto failure; total_read += single_read; @@ -615,15 +617,12 @@ static PyMethodDef _gi_functions[] = { { "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS }, { "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS }, { "io_channel_read", (PyCFunction) pyg_channel_read, METH_VARARGS }, + { "require_foreign", (PyCFunction) pygi_require_foreign, METH_VARARGS | METH_KEYWORDS }, { NULL, NULL, 0 } }; static struct PyGI_API CAPI = { - pygi_type_import_by_g_type_real, - pygi_get_property_value_real, - pygi_set_property_value_real, - pygi_signal_closure_new_real, - pygi_register_foreign_struct_real, + pygi_register_foreign_struct, }; PYGLIB_MODULE_START(_gi, "_gi") @@ -664,12 +663,14 @@ PYGLIB_MODULE_START(_gi, "_gi") PyModule_AddObject (module, "_gobject", _gobject_module); PyModule_AddStringConstant(module, "__package__", "gi._gi"); + pygi_foreign_init (); + pygi_error_register_types (module); _pygi_repository_register_types (module); _pygi_info_register_types (module); _pygi_struct_register_types (module); _pygi_boxed_register_types (module); _pygi_ccallback_register_types (module); - _pygi_argument_init(); + _pygi_argument_init (); /* Use RuntimeWarning as the base class of PyGIDeprecationWarning * for unstable (odd minor version) and use DeprecationWarning for diff --git a/gi/glibmodule.c b/gi/glibmodule.c index e859158..297805a 100644 --- a/gi/glibmodule.c +++ b/gi/glibmodule.c @@ -31,8 +31,6 @@ #include "pygoptiongroup.h" #include "pygspawn.h" -PyObject *PyGError = NULL; - /* ---------------- glib module functions -------------------- */ static PyMethodDef _glib_functions[] = { @@ -48,27 +46,10 @@ static PyMethodDef _glib_functions[] = { { NULL, NULL, 0 } }; -static void -pyglib_register_error(PyObject *d) -{ - PyObject *dict; - dict = PyDict_New(); - /* This is a hack to work around the deprecation warning of - * BaseException.message in Python 2.6+. - * GError has also an "message" attribute. - */ - PyDict_SetItemString(dict, "message", Py_None); - PyGError = PyErr_NewException("gi._glib.GError", PyExc_RuntimeError, dict); - Py_DECREF(dict); - - PyDict_SetItemString(d, "GError", PyGError); -} - PYGLIB_MODULE_START(_glib, "_glib") { PyObject *d = PyModule_GetDict(module); - pyglib_register_error(d); pyglib_spawn_register_types(d); pyglib_option_context_register_types(d); pyglib_option_group_register_types(d); diff --git a/gi/gobjectmodule.c b/gi/gobjectmodule.c index a20d93a..458884b 100644 --- a/gi/gobjectmodule.c +++ b/gi/gobjectmodule.c @@ -37,6 +37,7 @@ #include "pygoptiongroup.h" #include "pygi-value.h" +#include "pygi-error.h" static GHashTable *log_handlers = NULL; static gboolean log_handlers_disabled = FALSE; @@ -1834,55 +1835,6 @@ pyg_flags_add_constants(PyObject *module, GType flags_type, } /** - * pyg_error_check: - * @error: a pointer to the GError. - * - * Checks to see if the GError has been set. If the error has been - * set, then the gobject.GError Python exception will be raised, and - * the GError cleared. - * - * Returns: True if an error was set. - * - * Deprecated: Since 2.16, use pyglib_error_check instead. - */ -gboolean -pyg_error_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_error_check is deprecated, use " - "pyglib_error_check instead")) - return NULL; -#endif - return pyglib_error_check(error); -} - -/** - * pyg_gerror_exception_check: - * @error: a standard GLib GError ** output parameter - * - * Checks to see if a GError exception has been raised, and if so - * translates the python exception to a standard GLib GError. If the - * raised exception is not a GError then PyErr_Print() is called. - * - * Returns: 0 if no exception has been raised, -1 if it is a - * valid gobject.GError, -2 otherwise. - * - * Deprecated: Since 2.16, use pyglib_gerror_exception_check instead. - */ -gboolean -pyg_gerror_exception_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_gerror_exception_check is deprecated, use " - "pyglib_gerror_exception_check instead")) - return NULL; -#endif - return pyglib_gerror_exception_check(error); -} - -/** * pyg_parse_constructor_args: helper function for PyGObject constructors * @obj_type: GType of the GObject, for parameter introspection * @arg_names: %NULL-terminated array of constructor argument names @@ -2055,7 +2007,7 @@ struct _PyGObject_Functions pygobject_api_functions = { pyg_constant_strip_prefix, - pyg_error_check, + pygi_error_check, _pyg_set_thread_block_funcs, (PyGThreadBlockFunc)0, /* block_threads */ @@ -2098,7 +2050,7 @@ struct _PyGObject_Functions pygobject_api_functions = { NULL, /* previously type_register_custom */ - pyg_gerror_exception_check, + pygi_gerror_exception_check, pyg_option_group_new, pyg_type_from_object_strict, diff --git a/gi/overrides/GIMarshallingTests.py b/gi/overrides/GIMarshallingTests.py index cc967b4..b675adf 100644 --- a/gi/overrides/GIMarshallingTests.py +++ b/gi/overrides/GIMarshallingTests.py @@ -53,13 +53,13 @@ class OverridesObject(GIMarshallingTests.OverridesObject): def __init__(self, long_): GIMarshallingTests.OverridesObject.__init__(self) # FIXME: doesn't work yet - #self.long_ = long_ + # self.long_ = long_ @classmethod def new(cls, long_): self = GIMarshallingTests.OverridesObject.new() # FIXME: doesn't work yet - #self.long_ = long_ + # self.long_ = long_ return self def method(self): diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py index 0e8f694..214d507 100644 --- a/gi/overrides/GLib.py +++ b/gi/overrides/GLib.py @@ -40,7 +40,9 @@ __all__.append('option') # Types and functions still needed from static bindings from gi._gi import _glib -GError = _glib.GError +from gi._error import GError + +Error = GError OptionContext = _glib.OptionContext OptionGroup = _glib.OptionGroup Pid = _glib.Pid @@ -52,7 +54,30 @@ def threads_init(): 'See: https://wiki.gnome.org/PyGObject/Threading', PyGIDeprecationWarning, stacklevel=2) -__all__ += ['GError', 'OptionContext', 'OptionGroup', 'Pid', + +def gerror_matches(self, domain, code): + # Handle cases where self.domain was set to an integer for compatibility + # with the introspected GLib.Error. + if isinstance(self.domain, str): + self_domain_quark = GLib.quark_from_string(self.domain) + else: + self_domain_quark = self.domain + return (self_domain_quark, self.code) == (domain, code) + + +def gerror_new_literal(domain, message, code): + domain_quark = GLib.quark_to_string(domain) + return GError(message, domain_quark, code) + + +# Monkey patch methods that rely on GLib introspection to be loaded at runtime. +Error.__name__ = 'Error' +Error.__module__ = 'GLib' +Error.matches = gerror_matches +Error.new_literal = staticmethod(gerror_new_literal) + + +__all__ += ['GError', 'Error', 'OptionContext', 'OptionGroup', 'Pid', 'spawn_async', 'threads_init'] diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py index 5a5dd2f..e646821 100644 --- a/gi/overrides/Gio.py +++ b/gi/overrides/Gio.py @@ -82,14 +82,14 @@ class Settings(Gio.Settings): def __getitem__(self, key): # get_value() aborts the program on an unknown key - if not key in self: + if key not in self: raise KeyError('unknown key: %r' % (key,)) return self.get_value(key).unpack() def __setitem__(self, key, value): # set_value() aborts the program on an unknown key - if not key in self: + if key not in self: raise KeyError('unknown key: %r' % (key,)) # determine type string of this key diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py index df55c2d..561bdf0 100644 --- a/gi/overrides/Gtk.py +++ b/gi/overrides/Gtk.py @@ -86,6 +86,17 @@ class Widget(Gtk.Widget): target_list = Gtk.TargetList.new(_construct_target_list(target_list)) super(Widget, self).drag_source_set_target_list(target_list) + def style_get_property(self, property_name, value=None): + if value is None: + prop = self.find_style_property(property_name) + if prop is None: + raise ValueError('Class "%s" does not contain style property "%s"' % + (self, property_name)) + value = GObject.Value(prop.value_type) + + Gtk.Widget.style_get_property(self, property_name, value) + return value.get_value() + Widget = override(Widget) __all__.append('Widget') @@ -110,6 +121,27 @@ class Container(Gtk.Container, Widget): get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain) + def child_get_property(self, child, property_name, value=None): + if value is None: + prop = self.find_child_property(property_name) + if prop is None: + raise ValueError('Class "%s" does not contain child property "%s"' % + (self, property_name)) + value = GObject.Value(prop.value_type) + + Gtk.Container.child_get_property(self, child, property_name, value) + return value.get_value() + + def child_get(self, child, *prop_names): + """Returns a list of child property values for the given names.""" + return [self.child_get_property(child, name) for name in prop_names] + + def child_set(self, child, **kwargs): + """Set a child properties on the given child to key/value pairs.""" + for name, value in kwargs.items(): + name = name.replace('_', '-') + self.child_set_property(child, name, value) + Container = override(Container) __all__.append('Container') @@ -1122,13 +1154,13 @@ class TreePath(Gtk.TreePath): return self.to_string() def __lt__(self, other): - return not other is None and self.compare(other) < 0 + return other is not None and self.compare(other) < 0 def __le__(self, other): - return not other is None and self.compare(other) <= 0 + return other is not None and self.compare(other) <= 0 def __eq__(self, other): - return not other is None and self.compare(other) == 0 + return other is not None and self.compare(other) == 0 def __ne__(self, other): return other is None or self.compare(other) != 0 diff --git a/gi/pygboxed.c b/gi/pygboxed.c index 35716a2..9faa652 100644 --- a/gi/pygboxed.c +++ b/gi/pygboxed.c @@ -27,6 +27,7 @@ #include "pygboxed.h" #include "pygi.h" +#include "pygi-type.h" GQuark pygboxed_type_key; GQuark pygboxed_marshal_key; @@ -36,9 +37,9 @@ PYGLIB_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); static void pyg_boxed_dealloc(PyGBoxed *self) { - if (self->free_on_dealloc && self->boxed) { + if (self->free_on_dealloc && pyg_boxed_get_ptr (self)) { PyGILState_STATE state = pyglib_gil_state_ensure(); - g_boxed_free(self->gtype, self->boxed); + g_boxed_free (self->gtype, pyg_boxed_get_ptr (self)); pyglib_gil_state_release(state); } @@ -50,9 +51,9 @@ pyg_boxed_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type)) - return _pyglib_generic_ptr_richcompare(((PyGBoxed*)self)->boxed, - ((PyGBoxed*)other)->boxed, - op); + return _pyglib_generic_ptr_richcompare (pyg_boxed_get_ptr (self), + pyg_boxed_get_ptr (other), + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -63,7 +64,7 @@ pyg_boxed_richcompare(PyObject *self, PyObject *other, int op) static long pyg_boxed_hash(PyGBoxed *self) { - return (long)self->boxed; + return (long)pyg_boxed_get_ptr (self); } static PyObject * @@ -72,7 +73,7 @@ pyg_boxed_repr(PyGBoxed *self) gchar buf[128]; g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->boxed); + (long)pyg_boxed_get_ptr (self)); return PYGLIB_PyUnicode_FromString(buf); } @@ -84,7 +85,7 @@ pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) if (!PyArg_ParseTuple(args, ":GBoxed.__init__")) return -1; - self->boxed = NULL; + pyg_boxed_set_ptr (self, NULL); self->gtype = 0; self->free_on_dealloc = FALSE; @@ -103,7 +104,7 @@ pyg_boxed_free(PyObject *op) static PyObject * pyg_boxed_copy(PyGBoxed *self) { - return pyg_boxed_new (self->gtype, self->boxed, TRUE, TRUE); + return pyg_boxed_new (self->gtype, pyg_boxed_get_ptr (self), TRUE, TRUE); } @@ -205,7 +206,7 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, if (copy_boxed) boxed = g_boxed_copy(boxed_type, boxed); - self->boxed = boxed; + pyg_boxed_set_ptr (self, boxed); self->gtype = boxed_type; self->free_on_dealloc = own_ref; diff --git a/gi/pygenum.c b/gi/pygenum.c index 1b9b50e..053518f 100644 --- a/gi/pygenum.c +++ b/gi/pygenum.c @@ -26,6 +26,7 @@ #include #include "pygobject-private.h" #include "pygi.h" +#include "pygi-type.h" #include "pygenum.h" diff --git a/gi/pygflags.c b/gi/pygflags.c index c14bf7d..a7df8ce 100644 --- a/gi/pygflags.c +++ b/gi/pygflags.c @@ -28,6 +28,7 @@ #include "pygflags.h" #include "pygi.h" +#include "pygi-type.h" GQuark pygflags_class_key; diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index 4094c3d..15be78c 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -33,7 +33,7 @@ #include "pygi-basictype.h" #include "pygi-object.h" #include "pygi-struct-marshal.h" - +#include "pygi-error.h" static gboolean gi_argument_to_gssize (GIArgument *arg_in, @@ -1029,16 +1029,16 @@ array_success: * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ - _pygi_marshal_from_py_interface_struct (object, - &arg, - NULL, /*arg_name*/ - info, /*interface_info*/ - g_type, - py_type, - transfer, - FALSE, /*copy_reference*/ - g_struct_info_is_foreign (info), - g_type_info_is_pointer (type_info)); + pygi_arg_struct_from_py_marshal (object, + &arg, + NULL, /*arg_name*/ + info, /*interface_info*/ + g_type, + py_type, + transfer, + FALSE, /*copy_reference*/ + g_struct_info_is_foreign (info), + g_type_info_is_pointer (type_info)); Py_DECREF (py_type); break; @@ -1372,13 +1372,13 @@ _pygi_argument_to_object (GIArgument *arg, py_type = _pygi_type_get_from_g_type (g_type); } - object = _pygi_marshal_to_py_interface_struct (arg, - info, /*interface_info*/ - g_type, - py_type, - transfer, - FALSE, /*is_allocated*/ - g_struct_info_is_foreign (info)); + object = pygi_arg_struct_to_py_marshal (arg, + info, /*interface_info*/ + g_type, + py_type, + transfer, + FALSE, /*is_allocated*/ + g_struct_info_is_foreign (info)); Py_XDECREF (py_type); break; @@ -1558,12 +1558,12 @@ _pygi_argument_to_object (GIArgument *arg, GError *error = (GError *) arg->v_pointer; if (error != NULL && transfer == GI_TRANSFER_NOTHING) { /* If we have not been transferred the ownership we must copy - * the error, because pyglib_error_check() is going to free it. + * the error, because pygi_error_check() is going to free it. */ error = g_error_copy (error); } - if (pyglib_error_check (&error)) { + if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; diff --git a/gi/pygi-array.c b/gi/pygi-array.c index c17ace0..fceffc6 100644 --- a/gi/pygi-array.c +++ b/gi/pygi-array.c @@ -454,7 +454,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, * allocated in _pygi_marshal_from_py_array(), so we must * not try to deallocate it as a slice and thus * short-circuit cleanup_func. */ - if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) { + if (cleanup_func == pygi_arg_gvalue_from_py_cleanup) { g_value_unset ((GValue*) item); continue; } diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c index c52858b..b46cdcc 100644 --- a/gi/pygi-boxed.c +++ b/gi/pygi-boxed.c @@ -32,10 +32,10 @@ _boxed_dealloc (PyGIBoxed *self) if ( ( (PyGBoxed *) self)->free_on_dealloc) { if (self->slice_allocated) { - g_slice_free1 (self->size, ( (PyGBoxed *) self)->boxed); + g_slice_free1 (self->size, pyg_boxed_get_ptr (self)); } else { g_type = pyg_type_from_object ( (PyObject *) self); - g_boxed_free (g_type, ( (PyGBoxed *) self)->boxed); + g_boxed_free (g_type, pyg_boxed_get_ptr (self)); } } @@ -158,8 +158,8 @@ _pygi_boxed_new (PyTypeObject *type, } ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type); - ( (PyGBoxed *) self)->boxed = boxed; ( (PyGBoxed *) self)->free_on_dealloc = free_on_dealloc; + pyg_boxed_set_ptr (self, boxed); if (allocated_slice > 0) { self->size = allocated_slice; self->slice_allocated = TRUE; diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index c8da66f..24bb1a4 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -695,7 +695,7 @@ _setup_invoker (GICallableInfo *callable_info, &error)) { return TRUE; } - if (!pyglib_error_check (&error)) { + if (!pygi_error_check (&error)) { PyErr_Format (PyExc_RuntimeError, "unknown error creating invoker for %s", g_base_info_get_name ((GIBaseInfo *)callable_info)); @@ -707,7 +707,7 @@ _setup_invoker (GICallableInfo *callable_info, (GIFunctionInfo *)callable_info, invoker, &error)) { - if (!pyglib_error_check (&error)) { + if (!pygi_error_check (&error)) { PyErr_Format (PyExc_RuntimeError, "unknown error creating invoker for %s", g_base_info_get_name ((GIBaseInfo *)callable_info)); diff --git a/gi/pygi-error.c b/gi/pygi-error.c index 349bb7e..2e9150f 100644 --- a/gi/pygi-error.c +++ b/gi/pygi-error.c @@ -1,6 +1,8 @@ /* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * @@ -23,6 +25,194 @@ #include "pygi-error.h" +static PyObject *PyGError = NULL; +static PyObject *exception_table = NULL; + +/** + * pygi_error_marshal: + * @error: a pointer to the GError. + * + * Checks to see if @error has been set. If @error has been set, then a + * GLib.GError Python exception object is returned (but not raised). + * + * Returns: a GLib.GError Python exception object, or NULL. + */ +PyObject * +pygi_error_marshal (GError **error) +{ + PyGILState_STATE state; + PyObject *exc_type; + PyObject *exc_instance; + const char *domain = NULL; + + g_return_val_if_fail(error != NULL, NULL); + + if (*error == NULL) + return NULL; + + state = pyglib_gil_state_ensure(); + + exc_type = PyGError; + if (exception_table != NULL) + { + PyObject *item; + item = PyDict_GetItem(exception_table, PYGLIB_PyLong_FromLong((*error)->domain)); + if (item != NULL) + exc_type = item; + } + + if ((*error)->domain) { + domain = g_quark_to_string ((*error)->domain); + } + + exc_instance = PyObject_CallFunction (exc_type, "ssi", + (*error)->message, + domain, + (*error)->code); + + pyglib_gil_state_release(state); + + return exc_instance; +} + +/** + * pygi_error_check: + * @error: a pointer to the GError. + * + * Checks to see if the GError has been set. If the error has been + * set, then the glib.GError Python exception will be raised, and + * the GError cleared. + * + * Returns: True if an error was set. + */ +gboolean +pygi_error_check (GError **error) +{ + PyGILState_STATE state; + PyObject *exc_instance; + + g_return_val_if_fail(error != NULL, FALSE); + if (*error == NULL) + return FALSE; + + state = pyglib_gil_state_ensure(); + + exc_instance = pygi_error_marshal (error); + PyErr_SetObject(PyGError, exc_instance); + Py_DECREF(exc_instance); + g_clear_error(error); + + pyglib_gil_state_release(state); + + return TRUE; +} + +/** + * pygi_gerror_exception_check: + * @error: a standard GLib GError ** output parameter + * + * Checks to see if a GError exception has been raised, and if so + * translates the python exception to a standard GLib GError. If the + * raised exception is not a GError then PyErr_Print() is called. + * + * Returns: 0 if no exception has been raised, -1 if it is a + * valid glib.GError, -2 otherwise. + */ +gboolean +pygi_gerror_exception_check (GError **error) +{ + PyObject *type, *value, *traceback; + PyObject *py_message, *py_domain, *py_code; + const char *bad_gerror_message; + + PyErr_Fetch(&type, &value, &traceback); + if (type == NULL) + return 0; + PyErr_NormalizeException(&type, &value, &traceback); + if (value == NULL) { + PyErr_Restore(type, value, traceback); + PyErr_Print(); + return -2; + } + if (!value || + !PyErr_GivenExceptionMatches(type, + (PyObject *) PyGError)) { + PyErr_Restore(type, value, traceback); + PyErr_Print(); + return -2; + } + Py_DECREF(type); + Py_XDECREF(traceback); + + py_message = PyObject_GetAttrString(value, "message"); + if (!py_message || !PYGLIB_PyUnicode_Check(py_message)) { + bad_gerror_message = "GLib.Error instances must have a 'message' string attribute"; + Py_XDECREF(py_message); + goto bad_gerror; + } + + py_domain = PyObject_GetAttrString(value, "domain"); + if (!py_domain || !PYGLIB_PyUnicode_Check(py_domain)) { + bad_gerror_message = "GLib.Error instances must have a 'domain' string attribute"; + Py_DECREF(py_message); + Py_XDECREF(py_domain); + goto bad_gerror; + } + + py_code = PyObject_GetAttrString(value, "code"); + if (!py_code || !PYGLIB_PyLong_Check(py_code)) { + bad_gerror_message = "GLib.Error instances must have a 'code' int attribute"; + Py_DECREF(py_message); + Py_DECREF(py_domain); + Py_XDECREF(py_code); + goto bad_gerror; + } + + g_set_error(error, g_quark_from_string(PYGLIB_PyUnicode_AsString(py_domain)), + PYGLIB_PyLong_AsLong(py_code), "%s", PYGLIB_PyUnicode_AsString(py_message)); + + Py_DECREF(py_message); + Py_DECREF(py_code); + Py_DECREF(py_domain); + return -1; + +bad_gerror: + Py_DECREF(value); + g_set_error(error, g_quark_from_static_string("pygi"), 0, "%s", bad_gerror_message); + PyErr_SetString(PyExc_ValueError, bad_gerror_message); + PyErr_Print(); + return -2; +} + +/** + * pygi_register_exception_for_domain: + * @name: name of the exception + * @error_domain: error domain + * + * Registers a new GLib.Error exception subclass called #name for + * a specific #domain. This exception will be raised when a GError + * of the same domain is passed in to pygi_error_check(). + * + * Returns: the new exception + */ +PyObject * +pygi_register_exception_for_domain (gchar *name, + gint error_domain) +{ + PyObject *exception; + + exception = PyErr_NewException(name, PyGError, NULL); + + if (exception_table == NULL) + exception_table = PyDict_New(); + + PyDict_SetItem(exception_table, + PYGLIB_PyLong_FromLong(error_domain), + exception); + + return exception; +} + static gboolean _pygi_marshal_from_py_gerror (PyGIInvokeState *state, PyGICallableCache *callable_cache, @@ -45,7 +235,7 @@ _pygi_marshal_to_py_gerror (PyGIInvokeState *state, GError *error = arg->v_pointer; PyObject *py_obj = NULL; - py_obj = pyglib_error_marshal(&error); + py_obj = pygi_error_marshal (&error); if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) { g_error_free (error); @@ -107,3 +297,16 @@ pygi_arg_gerror_new_from_info (GITypeInfo *type_info, return NULL; } } + +void +pygi_error_register_types (PyObject *module) +{ + PyObject *error_module = PyImport_ImportModule ("gi._error"); + if (!error_module) { + return; + } + + /* Stash a reference to the Python implemented gi._error.GError. */ + PyGError = PyObject_GetAttrString (error_module, "GError"); +} + diff --git a/gi/pygi-error.h b/gi/pygi-error.h index fdeb32f..72d2be0 100644 --- a/gi/pygi-error.h +++ b/gi/pygi-error.h @@ -1,6 +1,8 @@ /* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin * Copyright (C) 2014 Simon Feltman * * This library is free software; you can redistribute it and/or @@ -25,10 +27,21 @@ G_BEGIN_DECLS -PyGIArgCache *pygi_arg_gerror_new_from_info (GITypeInfo *type_info, - GIArgInfo *arg_info, /* may be null */ - GITransfer transfer, - PyGIDirection direction); +gboolean pygi_error_check (GError **error); + +PyObject* pygi_error_marshal (GError **error); + +gboolean pygi_gerror_exception_check (GError **error); + +PyObject* pygi_register_exception_for_domain (gchar *name, + gint error_domain); + +PyGIArgCache* pygi_arg_gerror_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction); + +void pygi_error_register_types (PyObject *module); G_END_DECLS diff --git a/gi/pygi-foreign-api.h b/gi/pygi-foreign-api.h new file mode 100644 index 0000000..9367518 --- /dev/null +++ b/gi/pygi-foreign-api.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin + * + * 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, see . + */ + +#ifndef __PYGI_FOREIGN_API_H__ +#define __PYGI_FOREIGN_API_H__ + +#include +#include + +typedef PyObject * (*PyGIArgOverrideToGIArgumentFunc) (PyObject *value, + GIInterfaceInfo *interface_info, + GITransfer transfer, + GIArgument *arg); +typedef PyObject * (*PyGIArgOverrideFromGIArgumentFunc) (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data); +typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info, + gpointer struct_); + + +struct PyGI_API { + void (*register_foreign_struct) (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func); +}; + + +#ifndef _INSIDE_PYGOBJECT_ + +static struct PyGI_API *PyGI_API = NULL; + +static int +_pygi_import (void) +{ + if (PyGI_API != NULL) { + return 1; + } + PyGI_API = (struct PyGI_API*) PyCapsule_Import("gi._API", FALSE); + if (PyGI_API == NULL) { + return -1; + } + + return 0; +} + + +static inline PyObject * +pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func) +{ + if (_pygi_import() < 0) { + return NULL; + } + PyGI_API->register_foreign_struct(namespace_, + name, + to_func, + from_func, + release_func); + Py_RETURN_NONE; +} + +#endif /* _INSIDE_PYGOBJECT_ */ + +#endif /* __PYGI_FOREIGN_API_H__ */ diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c index 8261a07..5937759 100644 --- a/gi/pygi-foreign-cairo.c +++ b/gi/pygi-foreign-cairo.c @@ -31,11 +31,19 @@ static Pycairo_CAPI_t *Pycairo_CAPI; #include #endif +#include -#include "pygi-foreign.h" - +/* Limit includes from PyGI to APIs which do not have link dependencies + * (pygobject.h and pygi-foreign-api.h) since _gi_cairo is built as a separate + * shared library that interacts with PyGI through a PyCapsule API at runtime. + */ +#include #include +/* + * cairo_t marshaling + */ + static PyObject * cairo_context_to_arg (PyObject *value, GIInterfaceInfo *interface_info, @@ -68,6 +76,7 @@ cairo_context_from_arg (GIInterfaceInfo *interface_info, return PycairoContext_FromContext (context, &PycairoContext_Type, NULL); } + static PyObject * cairo_context_release (GIBaseInfo *base_info, gpointer struct_) @@ -76,6 +85,36 @@ cairo_context_release (GIBaseInfo *base_info, Py_RETURN_NONE; } +static int +cairo_context_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_t *cr = PycairoContext_GET (obj); + if (!cr) { + return -1; + } + + /* PycairoContext_GET returns a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, cr); + return 0; +} + +static PyObject * +cairo_context_from_gvalue (const GValue *value) +{ + /* PycairoContext_FromContext steals a ref, so we dup it out of the GValue. */ + cairo_t *cr = g_value_dup_boxed (value); + if (!cr) { + return NULL; + } + + return PycairoContext_FromContext (cr, &PycairoContext_Type, NULL); +} + + +/* + * cairo_surface_t marshaling + */ static PyObject * cairo_surface_to_arg (PyObject *value, @@ -118,6 +157,36 @@ cairo_surface_release (GIBaseInfo *base_info, Py_RETURN_NONE; } +static int +cairo_surface_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_surface_t *surface = ((PycairoSurface*) obj)->surface; + if (!surface) { + return -1; + } + + /* surface is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, surface); + return 0; +} + +static PyObject * +cairo_surface_from_gvalue (const GValue *value) +{ + /* PycairoSurface_FromSurface steals a ref, so we dup it out of the GValue. */ + cairo_surface_t *surface = g_value_dup_boxed (value); + if (!surface) { + return NULL; + } + + return PycairoSurface_FromSurface (surface, NULL); +} + + +/* + * cairo_path_t marshaling + */ static PyObject * cairo_path_to_arg (PyObject *value, @@ -162,6 +231,39 @@ cairo_path_release (GIBaseInfo *base_info, Py_RETURN_NONE; } + +/* + * cairo_font_face_t marshaling + */ + +static int +cairo_font_face_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_font_face_t *font_face = ((PycairoFontFace*) obj)->font_face; + if (!font_face) { + return -1; + } + + g_value_set_boxed (value, font_face); + return 0; +} + +static PyObject * +cairo_font_face_from_gvalue (const GValue *value) +{ + cairo_font_face_t *font_face = g_value_dup_boxed (value); + if (!font_face) { + return NULL; + } + + return PycairoFontFace_FromFontFace (font_face); +} + + +/* + * cairo_font_options_t marshaling + */ + static PyObject * cairo_font_options_to_arg (PyObject *value, GIInterfaceInfo *interface_info, @@ -203,6 +305,69 @@ cairo_font_options_release (GIBaseInfo *base_info, Py_RETURN_NONE; } + +/* + * scaled_font_t marshaling + */ + +static int +cairo_scaled_font_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_scaled_font_t *scaled_font = ((PycairoScaledFont*) obj)->scaled_font; + if (!scaled_font) { + return -1; + } + + /* scaled_font is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, scaled_font); + return 0; +} + +static PyObject * +cairo_scaled_font_from_gvalue (const GValue *value) +{ + /* PycairoScaledFont_FromScaledFont steals a ref, so we dup it out of the GValue. */ + cairo_scaled_font_t *scaled_font = g_value_dup_boxed (value); + if (!scaled_font) { + return NULL; + } + + return PycairoScaledFont_FromScaledFont (scaled_font); +} + + +/* + * cairo_pattern_t marshaling + */ + +static int +cairo_pattern_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_pattern_t *pattern = ((PycairoPattern*) obj)->pattern; + if (!pattern) { + return -1; + } + + /* pattern is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, pattern); + return 0; +} + +static PyObject * +cairo_pattern_from_gvalue (const GValue *value) +{ + /* PycairoPattern_FromPattern steals a ref, so we dup it out of the GValue. */ + cairo_pattern_t *pattern = g_value_dup_boxed (value); + if (!pattern) { + return NULL; + } + + return PycairoPattern_FromPattern (pattern, NULL); +} + + static PyMethodDef _gi_cairo_functions[] = { {0,} }; PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo") { @@ -215,6 +380,8 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo") if (Pycairo_CAPI == NULL) return PYGLIB_MODULE_ERROR_RETURN; + pygobject_init (3, 13, 2); + pygi_register_foreign_struct ("cairo", "Context", cairo_context_to_arg, @@ -238,5 +405,26 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo") cairo_font_options_to_arg, cairo_font_options_from_arg, cairo_font_options_release); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_CONTEXT, + cairo_context_from_gvalue, + cairo_context_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SURFACE, + cairo_surface_from_gvalue, + cairo_surface_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_FONT_FACE, + cairo_font_face_from_gvalue, + cairo_font_face_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SCALED_FONT, + cairo_scaled_font_from_gvalue, + cairo_scaled_font_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_PATTERN, + cairo_pattern_from_gvalue, + cairo_pattern_to_gvalue); + } PYGLIB_MODULE_END; diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c index f3c1a34..82392be 100644 --- a/gi/pygi-foreign.c +++ b/gi/pygi-foreign.c @@ -63,24 +63,24 @@ do_lookup (const gchar *namespace, const gchar *name) return NULL; } +static PyObject * +pygi_struct_foreign_load_module (const char *namespace) +{ + gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL); + PyObject *module = PyImport_ImportModule (module_name); + g_free (module_name); + return module; +} + static PyGIForeignStruct * -pygi_struct_foreign_lookup (GIBaseInfo *base_info) +pygi_struct_foreign_lookup_by_name (const char *namespace, const char *name) { PyGIForeignStruct *result; - const gchar *namespace = g_base_info_get_namespace (base_info); - const gchar *name = g_base_info_get_name (base_info); - - if (foreign_structs == NULL) { - init_foreign_structs (); - } result = do_lookup (namespace, name); if (result == NULL) { - gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL); - PyObject *module = PyImport_ImportModule (module_name); - - g_free (module_name); + PyObject *module = pygi_struct_foreign_load_module (namespace); if (module == NULL) PyErr_Clear (); @@ -92,7 +92,7 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info) if (result == NULL) { PyErr_Format (PyExc_TypeError, - "Couldn't find conversion for foreign struct '%s.%s'", + "Couldn't find foreign struct converter for '%s.%s'", namespace, name); } @@ -100,6 +100,15 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info) return result; } +static PyGIForeignStruct * +pygi_struct_foreign_lookup (GIBaseInfo *base_info) +{ + const gchar *namespace = g_base_info_get_namespace (base_info); + const gchar *name = g_base_info_get_name (base_info); + + return pygi_struct_foreign_lookup_by_name (namespace, name); +} + PyObject * pygi_struct_foreign_convert_to_g_argument (PyObject *value, GIInterfaceInfo *interface_info, @@ -151,11 +160,11 @@ pygi_struct_foreign_release (GIBaseInfo *base_info, } void -pygi_register_foreign_struct_real (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func) +pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func) { PyGIForeignStruct *new_struct = g_slice_new (PyGIForeignStruct); new_struct->namespace = namespace_; @@ -166,3 +175,42 @@ pygi_register_foreign_struct_real (const char* namespace_, g_ptr_array_add (foreign_structs, new_struct); } + +PyObject * +pygi_require_foreign (PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "symbol", NULL }; + const char *namespace = NULL; + const char *symbol = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, + "s|z:require_foreign", + kwlist, &namespace, &symbol)) { + return NULL; + } + + if (symbol) { + PyGIForeignStruct *foreign; + foreign = pygi_struct_foreign_lookup_by_name (namespace, symbol); + if (foreign == NULL) { + return NULL; + } + } else { + PyObject *module = pygi_struct_foreign_load_module (namespace); + if (module) { + Py_DECREF (module); + } else { + return NULL; + } + } + + Py_RETURN_NONE; +} + +void +pygi_foreign_init (void) +{ + if (foreign_structs == NULL) { + init_foreign_structs (); + } +} diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h index 478d759..afa4768 100644 --- a/gi/pygi-foreign.h +++ b/gi/pygi-foreign.h @@ -26,9 +26,7 @@ #define __PYGI_FOREIGN_H__ #include -#include - -#include "pygi.h" +#include "pygi-foreign-api.h" PyObject *pygi_struct_foreign_convert_to_g_argument (PyObject *value, GIInterfaceInfo *interface_info, @@ -40,10 +38,16 @@ PyObject *pygi_struct_foreign_convert_from_g_argument (GIInterfaceInfo *interfac PyObject *pygi_struct_foreign_release (GITypeInfo *type_info, gpointer struct_); -void pygi_register_foreign_struct_real (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func); +void pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func); + +PyObject *pygi_require_foreign (PyObject *self, + PyObject *args, + PyObject *kwargs); + +void pygi_foreign_init (void); #endif /* __PYGI_FOREIGN_H__ */ diff --git a/gi/pygi-info.c b/gi/pygi-info.c index 065d470..43ee711 100644 --- a/gi/pygi-info.c +++ b/gi/pygi-info.c @@ -754,6 +754,15 @@ _wrap_g_callable_info_get_return_attribute (PyGIBaseInfo *self, PyObject *py_nam } } +static PyObject * +_wrap_g_callable_info_can_throw_gerror (PyGIBaseInfo *self) +{ + if (g_callable_info_can_throw_gerror (self->info)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + 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 }, @@ -762,11 +771,12 @@ static PyMethodDef _PyGICallableInfo_methods[] = { { "may_return_null", (PyCFunction) _wrap_g_callable_info_may_return_null, METH_NOARGS }, { "skip_return", (PyCFunction) _wrap_g_callable_info_skip_return, METH_NOARGS }, { "get_return_attribute", (PyCFunction) _wrap_g_callable_info_get_return_attribute, METH_O }, + { "can_throw_gerror", (PyCFunction) _wrap_g_callable_info_can_throw_gerror, METH_NOARGS }, { NULL, NULL, 0 } }; /* CallbackInfo */ -PYGLIB_DEFINE_TYPE ("gi.CallbackInfo", PyGICallbackInfo_Type, PyGIBaseInfo); +PYGLIB_DEFINE_TYPE ("gi.CallbackInfo", PyGICallbackInfo_Type, PyGICallableInfo); static PyMethodDef _PyGICallbackInfo_methods[] = { { NULL, NULL, 0 } @@ -2185,7 +2195,7 @@ _pygi_info_register_types (PyObject *m) _PyGI_REGISTER_TYPE (m, PyGIUnresolvedInfo_Type, UnresolvedInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGICallbackInfo_Type, CallbackInfo, - PyGIBaseInfo_Type); + PyGICallableInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIRegisteredTypeInfo_Type, RegisteredTypeInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIStructInfo_Type, StructInfo, diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index 4af2e72..eebf959 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -23,6 +23,7 @@ #include #include "pygi-invoke.h" #include "pygi-marshal-cleanup.h" +#include "pygi-error.h" static inline gboolean _invoke_callable (PyGIInvokeState *state, @@ -46,7 +47,7 @@ _invoke_callable (PyGIInvokeState *state, * state->error allowing for easy checking here. */ if (state->error != NULL) { - if (pyglib_error_check (&(state->error))) { + if (pygi_error_check (&(state->error))) { /* even though we errored out, the call itself was successful, so we assume the call processed all of the parameters */ pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); @@ -308,7 +309,7 @@ _invoke_state_init_from_callable_cache (GIBaseInfo *info, state->function_ptr = g_vfunc_info_get_address ((GIVFuncInfo *)info, state->implementor_gtype, &error); - if (pyglib_error_check (&error)) { + if (pygi_error_check (&error)) { return FALSE; } } diff --git a/gi/pygi-property.c b/gi/pygi-property.c index 6f80506..f7cb032 100644 --- a/gi/pygi-property.c +++ b/gi/pygi-property.c @@ -105,7 +105,7 @@ g_value_get_or_dup_boxed (const GValue *value, GITransfer transfer) } PyObject * -pygi_get_property_value_real (PyGObject *instance, GParamSpec *pspec) +pygi_get_property_value (PyGObject *instance, GParamSpec *pspec) { GIPropertyInfo *property_info = NULL; GValue value = { 0, }; @@ -271,9 +271,9 @@ out: } gint -pygi_set_property_value_real (PyGObject *instance, - GParamSpec *pspec, - PyObject *py_value) +pygi_set_property_value (PyGObject *instance, + GParamSpec *pspec, + PyObject *py_value) { GIPropertyInfo *property_info = NULL; GITypeInfo *type_info = NULL; diff --git a/gi/pygi-property.h b/gi/pygi-property.h index 875d21e..5678bc3 100644 --- a/gi/pygi-property.h +++ b/gi/pygi-property.h @@ -27,13 +27,15 @@ #include #include -#include "pygi.h" +#include "pygobject.h" -PyObject *pygi_get_property_value_real (PyGObject *instance, - GParamSpec *pspec); +PyObject * +pygi_get_property_value (PyGObject *instance, + GParamSpec *pspec); -gint pygi_set_property_value_real (PyGObject *instance, - GParamSpec *pspec, - PyObject *py_value); +gint +pygi_set_property_value (PyGObject *instance, + GParamSpec *pspec, + PyObject *py_value); #endif /* __PYGI_PROPERTY_H__ */ diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c index c5f51af..079669c 100644 --- a/gi/pygi-signal-closure.c +++ b/gi/pygi-signal-closure.c @@ -171,12 +171,12 @@ pygi_signal_closure_marshal(GClosure *closure, } GClosure * -pygi_signal_closure_new_real (PyGObject *instance, - GType g_type, - const gchar *signal_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data) +pygi_signal_closure_new (PyGObject *instance, + GType g_type, + const gchar *signal_name, + PyObject *callback, + PyObject *extra_args, + PyObject *swap_data) { GClosure *closure = NULL; PyGISignalClosure *pygi_closure = NULL; diff --git a/gi/pygi-signal-closure.h b/gi/pygi-signal-closure.h index ffdd29c..5cc191b 100644 --- a/gi/pygi-signal-closure.h +++ b/gi/pygi-signal-closure.h @@ -24,7 +24,7 @@ #ifndef __PYGI_SIGNAL_CLOSURE_H__ #define __PYGI_SIGNAL_CLOSURE_H__ -#include "pygi.h" +#include "pygobject.h" G_BEGIN_DECLS @@ -35,12 +35,13 @@ typedef struct _PyGISignalClosure GISignalInfo *signal_info; } PyGISignalClosure; -GClosure * pygi_signal_closure_new_real (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data); +GClosure * +pygi_signal_closure_new (PyGObject *instance, + GType g_type, + const gchar *sig_name, + PyObject *callback, + PyObject *extra_args, + PyObject *swap_data); G_END_DECLS diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c index 7346eae..9abaaae 100644 --- a/gi/pygi-struct-marshal.c +++ b/gi/pygi-struct-marshal.c @@ -84,7 +84,7 @@ _is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) { * GValue from Python */ -/* _pygi_marshal_from_py_gvalue: +/* pygi_arg_gvalue_from_py_marshal: * py_arg: (in): * arg: (out): * transfer: @@ -92,10 +92,10 @@ _is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) { * when it is already holding a GValue vs. copying the value. */ gboolean -_pygi_marshal_from_py_gvalue (PyObject *py_arg, - GIArgument *arg, - GITransfer transfer, - gboolean copy_reference) { +pygi_arg_gvalue_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + GITransfer transfer, + gboolean copy_reference) { GValue *value; GType object_type; @@ -130,11 +130,11 @@ _pygi_marshal_from_py_gvalue (PyObject *py_arg, } void -_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - PyObject *py_arg, - gpointer data, - gboolean was_processed) +pygi_arg_gvalue_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) { /* Note py_arg can be NULL for hash table which is a bug. */ if (was_processed && py_arg != NULL) { @@ -151,13 +151,13 @@ _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, } } -/* _pygi_marshal_from_py_gclosure: +/* pygi_arg_gclosure_from_py_marshal: * py_arg: (in): * arg: (out): */ gboolean -_pygi_marshal_from_py_gclosure(PyObject *py_arg, - GIArgument *arg) +pygi_arg_gclosure_from_py_marshal (PyObject *py_arg, + GIArgument *arg) { GClosure *closure; GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE); @@ -183,21 +183,21 @@ _pygi_marshal_from_py_gclosure(PyObject *py_arg, return TRUE; } -/* _pygi_marshal_from_py_interface_struct: +/* pygi_arg_struct_from_py_marshal: * * Dispatcher to various sub marshalers */ gboolean -_pygi_marshal_from_py_interface_struct (PyObject *py_arg, - GIArgument *arg, - const gchar *arg_name, - GIBaseInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean copy_reference, - gboolean is_foreign, - gboolean is_pointer) +pygi_arg_struct_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + const gchar *arg_name, + GIBaseInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean copy_reference, + gboolean is_foreign, + gboolean is_pointer) { gboolean is_union = FALSE; @@ -211,12 +211,12 @@ _pygi_marshal_from_py_interface_struct (PyObject *py_arg, */ if (g_type_is_a (g_type, G_TYPE_CLOSURE)) { - return _pygi_marshal_from_py_gclosure (py_arg, arg); + return pygi_arg_gclosure_from_py_marshal (py_arg, arg); } else if (g_type_is_a (g_type, G_TYPE_VALUE)) { - return _pygi_marshal_from_py_gvalue(py_arg, - arg, - transfer, - copy_reference); + return pygi_arg_gvalue_from_py_marshal(py_arg, + arg, + transfer, + copy_reference); } else if (is_foreign) { PyObject *success; success = pygi_struct_foreign_convert_to_g_argument (py_arg, @@ -292,25 +292,25 @@ type_error: } static gboolean -_pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg, - gpointer *cleanup_data) +arg_struct_from_py_marshal_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - 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); + gboolean res = pygi_arg_struct_from_py_marshal (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. @@ -320,27 +320,28 @@ _pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, } static void -_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - PyObject *py_arg, - gpointer data, - gboolean was_processed) +arg_foreign_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) { - if (state->failed && was_processed) + if (state->failed && was_processed) { pygi_struct_foreign_release ( ( (PyGIInterfaceCache *)arg_cache)->interface_info, data); + } } PyObject * -_pygi_marshal_to_py_interface_struct (GIArgument *arg, - GIInterfaceInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign) +pygi_arg_struct_to_py_marshal (GIArgument *arg, + GIInterfaceInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign) { PyObject *py_obj = NULL; @@ -400,89 +401,107 @@ _pygi_marshal_to_py_interface_struct (GIArgument *arg, } static PyObject * -_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) +arg_struct_to_py_marshal_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - return _pygi_marshal_to_py_interface_struct (arg, - iface_cache->interface_info, - iface_cache->g_type, - iface_cache->py_type, - arg_cache->transfer, - arg_cache->is_caller_allocates, - iface_cache->is_foreign); + return pygi_arg_struct_to_py_marshal (arg, + iface_cache->interface_info, + iface_cache->g_type, + iface_cache->py_type, + arg_cache->transfer, + arg_cache->is_caller_allocates, + iface_cache->is_foreign); } static void -_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - PyObject *dummy, - gpointer data, - gboolean was_processed) +arg_foreign_to_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *dummy, + gpointer data, + gboolean was_processed) { - if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) + if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) { pygi_struct_foreign_release ( ( (PyGIInterfaceCache *)arg_cache)->interface_info, data); + } } +static gboolean +arg_type_class_from_py_marshal (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + GType gtype = pyg_type_from_object (py_arg); + + if (G_TYPE_IS_CLASSED (gtype)) { + arg->v_pointer = g_type_class_ref (gtype); + *cleanup_data = arg->v_pointer; + return TRUE; + } else { + PyErr_Format (PyExc_TypeError, + "Unable to retrieve a GObject type class from \"%s\".", + Py_TYPE(py_arg)->tp_name); + return FALSE; + } +} static void -_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) +arg_type_class_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) { - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter; - - if (iface_cache->g_type == G_TYPE_VALUE) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue; - else if (iface_cache->is_foreign) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign; + if (was_processed) { + g_type_class_unref (data); + } } static void -_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) +arg_struct_from_py_setup (PyGIArgCache *arg_cache, + GIInterfaceInfo *iface_info, + GITransfer transfer) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter; - if (iface_cache->is_foreign) - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign; -} + if (g_struct_info_is_gtype_struct ((GIStructInfo*)iface_info)) { + arg_cache->from_py_marshaller = arg_type_class_from_py_marshal; + /* Since we always add a ref in the marshalling, only unref the + * GTypeClass when we don't transfer ownership. */ + if (transfer == GI_TRANSFER_NOTHING) { + arg_cache->from_py_cleanup = arg_type_class_from_py_cleanup; + } -static gboolean -pygi_arg_struct_setup_from_info (PyGIArgCache *arg_cache, - GITypeInfo *type_info, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - GIInterfaceInfo *iface_info) -{ - /* NOTE: usage of pygi_arg_interface_new_from_info already calls - * pygi_arg_interface_setup so no need to do it here. - */ + } else { + arg_cache->from_py_marshaller = arg_struct_from_py_marshal_adapter; - if (direction & PYGI_DIRECTION_FROM_PYTHON) { - _arg_cache_from_py_interface_struct_setup (arg_cache, - iface_info, - transfer); + if (iface_cache->g_type == G_TYPE_VALUE) + arg_cache->from_py_cleanup = pygi_arg_gvalue_from_py_cleanup; + else if (iface_cache->is_foreign) + arg_cache->from_py_cleanup = arg_foreign_from_py_cleanup; } +} - if (direction & PYGI_DIRECTION_TO_PYTHON) { - _arg_cache_to_py_interface_struct_setup (arg_cache, - iface_info, - transfer); - } +static void +arg_struct_to_py_setup (PyGIArgCache *arg_cache, + GIInterfaceInfo *iface_info, + GITransfer transfer) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); + arg_cache->to_py_marshaller = arg_struct_to_py_marshal_adapter; - return TRUE; + if (iface_cache->is_foreign) + arg_cache->to_py_cleanup = arg_foreign_to_py_cleanup; } PyGIArgCache * @@ -492,7 +511,6 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info, PyGIDirection direction, GIInterfaceInfo *iface_info) { - gboolean res = FALSE; PyGIArgCache *cache = NULL; cache = pygi_arg_interface_new_from_info (type_info, @@ -503,16 +521,13 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info, if (cache == NULL) return NULL; - res = pygi_arg_struct_setup_from_info (cache, - type_info, - arg_info, - transfer, - direction, - iface_info); - if (res) { - return cache; - } else { - pygi_arg_cache_free (cache); - return NULL; + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_struct_from_py_setup (cache, iface_info, transfer); } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + arg_struct_to_py_setup (cache, iface_info, transfer); + } + + return cache; } diff --git a/gi/pygi-struct-marshal.h b/gi/pygi-struct-marshal.h index 66e3ecf..6a7f92d 100644 --- a/gi/pygi-struct-marshal.h +++ b/gi/pygi-struct-marshal.h @@ -33,40 +33,40 @@ PyGIArgCache *pygi_arg_struct_new_from_info (GITypeInfo *type_info, GIInterfaceInfo *iface_info); -gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer, - gboolean is_allocated); +gboolean pygi_arg_gvalue_from_py_marshal (PyObject *py_arg, /*in*/ + GIArgument *arg, /*out*/ + GITransfer transfer, + gboolean is_allocated); -gboolean _pygi_marshal_from_py_gclosure(PyObject *py_arg, /*in*/ - GIArgument *arg); /*out*/ +gboolean pygi_arg_gclosure_from_py_marshal (PyObject *py_arg, /*in*/ + GIArgument *arg); /*out*/ -gboolean _pygi_marshal_from_py_interface_struct (PyObject *py_arg, - GIArgument *arg, - const gchar *arg_name, - GIBaseInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign, - gboolean is_pointer); +gboolean pygi_arg_struct_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + const gchar *arg_name, + GIBaseInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign, + gboolean is_pointer); -PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg, - GIInterfaceInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign); +PyObject *pygi_arg_struct_to_py_marshal (GIArgument *arg, + GIInterfaceInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign); /* Needed for hack in pygi-arg-garray.c */ -void _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - PyObject *py_arg, - gpointer data, - gboolean was_processed); +void pygi_arg_gvalue_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed); G_END_DECLS diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c index b1db8a4..692068b 100644 --- a/gi/pygi-struct.c +++ b/gi/pygi-struct.c @@ -60,9 +60,9 @@ _struct_dealloc (PyGIStruct *self) GIBaseInfo *info = _struct_get_info ( (PyObject *) self ); if (info != NULL && g_struct_info_is_foreign ( (GIStructInfo *) info)) { - pygi_struct_foreign_release (info, ( (PyGPointer *) self)->pointer); + pygi_struct_foreign_release (info, pyg_pointer_get_ptr (self)); } else if (self->free_on_dealloc) { - g_free ( ( (PyGPointer *) self)->pointer); + g_free (pyg_pointer_get_ptr (self)); } if (info != NULL) { @@ -152,8 +152,8 @@ _pygi_struct_new (PyTypeObject *type, g_type = pyg_type_from_object ( (PyObject *) type); + pyg_pointer_set_ptr (self, pointer); ( (PyGPointer *) self)->gtype = g_type; - ( (PyGPointer *) self)->pointer = pointer; self->free_on_dealloc = free_on_dealloc; return (PyObject *) self; diff --git a/gi/pygi-type.c b/gi/pygi-type.c index b8d4c65..924e0b8 100644 --- a/gi/pygi-type.c +++ b/gi/pygi-type.c @@ -50,7 +50,7 @@ _pygi_type_import_by_name (const char *namespace_, } PyObject * -pygi_type_import_by_g_type_real (GType g_type) +pygi_type_import_by_g_type (GType g_type) { GIRepository *repository; GIBaseInfo *info; @@ -89,7 +89,7 @@ _pygi_type_get_from_g_type (GType g_type) py_type = PyObject_GetAttrString (py_g_type, "pytype"); if (py_type == Py_None) { - py_type = pygi_type_import_by_g_type_real (g_type); + py_type = pygi_type_import_by_g_type (g_type); } Py_DECREF (py_g_type); diff --git a/gi/pygi-type.h b/gi/pygi-type.h index 822a441..85f7551 100644 --- a/gi/pygi-type.h +++ b/gi/pygi-type.h @@ -21,12 +21,13 @@ #define __PYGI_TYPE_H__ #include +#include G_BEGIN_DECLS /* Public */ -PyObject *pygi_type_import_by_g_type_real (GType g_type); +PyObject *pygi_type_import_by_g_type (GType g_type); /* Private */ diff --git a/gi/pygi-value.c b/gi/pygi-value.c index 8235116..f54f8e1 100644 --- a/gi/pygi-value.c +++ b/gi/pygi-value.c @@ -555,7 +555,7 @@ pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj) * GObject.ParamSpec */ if (G_IS_PARAM_SPEC (pygobject_get (obj))) g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj))); - else if (PyGParamSpec_Check(obj)) + else if (pyg_param_spec_check (obj)) g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL)); else { PyErr_SetString(PyExc_TypeError, "Expected ParamSpec"); diff --git a/gi/pygi.h b/gi/pygi.h index a67696e..2a9ee14 100644 --- a/gi/pygi.h +++ b/gi/pygi.h @@ -78,112 +78,5 @@ typedef struct { PyGICallableCache *cache; } PyGICCallback; -typedef PyObject * (*PyGIArgOverrideToGIArgumentFunc) (PyObject *value, - GIInterfaceInfo *interface_info, - GITransfer transfer, - GIArgument *arg); -typedef PyObject * (*PyGIArgOverrideFromGIArgumentFunc) (GIInterfaceInfo *interface_info, - GITransfer transfer, - gpointer data); -typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info, - gpointer struct_); - -struct PyGI_API { - PyObject* (*type_import_by_g_type) (GType g_type); - PyObject* (*get_property_value) (PyGObject *instance, - GParamSpec *pspec); - gint (*set_property_value) (PyGObject *instance, - GParamSpec *pspec, - PyObject *value); - GClosure * (*signal_closure_new) (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data); - void (*register_foreign_struct) (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func); -}; - -static struct PyGI_API *PyGI_API = NULL; - -static int -_pygi_import (void) -{ - if (PyGI_API != NULL) { - return 1; - } - PyGI_API = (struct PyGI_API*) PyCapsule_Import("gi._API", FALSE); - if (PyGI_API == NULL) { - return -1; - } - - return 0; -} - -static inline PyObject * -pygi_type_import_by_g_type (GType g_type) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->type_import_by_g_type(g_type); -} - -static inline PyObject * -pygi_get_property_value (PyGObject *instance, - GParamSpec *pspec) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->get_property_value(instance, pspec); -} - -static inline gint -pygi_set_property_value (PyGObject *instance, - GParamSpec *pspec, - PyObject *value) -{ - if (_pygi_import() < 0) { - return -1; - } - return PyGI_API->set_property_value(instance, pspec, value); -} - -static inline GClosure * -pygi_signal_closure_new (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->signal_closure_new(instance, g_type, sig_name, callback, extra_args, swap_data); -} - -static inline PyObject * -pygi_register_foreign_struct (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func) -{ - if (_pygi_import() < 0) { - return NULL; - } - PyGI_API->register_foreign_struct(namespace_, - name, - to_func, - from_func, - release_func); - Py_RETURN_NONE; -} #endif /* __PYGI_H__ */ diff --git a/gi/pyglib-private.h b/gi/pyglib-private.h index 3569c6b..78dd489 100644 --- a/gi/pyglib-private.h +++ b/gi/pyglib-private.h @@ -31,7 +31,6 @@ G_BEGIN_DECLS gboolean _pyglib_handler_marshal(gpointer user_data); void _pyglib_destroy_notify(gpointer user_data); -extern PyObject *PyGError; extern PyObject *pyglib__glib_module_create (void); G_END_DECLS diff --git a/gi/pyglib.c b/gi/pyglib.c index 6c52f31..8db9b17 100644 --- a/gi/pyglib.c +++ b/gi/pyglib.c @@ -28,205 +28,6 @@ #include "pygoptioncontext.h" #include "pygoptiongroup.h" -static PyObject *exception_table = NULL; - -/** - * pyglib_error_marshal: - * @error: a pointer to the GError. - * - * Checks to see if @error has been set. If @error has been set, then a - * GLib.GError Python exception object is returned (but not raised). - * - * Returns: a GLib.GError Python exception object, or NULL. - */ -PyObject * -pyglib_error_marshal (GError **error) -{ - PyGILState_STATE state; - PyObject *exc_type; - PyObject *exc_instance; - PyObject *d; - - g_return_val_if_fail(error != NULL, NULL); - - if (*error == NULL) - return NULL; - - state = pyglib_gil_state_ensure(); - - exc_type = PyGError; - if (exception_table != NULL) - { - PyObject *item; - item = PyDict_GetItem(exception_table, PYGLIB_PyLong_FromLong((*error)->domain)); - if (item != NULL) - exc_type = item; - } - - exc_instance = PyObject_CallFunction(exc_type, "z", (*error)->message); - - if ((*error)->domain) { - PyObject_SetAttrString(exc_instance, "domain", - d=PYGLIB_PyUnicode_FromString(g_quark_to_string((*error)->domain))); - Py_DECREF(d); - } - else - PyObject_SetAttrString(exc_instance, "domain", Py_None); - - PyObject_SetAttrString(exc_instance, "code", - d=PYGLIB_PyLong_FromLong((*error)->code)); - Py_DECREF(d); - - if ((*error)->message) { - PyObject_SetAttrString(exc_instance, "message", - d=PYGLIB_PyUnicode_FromString((*error)->message)); - Py_DECREF(d); - } else { - PyObject_SetAttrString(exc_instance, "message", Py_None); - } - - pyglib_gil_state_release(state); - - return exc_instance; -} - -/** - * pyglib_error_check: - * @error: a pointer to the GError. - * - * Checks to see if the GError has been set. If the error has been - * set, then the glib.GError Python exception will be raised, and - * the GError cleared. - * - * Returns: True if an error was set. - */ -gboolean -pyglib_error_check(GError **error) -{ - PyGILState_STATE state; - PyObject *exc_instance; - - g_return_val_if_fail(error != NULL, FALSE); - if (*error == NULL) - return FALSE; - - state = pyglib_gil_state_ensure(); - - exc_instance = pyglib_error_marshal (error); - PyErr_SetObject(PyGError, exc_instance); - Py_DECREF(exc_instance); - g_clear_error(error); - - pyglib_gil_state_release(state); - - return TRUE; -} - -/** - * pyglib_gerror_exception_check: - * @error: a standard GLib GError ** output parameter - * - * Checks to see if a GError exception has been raised, and if so - * translates the python exception to a standard GLib GError. If the - * raised exception is not a GError then PyErr_Print() is called. - * - * Returns: 0 if no exception has been raised, -1 if it is a - * valid glib.GError, -2 otherwise. - */ -gboolean -pyglib_gerror_exception_check(GError **error) -{ - PyObject *type, *value, *traceback; - PyObject *py_message, *py_domain, *py_code; - const char *bad_gerror_message; - - PyErr_Fetch(&type, &value, &traceback); - if (type == NULL) - return 0; - PyErr_NormalizeException(&type, &value, &traceback); - if (value == NULL) { - PyErr_Restore(type, value, traceback); - PyErr_Print(); - return -2; - } - if (!value || - !PyErr_GivenExceptionMatches(type, - (PyObject *) PyGError)) { - PyErr_Restore(type, value, traceback); - PyErr_Print(); - return -2; - } - Py_DECREF(type); - Py_XDECREF(traceback); - - py_message = PyObject_GetAttrString(value, "message"); - if (!py_message || !PYGLIB_PyUnicode_Check(py_message)) { - bad_gerror_message = "gi._glib.GError instances must have a 'message' string attribute"; - Py_XDECREF(py_message); - goto bad_gerror; - } - - py_domain = PyObject_GetAttrString(value, "domain"); - if (!py_domain || !PYGLIB_PyUnicode_Check(py_domain)) { - bad_gerror_message = "gi._glib.GError instances must have a 'domain' string attribute"; - Py_DECREF(py_message); - Py_XDECREF(py_domain); - goto bad_gerror; - } - - py_code = PyObject_GetAttrString(value, "code"); - if (!py_code || !PYGLIB_PyLong_Check(py_code)) { - bad_gerror_message = "gi._glib.GError instances must have a 'code' int attribute"; - Py_DECREF(py_message); - Py_DECREF(py_domain); - Py_XDECREF(py_code); - goto bad_gerror; - } - - g_set_error(error, g_quark_from_string(PYGLIB_PyUnicode_AsString(py_domain)), - PYGLIB_PyLong_AsLong(py_code), "%s", PYGLIB_PyUnicode_AsString(py_message)); - - Py_DECREF(py_message); - Py_DECREF(py_code); - Py_DECREF(py_domain); - return -1; - -bad_gerror: - Py_DECREF(value); - g_set_error(error, g_quark_from_static_string("pyglib"), 0, "%s", bad_gerror_message); - PyErr_SetString(PyExc_ValueError, bad_gerror_message); - PyErr_Print(); - return -2; -} - -/** - * pyglib_register_exception_for_domain: - * @name: name of the exception - * @error_domain: error domain - * - * Registers a new glib.GError exception subclass called #name for - * a specific #domain. This exception will be raised when a GError - * of the same domain is passed in to pyglib_error_check(). - * - * Returns: the new exception - */ -PyObject * -pyglib_register_exception_for_domain(gchar *name, - gint error_domain) -{ - PyObject *exception; - - exception = PyErr_NewException(name, PyGError, NULL); - - if (exception_table == NULL) - exception_table = PyDict_New(); - - PyDict_SetItem(exception_table, - PYGLIB_PyLong_FromLong(error_domain), - exception); - - return exception; -} /** * pyg_option_group_transfer_group: diff --git a/gi/pyglib.h b/gi/pyglib.h index 544bada..00228dd 100644 --- a/gi/pyglib.h +++ b/gi/pyglib.h @@ -37,11 +37,6 @@ typedef void (*PyGLibThreadBlockFunc) (void); # define pyglib_gil_state_release PyGILState_Release #endif -gboolean pyglib_error_check(GError **error); -PyObject *pyglib_error_marshal (GError **error); -gboolean pyglib_gerror_exception_check(GError **error); -PyObject *pyglib_register_exception_for_domain(gchar *name, - gint error_domain); GOptionGroup * pyglib_option_group_transfer_group(PyObject *self); /* Private: for gobject <-> glib interaction only. */ diff --git a/gi/pygobject-private.h b/gi/pygobject-private.h index be565d6..b6242cd 100644 --- a/gi/pygobject-private.h +++ b/gi/pygobject-private.h @@ -53,7 +53,6 @@ extern GQuark pygobject_custom_key; void pygobject_data_free (PyGObjectData *data); void pyg_destroy_notify (gpointer user_data); gboolean pyg_handler_marshal (gpointer user_data); -gboolean pyg_error_check (GError **error); int pygobject_constructv (PyGObject *self, guint n_parameters, GParameter *parameters); @@ -62,8 +61,6 @@ PyObject *pyg_integer_richcompare(PyObject *v, PyObject *w, int op); -gboolean pyg_gerror_exception_check(GError **error); - void pygobject_ref_float(PyGObject *self); void pygobject_ref_sink(PyGObject *self); diff --git a/gi/pygobject.c b/gi/pygobject.c index 04fd6a5..1a011e1 100644 --- a/gi/pygobject.c +++ b/gi/pygobject.c @@ -29,6 +29,9 @@ #include "pygi.h" #include "pygi-value.h" +#include "pygi-type.h" +#include "pygi-property.h" +#include "pygi-signal-closure.h" static void pygobject_dealloc(PyGObject *self); static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); diff --git a/gi/pygobject.h b/gi/pygobject.h index 76b8b11..85359a5 100644 --- a/gi/pygobject.h +++ b/gi/pygobject.h @@ -57,6 +57,8 @@ typedef struct { } PyGBoxed; #define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) +#define pyg_boxed_get_ptr(v) (((PyGBoxed *)(v))->boxed) +#define pyg_boxed_set_ptr(v,p) (((PyGBoxed *)(v))->boxed = (gpointer)p) #define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) typedef struct { @@ -66,6 +68,8 @@ typedef struct { } PyGPointer; #define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) +#define pyg_pointer_get_ptr(v) (((PyGPointer *)(v))->pointer) +#define pyg_pointer_set_ptr(v,p) (((PyGPointer *)(v))->pointer = (gpointer)p) #define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) typedef void (*PyGFatalExceptionFunc) (void); @@ -76,8 +80,13 @@ typedef struct { GParamSpec *pspec; } PyGParamSpec; -#define PyGParamSpec_Get(v) (((PyGParamSpec *)v)->pspec) -#define PyGParamSpec_Check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) +#define pyg_param_spec_get(v) (((PyGParamSpec *)v)->pspec) +#define pyg_param_spec_set(v,p) (((PyGParamSpec *)v)->pspec = (GParamSpec*)p) +#define pyg_param_spec_check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) + +/* Deprecated in favor of lower case with underscore macros above. */ +#define PyGParamSpec_Get pyg_param_spec_get +#define PyGParamSpec_Check pyg_param_spec_check typedef int (*PyGClassInitFunc) (gpointer gclass, PyTypeObject *pyclass); typedef PyTypeObject * (*PyGTypeRegistrationFunction) (const gchar *name, diff --git a/gi/pygoptioncontext.c b/gi/pygoptioncontext.c index f6bb223..ab439f0 100644 --- a/gi/pygoptioncontext.c +++ b/gi/pygoptioncontext.c @@ -25,6 +25,7 @@ #include #include "pyglib-private.h" #include "pygoptioncontext.h" +#include "pygi-error.h" PYGLIB_DEFINE_TYPE("gi._glib.OptionContext", PyGOptionContext_Type, PyGOptionContext) @@ -138,7 +139,7 @@ pyg_option_context_parse(PyGOptionContext *self, { g_strfreev(argv_content); g_strfreev(original); - pyglib_error_check(&error); + pygi_error_check(&error); return NULL; } diff --git a/gi/pygoptiongroup.c b/gi/pygoptiongroup.c index 613232f..4c1664d 100644 --- a/gi/pygoptiongroup.c +++ b/gi/pygoptiongroup.c @@ -25,6 +25,7 @@ #include #include "pyglib-private.h" #include "pygoptiongroup.h" +#include "pygi-error.h" PYGLIB_DEFINE_TYPE("gi._glib.OptionGroup", PyGOptionGroup_Type, PyGOptionGroup) @@ -148,7 +149,7 @@ arg_func(const gchar *option_name, Py_DECREF(ret); no_error = TRUE; } else - no_error = pyglib_gerror_exception_check(error) != -1; + no_error = pygi_gerror_exception_check(error) != -1; pyglib_gil_state_release(state); return no_error; diff --git a/gi/pygparamspec.c b/gi/pygparamspec.c index 9e6c467..ff53243 100644 --- a/gi/pygparamspec.c +++ b/gi/pygparamspec.c @@ -34,9 +34,9 @@ static PyObject* pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGParamSpec_Type) - return _pyglib_generic_ptr_richcompare(((PyGParamSpec*)self)->pspec, - ((PyGParamSpec*)other)->pspec, - op); + return _pyglib_generic_ptr_richcompare (pyg_param_spec_get (self), + pyg_param_spec_get (other), + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -46,7 +46,7 @@ pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) static long pyg_param_spec_hash(PyGParamSpec *self) { - return (long)self->pspec; + return (long)pyg_param_spec_get (self); } static PyObject * @@ -55,15 +55,15 @@ pyg_param_spec_repr(PyGParamSpec *self) char buf[80]; g_snprintf(buf, sizeof(buf), "<%s '%s'>", - G_PARAM_SPEC_TYPE_NAME(self->pspec), - g_param_spec_get_name(self->pspec)); + G_PARAM_SPEC_TYPE_NAME (pyg_param_spec_get (self)), + g_param_spec_get_name (pyg_param_spec_get (self))); return PYGLIB_PyUnicode_FromString(buf); } static void pyg_param_spec_dealloc(PyGParamSpec *self) { - g_param_spec_unref(self->pspec); + g_param_spec_unref (pyg_param_spec_get (self)); PyObject_DEL(self); } @@ -112,8 +112,8 @@ pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) { GParamSpec *pspec; - pspec = self->pspec; - + pspec = pyg_param_spec_get (self); + /* common attributes */ if (!strcmp(attr, "__gtype__")) { return pyg_type_wrapper_new(G_PARAM_SPEC_TYPE(pspec)); @@ -281,7 +281,7 @@ pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) static PyObject * pyg_param_spec_dir(PyGParamSpec *self, PyObject *dummy) { - GParamSpec *pspec = self->pspec; + GParamSpec *pspec = pyg_param_spec_get (self); if (G_IS_PARAM_SPEC_CHAR(pspec)) { return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", @@ -393,7 +393,7 @@ pyg_param_spec_new(GParamSpec *pspec) if (self == NULL) return NULL; - self->pspec = g_param_spec_ref(pspec); + pyg_param_spec_set (self, g_param_spec_ref (pspec)); return (PyObject *)self; } diff --git a/gi/pygpointer.c b/gi/pygpointer.c index 2729695..d728a40 100644 --- a/gi/pygpointer.c +++ b/gi/pygpointer.c @@ -27,6 +27,7 @@ #include "pygpointer.h" #include "pygi.h" +#include "pygi-type.h" GQuark pygpointer_class_key; @@ -43,9 +44,9 @@ static PyObject* pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other)) - return _pyglib_generic_ptr_richcompare(((PyGPointer*)self)->pointer, - ((PyGPointer*)other)->pointer, - op); + return _pyglib_generic_ptr_richcompare (pyg_pointer_get_ptr (self), + pyg_pointer_get_ptr (other), + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -55,7 +56,7 @@ pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) static long pyg_pointer_hash(PyGPointer *self) { - return (long)self->pointer; + return (long)pyg_pointer_get_ptr (self); } static PyObject * @@ -64,7 +65,7 @@ pyg_pointer_repr(PyGPointer *self) gchar buf[128]; g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->pointer); + (long)pyg_pointer_get_ptr (self)); return PYGLIB_PyUnicode_FromString(buf); } @@ -76,7 +77,7 @@ pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs) if (!PyArg_ParseTuple(args, ":GPointer.__init__")) return -1; - self->pointer = NULL; + pyg_pointer_set_ptr (self, NULL); self->gtype = 0; g_snprintf(buf, sizeof(buf), "%s can not be constructed", @@ -174,7 +175,7 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) if (self == NULL) return NULL; - self->pointer = pointer; + pyg_pointer_set_ptr (self, pointer); self->gtype = pointer_type; return (PyObject *)self; diff --git a/gi/pygspawn.c b/gi/pygspawn.c index 8f3ff51..3851ad9 100644 --- a/gi/pygspawn.c +++ b/gi/pygspawn.c @@ -26,6 +26,7 @@ #include "pyglib-private.h" #include "pygspawn.h" +#include "pygi-error.h" struct _PyGChildSetupData { PyObject *func; @@ -214,7 +215,7 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) Py_XDECREF(callback_data->data); g_slice_free(struct _PyGChildSetupData, callback_data); } - pyglib_error_check(&error); + pygi_error_check(&error); return NULL; } g_free(argv); diff --git a/gi/pygtype.c b/gi/pygtype.c index 131a271..985e969 100644 --- a/gi/pygtype.c +++ b/gi/pygtype.c @@ -28,6 +28,7 @@ #include "pygparamspec.h" #include "pygtype.h" +#include "pygi-type.h" #include "pygi-value.h" /* -------------- __gtype__ objects ---------------------------- */ @@ -621,6 +622,7 @@ pyg_type_lookup(GType type) /* recursively lookup types */ while (ptype) { + pygi_type_import_by_g_type (ptype); if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL) break; ptype = g_type_parent(ptype); @@ -888,7 +890,8 @@ pyg_signal_class_closure_marshal(GClosure *closure, && item->ob_refcnt != 1) { PyGBoxed* boxed_item = (PyGBoxed*)item; if (!boxed_item->free_on_dealloc) { - boxed_item->boxed = g_boxed_copy(boxed_item->gtype, boxed_item->boxed); + gpointer boxed_ptr = pyg_boxed_get_ptr (boxed_item); + pyg_boxed_set_ptr (boxed_item, g_boxed_copy (boxed_item->gtype, boxed_ptr)); boxed_item->free_on_dealloc = TRUE; } } diff --git a/gi/types.py b/gi/types.py index e6e3903..aa5bcb4 100644 --- a/gi/types.py +++ b/gi/types.py @@ -55,6 +55,17 @@ class MetaClassHelper(object): for method_info in cls.__info__.get_methods(): setattr(cls, method_info.__name__, method_info) + def _setup_class_methods(cls): + info = cls.__info__ + class_struct = info.get_class_struct() + if class_struct is None: + return + for method_info in class_struct.get_methods(): + name = method_info.__name__ + # Don't mask regular methods or base class methods with TypeClass methods. + if not hasattr(cls, name): + setattr(cls, name, classmethod(method_info)) + def _setup_fields(cls): for field_info in cls.__info__.get_fields(): name = field_info.get_name().replace('-', '_') @@ -182,7 +193,7 @@ class _GObjectMetaBase(type): cls._type_register(cls.__dict__) def _type_register(cls, namespace): - ## don't register the class if already registered + # don't register the class if already registered if '__gtype__' in namespace: return @@ -211,6 +222,8 @@ class GObjectMeta(_GObjectMetaBase, MetaClassHelper): if is_python_defined: cls._setup_vfuncs() elif is_gi_defined: + if isinstance(cls.__info__, ObjectInfo): + cls._setup_class_methods() cls._setup_methods() cls._setup_constants() cls._setup_native_vfuncs() diff --git a/pygtkcompat/pygtkcompat.py b/pygtkcompat/pygtkcompat.py index d5b7b94..7ee2de4 100644 --- a/pygtkcompat/pygtkcompat.py +++ b/pygtkcompat/pygtkcompat.py @@ -38,8 +38,10 @@ import warnings try: # Python 3 from collections import UserList - from imp import reload UserList # pyflakes + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + from imp import reload except ImportError: # Python 2 ships that in a different module from UserList import UserList @@ -357,10 +359,10 @@ def enable_gtk(version='3.0'): except AttributeError: pass - #AccelGroup + # AccelGroup Gtk.AccelGroup.connect_group = Gtk.AccelGroup.connect - #StatusIcon + # StatusIcon Gtk.status_icon_position_menu = Gtk.StatusIcon.position_menu Gtk.StatusIcon.set_tooltip = Gtk.StatusIcon.set_tooltip_text diff --git a/tests/Makefile.am b/tests/Makefile.am index 3468740..c0f34f8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -84,6 +84,8 @@ EXTRA_DIST = \ test-unknown.h \ te_ST@nouppera \ org.gnome.test.gschema.xml \ + test_cairo.py \ + test_error.py \ test_gio.py \ test_glib.py \ test_gobject.py \ @@ -99,6 +101,7 @@ EXTRA_DIST = \ test_source.py \ test_subprocess.py \ test_thread.py \ + test_typeclass.py \ test_everything.py \ test_gi.py \ test_gdbus.py \ diff --git a/tests/Makefile.in b/tests/Makefile.in index 5b94b34..cdadc6f 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -382,6 +382,8 @@ EXTRA_DIST = \ test-unknown.h \ te_ST@nouppera \ org.gnome.test.gschema.xml \ + test_cairo.py \ + test_error.py \ test_gio.py \ test_glib.py \ test_gobject.py \ @@ -397,6 +399,7 @@ EXTRA_DIST = \ test_source.py \ test_subprocess.py \ test_thread.py \ + test_typeclass.py \ test_everything.py \ test_gi.py \ test_gdbus.py \ diff --git a/tests/test_cairo.py b/tests/test_cairo.py new file mode 100644 index 0000000..fdf86a2 --- /dev/null +++ b/tests/test_cairo.py @@ -0,0 +1,141 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# coding=utf-8 +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest + +import gi + +try: + gi.require_foreign('cairo') + import cairo + from gi.repository import Regress + has_cairo = True +except ImportError: + has_cairo = False + +try: + from gi.repository import Gtk + Gtk # pyflakes +except: + Gtk = None + +from gi.repository import GObject + + +@unittest.skipUnless(has_cairo, 'built without cairo support') +class Test(unittest.TestCase): + def test_cairo_context(self): + context = Regress.test_cairo_context_full_return() + self.assertTrue(isinstance(context, cairo.Context)) + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) + context = cairo.Context(surface) + Regress.test_cairo_context_none_in(context) + + def test_cairo_surface(self): + surface = Regress.test_cairo_surface_none_return() + self.assertTrue(isinstance(surface, cairo.ImageSurface)) + self.assertTrue(isinstance(surface, cairo.Surface)) + self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) + self.assertEqual(surface.get_width(), 10) + self.assertEqual(surface.get_height(), 10) + + surface = Regress.test_cairo_surface_full_return() + self.assertTrue(isinstance(surface, cairo.ImageSurface)) + self.assertTrue(isinstance(surface, cairo.Surface)) + self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) + self.assertEqual(surface.get_width(), 10) + self.assertEqual(surface.get_height(), 10) + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) + Regress.test_cairo_surface_none_in(surface) + + surface = Regress.test_cairo_surface_full_out() + self.assertTrue(isinstance(surface, cairo.ImageSurface)) + self.assertTrue(isinstance(surface, cairo.Surface)) + self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) + self.assertEqual(surface.get_width(), 10) + self.assertEqual(surface.get_height(), 10) + + def test_require_foreign(self): + self.assertEqual(gi.require_foreign('cairo'), None) + self.assertEqual(gi.require_foreign('cairo', 'Context'), None) + self.assertRaises(ImportError, gi.require_foreign, 'invalid_module') + self.assertRaises(ImportError, gi.require_foreign, 'invalid_module', 'invalid_symbol') + self.assertRaises(ImportError, gi.require_foreign, 'cairo', 'invalid_symbol') + + +@unittest.skipUnless(has_cairo, 'built without cairo support') +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestPango(unittest.TestCase): + def test_cairo_font_options(self): + screen = Gtk.Window().get_screen() + font_opts = screen.get_font_options() + self.assertEqual(type(font_opts.get_subpixel_order()), int) + + +if has_cairo: + from gi.repository import cairo as CairoGObject + + # Use PyGI signals to test non-introspected foreign marshaling. + class CairoSignalTester(GObject.Object): + sig_context = GObject.Signal(arg_types=[CairoGObject.Context]) + sig_surface = GObject.Signal(arg_types=[CairoGObject.Surface]) + sig_font_face = GObject.Signal(arg_types=[CairoGObject.FontFace]) + sig_scaled_font = GObject.Signal(arg_types=[CairoGObject.ScaledFont]) + sig_pattern = GObject.Signal(arg_types=[CairoGObject.Pattern]) + + +@unittest.skipUnless(has_cairo, 'built without cairo support') +class TestSignalMarshaling(unittest.TestCase): + # Tests round tripping of cairo objects through non-introspected signals. + + def setUp(self): + self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) + self.context = cairo.Context(self.surface) + self.tester = CairoSignalTester() + + def pass_object_through_signal(self, obj, signal): + """Pass the given `obj` through the `signal` emission storing the + `obj` passed through the signal and returning it.""" + passthrough_result = [] + + def callback(instance, passthrough): + passthrough_result.append(passthrough) + + signal.connect(callback) + signal.emit(obj) + + return passthrough_result[0] + + def test_context(self): + result = self.pass_object_through_signal(self.context, self.tester.sig_context) + self.assertTrue(isinstance(result, cairo.Context)) + + def test_surface(self): + result = self.pass_object_through_signal(self.surface, self.tester.sig_surface) + self.assertTrue(isinstance(result, cairo.Surface)) + + def test_font_face(self): + font_face = self.context.get_font_face() + result = self.pass_object_through_signal(font_face, self.tester.sig_font_face) + self.assertTrue(isinstance(result, cairo.FontFace)) + + def test_scaled_font(self): + scaled_font = cairo.ScaledFont(self.context.get_font_face(), + cairo.Matrix(), + cairo.Matrix(), + self.context.get_font_options()) + result = self.pass_object_through_signal(scaled_font, self.tester.sig_scaled_font) + self.assertTrue(isinstance(result, cairo.ScaledFont)) + + def test_pattern(self): + pattern = cairo.SolidPattern(1, 1, 1, 1) + result = self.pass_object_through_signal(pattern, self.tester.sig_pattern) + self.assertTrue(isinstance(result, cairo.Pattern)) + self.assertTrue(isinstance(result, cairo.SolidPattern)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_error.py b/tests/test_error.py new file mode 100644 index 0000000..baccef5 --- /dev/null +++ b/tests/test_error.py @@ -0,0 +1,116 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# test_error.py: Tests for GError wrapper implementation +# +# Copyright (C) 2012 Will Thompson +# Copyright (C) 2013 Martin Pitt +# Copyright (C) 2014 Simon Feltman +# +# 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 + +from gi.repository import GLib +from gi.repository import GIMarshallingTests + + +class TestType(unittest.TestCase): + def test_attributes(self): + e = GLib.Error('test message', 'mydomain', 42) + self.assertEqual(e.message, 'test message') + self.assertEqual(e.domain, 'mydomain') + self.assertEqual(e.code, 42) + + def test_new_literal(self): + mydomain = GLib.quark_from_string('mydomain') + e = GLib.Error.new_literal(mydomain, 'test message', 42) + self.assertEqual(e.message, 'test message') + self.assertEqual(e.domain, 'mydomain') + self.assertEqual(e.code, 42) + + def test_matches(self): + mydomain = GLib.quark_from_string('mydomain') + notmydomain = GLib.quark_from_string('notmydomain') + e = GLib.Error('test message', 'mydomain', 42) + self.assertTrue(e.matches(mydomain, 42)) + self.assertFalse(e.matches(notmydomain, 42)) + self.assertFalse(e.matches(mydomain, 40)) + + def test_str(self): + e = GLib.Error('test message', 'mydomain', 42) + self.assertEqual(str(e), + 'mydomain: test message (42)') + + def test_repr(self): + e = GLib.Error('test message', 'mydomain', 42) + self.assertEqual(repr(e), + "GLib.Error('test message', 'mydomain', 42)") + + def test_inheritance(self): + self.assertTrue(issubclass(GLib.Error, RuntimeError)) + + +class TestMarshalling(unittest.TestCase): + def test_array_in_crash(self): + # Previously there was a bug in invoke, in which C arrays were unwrapped + # from inside GArrays to be passed to the C function. But when a GError was + # set, invoke would attempt to free the C array as if it were a GArray. + # This crash is only for C arrays. It does not happen for C functions which + # take in GArrays. See https://bugzilla.gnome.org/show_bug.cgi?id=642708 + self.assertRaises(GLib.Error, GIMarshallingTests.gerror_array_in, [1, 2, 3]) + + def test_out(self): + # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 + error, debug = GIMarshallingTests.gerror_out() + + self.assertIsInstance(error, GLib.Error) + self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) + self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) + self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + self.assertEqual(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE) + + def test_out_transfer_none(self): + # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 + error, debug = GIMarshallingTests.gerror_out_transfer_none() + + self.assertIsInstance(error, GLib.Error) + self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) + self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) + self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + self.assertEqual(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug) + + def test_return(self): + # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 + error = GIMarshallingTests.gerror_return() + + self.assertIsInstance(error, GLib.Error) + self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) + self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) + self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + + def test_exception(self): + with self.assertRaises(GLib.Error) as context: + GIMarshallingTests.gerror() + + e = context.exception + self.assertEqual(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) + self.assertEqual(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE) + self.assertEqual(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_everything.py b/tests/test_everything.py index 0cd1804..f6017e4 100644 --- a/tests/test_everything.py +++ b/tests/test_everything.py @@ -10,12 +10,12 @@ import sys try: import cairo + cairo # Pyflakes has_cairo = True from gi.repository import Regress as Everything except ImportError: has_cairo = False -#import gi from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio @@ -47,39 +47,6 @@ class RawGList(ctypes.Structure): @unittest.skipUnless(has_cairo, 'built without cairo support') class TestEverything(unittest.TestCase): - def test_cairo_context(self): - context = Everything.test_cairo_context_full_return() - self.assertTrue(isinstance(context, cairo.Context)) - - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) - context = cairo.Context(surface) - Everything.test_cairo_context_none_in(context) - - def test_cairo_surface(self): - surface = Everything.test_cairo_surface_none_return() - self.assertTrue(isinstance(surface, cairo.ImageSurface)) - self.assertTrue(isinstance(surface, cairo.Surface)) - self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEqual(surface.get_width(), 10) - self.assertEqual(surface.get_height(), 10) - - surface = Everything.test_cairo_surface_full_return() - self.assertTrue(isinstance(surface, cairo.ImageSurface)) - self.assertTrue(isinstance(surface, cairo.Surface)) - self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEqual(surface.get_width(), 10) - self.assertEqual(surface.get_height(), 10) - - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) - Everything.test_cairo_surface_none_in(surface) - - surface = Everything.test_cairo_surface_full_out() - self.assertTrue(isinstance(surface, cairo.ImageSurface)) - self.assertTrue(isinstance(surface, cairo.Surface)) - self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEqual(surface.get_width(), 10) - self.assertEqual(surface.get_height(), 10) - def test_bool(self): self.assertEqual(Everything.test_boolean(False), False) self.assertEqual(Everything.test_boolean(True), True) @@ -1347,12 +1314,3 @@ class TestSignals(unittest.TestCase): self.assertEqual(obj.callback_i, 42) self.assertEqual(type(rv), GLib.Array) self.assertEqual(rv.len, 2) - - -@unittest.skipUnless(has_cairo, 'built without cairo support') -@unittest.skipUnless(Gtk, 'Gtk not available') -class TestPango(unittest.TestCase): - def test_cairo_font_options(self): - screen = Gtk.Window().get_screen() - font_opts = screen.get_font_options() - self.assertEqual(type(font_opts.get_subpixel_order()), int) diff --git a/tests/test_gi.py b/tests/test_gi.py index 9846440..4a5d510 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -61,9 +61,8 @@ class Sequence(object): class TestConstant(unittest.TestCase): -# Blocked by https://bugzilla.gnome.org/show_bug.cgi?id=595773 -# def test_constant_utf8(self): -# self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8) + def test_constant_utf8(self): + self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8) def test_constant_number(self): self.assertEqual(CONSTANT_NUMBER, GIMarshallingTests.CONSTANT_NUMBER) @@ -2009,7 +2008,6 @@ 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. @@ -2524,9 +2522,7 @@ class TestOverrides(unittest.TestCase): # not overridden self.assertEqual(GIMarshallingTests.SubObject.__module__, 'gi.repository.GIMarshallingTests') - # FIXME: does not work with TEST_NAMES='test_thread test_gi.TestOverrides', - # it is importlib._bootstrap then - #self.assertEqual(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject') + self.assertEqual(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject') class TestDir(unittest.TestCase): @@ -2554,55 +2550,6 @@ class TestDir(unittest.TestCase): # self.assertTrue('DoNotImportDummyTests' in list) -class TestGError(unittest.TestCase): - def test_array_in_crash(self): - # Previously there was a bug in invoke, in which C arrays were unwrapped - # from inside GArrays to be passed to the C function. But when a GError was - # set, invoke would attempt to free the C array as if it were a GArray. - # This crash is only for C arrays. It does not happen for C functions which - # take in GArrays. See https://bugzilla.gnome.org/show_bug.cgi?id=642708 - self.assertRaises(GObject.GError, GIMarshallingTests.gerror_array_in, [1, 2, 3]) - - def test_out(self): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - error, debug = GIMarshallingTests.gerror_out() - - self.assertIsInstance(error, GObject.GError) - self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - self.assertEqual(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE) - - def test_out_transfer_none(self): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - error, debug = GIMarshallingTests.gerror_out_transfer_none() - - self.assertIsInstance(error, GObject.GError) - self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - self.assertEqual(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug) - - def test_return(self): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - error = GIMarshallingTests.gerror_return() - - self.assertIsInstance(error, GObject.GError) - self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - - def test_exception(self): - self.assertRaises(GObject.GError, GIMarshallingTests.gerror) - try: - GIMarshallingTests.gerror() - except Exception: - etype, e = sys.exc_info()[:2] - self.assertEqual(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEqual(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEqual(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - - class TestParamSpec(unittest.TestCase): # https://bugzilla.gnome.org/show_bug.cgi?id=682355 @unittest.expectedFailure diff --git a/tests/test_gio.py b/tests/test_gio.py index 57ab013..986d6dc 100644 --- a/tests/test_gio.py +++ b/tests/test_gio.py @@ -40,7 +40,7 @@ class TestGio(unittest.TestCase): class TestGSettings(unittest.TestCase): def setUp(self): - self.settings = Gio.Settings('org.gnome.test') + self.settings = Gio.Settings(schema='org.gnome.test') # we change the values in the tests, so set them to predictable start # value self.settings.reset('test-string') @@ -78,7 +78,7 @@ class TestGSettings(unittest.TestCase): self.assertEqual(self.settings.get_property('path'), '/tests/') # optional constructor arguments - with_path = Gio.Settings('org.gnome.nopathtest', path='/mypath/') + with_path = Gio.Settings(schema='org.gnome.nopathtest', path='/mypath/') self.assertEqual(with_path.get_property('path'), '/mypath/') self.assertEqual(with_path['np-int'], 42) @@ -115,7 +115,7 @@ class TestGSettings(unittest.TestCase): self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo') def test_empty(self): - empty = Gio.Settings('org.gnome.empty', path='/tests/') + empty = Gio.Settings(schema='org.gnome.empty', path='/tests/') self.assertEqual(len(empty), 0) self.assertEqual(bool(empty), True) self.assertEqual(empty.keys(), []) diff --git a/tests/test_iochannel.py b/tests/test_iochannel.py index 0cc1b4b..259171b 100644 --- a/tests/test_iochannel.py +++ b/tests/test_iochannel.py @@ -108,7 +108,7 @@ second line ch.seek(2, 2) # SEEK_END # FIXME: does not work currently - #self.assertEqual(ch.read(2), b'n!') + # self.assertEqual(ch.read(2), b'n!') # invalid whence value self.assertRaises(ValueError, ch.seek, 0, 3) diff --git a/tests/test_option.py b/tests/test_option.py index 2900edd..fe25746 100644 --- a/tests/test_option.py +++ b/tests/test_option.py @@ -71,7 +71,7 @@ class TestOption(unittest.TestCase): def test_parse_args_double_dash(self): options, args = self.parser.parse_args( ["test_option.py", "--", "-xxx"]) - #self.assertEqual(args, ["-xxx"]) + # self.assertEqual(args, ["-xxx"]) def test_parse_args_group(self): group = self._create_group() diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py index 2a0fd90..d339adf 100644 --- a/tests/test_overrides_gtk.py +++ b/tests/test_overrides_gtk.py @@ -632,6 +632,35 @@ class TestGtk(unittest.TestCase): @unittest.skipUnless(Gtk, 'Gtk not available') +class TestWidget(unittest.TestCase): + def test_style_get_property_gvalue(self): + button = Gtk.Button() + value = GObject.Value(int, -42) + button.style_get_property('focus-padding', value) + # Test only that the style property changed since we can't actuall + # set it. + self.assertNotEqual(value.get_int(), -42) + + def test_style_get_property_return_with_explicit_gvalue(self): + button = Gtk.Button() + value = GObject.Value(int, -42) + result = button.style_get_property('focus-padding', value) + self.assertIsInstance(result, int) + self.assertNotEqual(result, -42) + + def test_style_get_property_return_with_implicit_gvalue(self): + button = Gtk.Button() + result = button.style_get_property('focus-padding') + self.assertIsInstance(result, int) + self.assertNotEqual(result, -42) + + def test_style_get_property_error(self): + button = Gtk.Button() + with self.assertRaises(ValueError): + button.style_get_property('not-a-valid-style-property') + + +@unittest.skipUnless(Gtk, 'Gtk not available') class TestSignals(unittest.TestCase): def test_class_closure_override_with_aliased_type(self): class WindowWithSizeAllocOverride(Gtk.ScrolledWindow): @@ -1796,3 +1825,66 @@ class TestTextBuffer(unittest.TestCase): None) self.assertEqual(start.get_offset(), 6) self.assertEqual(end.get_offset(), 11) + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestContainer(unittest.TestCase): + def test_child_set_property(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=False, fill=True, padding=0) + + box.child_set_property(child, 'padding', 42) + + value = GObject.Value(int) + box.child_get_property(child, 'padding', value) + self.assertEqual(value.get_int(), 42) + + def test_child_get_property_gvalue(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=False, fill=True, padding=42) + + value = GObject.Value(int) + box.child_get_property(child, 'padding', value) + self.assertEqual(value.get_int(), 42) + + def test_child_get_property_return_with_explicit_gvalue(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=False, fill=True, padding=42) + + value = GObject.Value(int) + result = box.child_get_property(child, 'padding', value) + self.assertEqual(result, 42) + + def test_child_get_property_return_with_implicit_gvalue(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=False, fill=True, padding=42) + + result = box.child_get_property(child, 'padding') + self.assertEqual(result, 42) + + def test_child_get_property_error(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=False, fill=True, padding=42) + with self.assertRaises(ValueError): + box.child_get_property(child, 'not-a-valid-child-property') + + def test_child_get_and_set(self): + box = Gtk.Box() + child = Gtk.Button() + box.pack_start(child, expand=True, fill=True, padding=42) + + expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding') + self.assertEqual(expand, True) + self.assertEqual(fill, True) + self.assertEqual(padding, 42) + + box.child_set(child, expand=False, fill=False, padding=21, pack_type=1) + expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type') + self.assertEqual(expand, False) + self.assertEqual(fill, False) + self.assertEqual(padding, 21) diff --git a/tests/test_repository.py b/tests/test_repository.py index c02581c..b73fbf9 100644 --- a/tests/test_repository.py +++ b/tests/test_repository.py @@ -100,6 +100,13 @@ class Test(unittest.TestCase): self.assertFalse(info.get_fundamental()) self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object')) + def test_callable_inheritance(self): + self.assertTrue(issubclass(GIRepository.CallableInfo, GIRepository.BaseInfo)) + self.assertTrue(issubclass(GIRepository.CallbackInfo, GIRepository.CallableInfo)) + self.assertTrue(issubclass(GIRepository.FunctionInfo, GIRepository.CallableInfo)) + self.assertTrue(issubclass(GIRepository.VFuncInfo, GIRepository.CallableInfo)) + self.assertTrue(issubclass(GIRepository.SignalInfo, GIRepository.CallableInfo)) + def test_registered_type_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') # Call these from the class because GIObjectInfo overrides them @@ -213,7 +220,6 @@ class Test(unittest.TestCase): 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') @@ -231,7 +237,6 @@ class Test(unittest.TestCase): 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') @@ -302,6 +307,22 @@ class Test(unittest.TestCase): self.assertEqual(vfunc.get_offset(), 0xFFFF) # unknown offset self.assertEqual(vfunc.get_signal(), None) + def test_callable_can_throw_gerror(self): + info = repo.find_by_name('GIMarshallingTests', 'Object') + invoker = find_child_info(info, 'get_methods', 'vfunc_meth_with_error') + vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_meth_with_err') + + self.assertTrue(invoker.can_throw_gerror()) + self.assertTrue(vfunc.can_throw_gerror()) + + # Test that args do not include the GError** + self.assertEqual(len(invoker.get_arguments()), 1) + self.assertEqual(len(vfunc.get_arguments()), 1) + + # Sanity check method that does not throw. + invoker_no_throws = find_child_info(info, 'get_methods', 'method_int8_in') + self.assertFalse(invoker_no_throws.can_throw_gerror()) + def test_flags_double_registration_error(self): # a warning is printed for double registration and pygobject will # also raise a RuntimeError. diff --git a/tests/test_signal.py b/tests/test_signal.py index 429afc9..80d4ac5 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -136,9 +136,9 @@ class TestAccumulator(unittest.TestCase): inst = Foo() inst.my_acc_signal.connect(lambda obj: 1) inst.my_acc_signal.connect(lambda obj: 2) - ## the value returned in the following handler will not be - ## considered, because at this point the accumulator already - ## reached its limit. + # the value returned in the following handler will not be + # considered, because at this point the accumulator already + # reached its limit. inst.my_acc_signal.connect(lambda obj: 3) retval = inst.my_acc_signal.emit() self.assertEqual(retval, 3) @@ -147,8 +147,8 @@ class TestAccumulator(unittest.TestCase): inst = Foo() inst.my_other_acc_signal.connect(self._true_handler1) inst.my_other_acc_signal.connect(self._true_handler2) - ## the following handler will not be called because handler2 - ## returns True, so it should stop the emission. + # the following handler will not be called because handler2 + # returns True, so it should stop the emission. inst.my_other_acc_signal.connect(self._true_handler3) self.__true_val = None inst.my_other_acc_signal.emit() @@ -629,20 +629,20 @@ class _TestCMarshaller: rv = self.obj.emit("test-gvalue", v) self.assertEqual(rv, GObject.G_MAXINT64) - # implicit int64 - # does not work, see https://bugzilla.gnome.org/show_bug.cgi?id=683775 - #rv = self.obj.emit("test-gvalue", GObject.G_MAXINT64) - #self.assertEqual(rv, GObject.G_MAXINT64) - # explicit uint64 v = GObject.Value(GObject.TYPE_UINT64, GObject.G_MAXUINT64) rv = self.obj.emit("test-gvalue", v) self.assertEqual(rv, GObject.G_MAXUINT64) + @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=705291 + def test_gvalue_implicit_int64(self): + # implicit int64 + rv = self.obj.emit("test-gvalue", GObject.G_MAXINT64) + self.assertEqual(rv, GObject.G_MAXINT64) + # implicit uint64 - # does not work, see https://bugzilla.gnome.org/show_bug.cgi?id=683775 - #rv = self.obj.emit("test-gvalue", GObject.G_MAXUINT64) - #self.assertEqual(rv, GObject.G_MAXUINT64) + rv = self.obj.emit("test-gvalue", GObject.G_MAXUINT64) + self.assertEqual(rv, GObject.G_MAXUINT64) def test_gvalue_ret(self): self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT), @@ -705,7 +705,6 @@ class TestSignalDecorator(unittest.TestCase): @GObject.SignalOverride def notify(self, *args, **kargs): self.overridden_closure_called = True - #GObject.GObject.notify(self, *args, **kargs) def on_notify(self, obj, prop): self.notify_called = True @@ -763,7 +762,6 @@ class TestSignalDecorator(unittest.TestCase): obj = self.DecoratedOverride() obj.connect("notify", obj.on_notify) self.assertEqual(obj.value, 0) - #obj.notify.emit() obj.value = 1 self.assertEqual(obj.value, 1) self.assertTrue(obj.overridden_closure_called) diff --git a/tests/test_typeclass.py b/tests/test_typeclass.py new file mode 100644 index 0000000..3ece684 --- /dev/null +++ b/tests/test_typeclass.py @@ -0,0 +1,80 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# test_typeclass.py: Tests for GTypeClass related methods and marshalling. +# +# Copyright (C) 2014 Simon Feltman +# +# 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 + +from gi.repository import GObject +from gi.repository import GIMarshallingTests + + +class TestCoercion(unittest.TestCase): + def test_coerce_from_class(self): + prop = GObject.ObjectClass.find_property(GIMarshallingTests.PropertiesObject, + 'some-int') + + self.assertIsInstance(prop, GObject.GParamSpec) + self.assertEqual(prop.name, 'some-int') + self.assertEqual(prop.value_type, GObject.TYPE_INT) + self.assertEqual(prop.owner_type, + GIMarshallingTests.PropertiesObject.__gtype__) + + def test_coerce_from_gtype(self): + gtype = GIMarshallingTests.PropertiesObject.__gtype__ + prop = GObject.ObjectClass.find_property(gtype, 'some-int') + + self.assertIsInstance(prop, GObject.GParamSpec) + self.assertEqual(prop.name, 'some-int') + self.assertEqual(prop.value_type, GObject.TYPE_INT) + self.assertEqual(prop.owner_type, gtype) + + def test_coerce_from_instance(self): + obj = GIMarshallingTests.PropertiesObject() + prop = GObject.ObjectClass.find_property(obj, 'some-int') + + self.assertIsInstance(prop, GObject.GParamSpec) + self.assertEqual(prop.name, 'some-int') + self.assertEqual(prop.value_type, GObject.TYPE_INT) + self.assertEqual(prop.owner_type, obj.__gtype__) + + def test_marshalling_error(self): + with self.assertRaises(TypeError): + GObject.ObjectClass.find_property(object, 'some-int') + + with self.assertRaises(TypeError): + GObject.ObjectClass.find_property(42, 'some-int') + + +class TestTypeClassMethodsMovedToClass(unittest.TestCase): + def test_list_child_properties(self): + pspecs = GIMarshallingTests.PropertiesObject.list_properties() + pnames = [pspec.name for pspec in pspecs] + self.assertTrue('some-int' in pnames) + self.assertTrue('some-float' in pnames) + self.assertTrue('some-char' in pnames) + + def test_find_child_property(self): + pspec = GIMarshallingTests.PropertiesObject.find_property('some-int') + self.assertEqual(pspec.name, 'some-int') + + +if __name__ == '__main__': + unittest.main() -- 2.7.4