Re: pygi: callback funcs and GErrors



So if you "return False, None" from the callback, None becomes the
GError and it is considered set (I guess because None is a Python
object and not NULL).

Then Pixbuf.save_to_callbackv() sets the GError and returns in
failure. There is a bug in PyGObject introspection for handling
cleanup of arrays when a GError is set. I've reported it, until the
invoke experts decide how best to solve it:

https://bugzilla.gnome.org/show_bug.cgi?id=642708

On Tue, Feb 15, 2011 at 1:54 PM, Christophe Saout <christophe saout de> wrote:
> Dear python hackers,
>
> I am having some troubles with the new Python bindings via the amazing
> gobject-introspection project:
>
> My attempts to use "gdk_pixbuf_save_to_callback" via
> gobject-introspection and gi.repository so far have failed.
>
> Note that the exact same thing is working with the classic pygtk & co
> bindings, however I have good reasons to port this to the new system. (I
> have started writing additional modules where I want to use the
> pygi-style bindings) And yes, I am aware that this is still kind of
> experimental, so I'd like to report my observations.
>
> It seems like the annotations added so far are mostly to keep the
> scanner happy.  I've tried to fix up the annotations to get things
> going, but I am running into a few problems:
>
> The method is defined as follows:
>
> gboolean gdk_pixbuf_save_to_callback    (GdkPixbuf  *pixbuf,
>                                         GdkPixbufSaveFunc save_func,
>                                         gpointer user_data,
>                                         const char *type,
>                                         GError    **error,
>                                         ...) G_GNUC_NULL_TERMINATED;
>
> Well, this one doesn't seem to want to work at all (probably due to
> varargs) - it doesn't even show up as a possible method from python.
>
> So I concentrated on its twin:
>
> gboolean gdk_pixbuf_save_to_callbackv   (GdkPixbuf  *pixbuf,
>                                         GdkPixbufSaveFunc save_func,
>                                         gpointer user_data,
>                                         const char *type,
>                                         char      **option_keys,
>                                         char      **option_values,
>                                         GError    **error);
>
> with the callback func declared as:
>
> typedef gboolean (*GdkPixbufSaveFunc)   (const gchar *buf,
>                                         gsize count,
>                                         GError **error,
>                                         gpointer data);
>
> I've tried to fix up the annotation as follows:
>
> /**
>  * gdk_pixbuf_save_to_callbackv:
>  * @pixbuf: a #GdkPixbuf.
>  * @save_func: (scope call): a function that is called to save each block of data that
>  *   the save routine generates.
>  * @user_data: (closure save_func): user data to pass to @save_func
>  * @type: name of file format.
>  * @option_keys: (array zero-terminated=1) (element-type utf8): name of options to set, %NULL-terminated
>  * @option_values: (array zero-terminated=1) (element-type utf8): values for named options
>  * @error: (allow-none): location to store error, or %NULL.
>  *
>  * Saves pixbuf to a callback in format @type, which is currently "jpeg",
>  * "png", "tiff", "ico" or "bmp".  If @error is set, %FALSE will be returned. See
>  * gdk_pixbuf_save_to_callback () for more details.
>  *
>  * Return value: whether an error was set
>  *
>  * Since: 2.4
>  **/
>
> Issues:
>
> * Not sure about option_values and being zero-terminated.  It should
>  have the same size as option_keys (where the zero-termination is
>  explicitly stated).  I guess I can't tell it I want to have the same
>  size as another array?  However, that's not my main issue, I just
>  wondered.
>
> * I've added the (scope call) and (closure save_func) to save_func /
>  user_data
>
> Now when calling that method from python it was telling me:
> app1:/root # python test.py
> ERROR:pygi-argument.c:1717:_pygi_argument_to_object: code should not be
> reached
>
> Which I traced down to the GError in GdkPixbufSaveFunc.  Apparently it
> was thinking this is a parameter that is being passed in (instead of
> automatically seeing that it's an error that can be thrown from inside
> the closure)
>
> So as a workaroung I tried to annotate the SaveFunc as follows:
>
> /**
>  * GdkPixbufSaveFunc:
>  * @buf:
>  * @count:
>  * @error: (out)
>  * @data: (closure):
>  */
>
> Now my callback is actually being called:
> ('\x89PNG\r\n\x1a\n\xc8\xb1\xde\x01', 8L, None)
>
> But afterwards I get:
>
> ERROR:pygi-closure.c:307:_pygi_closure_set_out_arguments: code should
> not be reached
>
> Which presumably is a problem with the GError now being an output
> parameter? (the Python function has a "return False")
>
> Changing that one to "return (False, None)" gives
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x00007ffff7d99ae7 in _pygi_argument_release ()
>   from /usr/lib64/python2.7/site-packages/gi/_gi.so
> (gdb) bt
> #0  0x00007ffff7d99ae7 in _pygi_argument_release ()
>   from /usr/lib64/python2.7/site-packages/gi/_gi.so
> #1  0x00007ffff7d99b7e in _pygi_argument_release ()
>   from /usr/lib64/python2.7/site-packages/gi/_gi.so
> #2  0x00007ffff7d963c0 in _free_invocation_state ()
>   from /usr/lib64/python2.7/site-packages/gi/_gi.so
> #3  0x00007ffff7d978ac in _wrap_g_callable_info_invoke ()
> [...]
>
> Also one further question:
>
> * Is it possible t have the (buffer, size) parameters be turned into a
>  single argument on the Python side?  I'm afraid that passing binary
>  data from C to Python this way, the converter will look for a
>  null-terminated string instead of making the buffer exactly the
>  indicated size.
>
> Oh, and in case you haven't noticed, this function is from the
> gdk-pixbuf package.
>
> Software versions used:
>
> glib                    2.28.0
> gobject-introspection   0.10.2
> python                  2.7.1
> pygobject               2.90.0
>
> Python test code:
>
> from gi.repository import GdkPixbuf
> x = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 100, 100)
>
> def cb(*args):
>  print args
>  return False
>
> x.save_to_callbackv(cb, None, 'png', [], [])
>
> I am trying to write a small web service that renders images to a png or
> something like that and then transmits those directly over the network.
>
> Thanks a lot,
>
>        Christophe
>
>
> _______________________________________________
> python-hackers-list mailing list
> python-hackers-list gnome org
> http://mail.gnome.org/mailman/listinfo/python-hackers-list
>


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