pygi: callback funcs and GErrors



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




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