GNOME Bugzilla – Bug 680016
Problems returning values
Last modified: 2012-10-16 07:30:39 UTC
While trying to port code based on pygtk's GenericTreeModel, I stumbled into a long list of problem. A major in is that for example the function TreeModel.do_get_iter is not wrapped correctly (see also https://bugs.launchpad.net/bugs/1024492) According to the .gir-File the function should return (True, gtk_tree_iter) which does not work as expected. I suspect, that this is due to the argument being caller-allocated. What happens is, that the value returned (i.e. 1234 of (True, 1234)) is written to the caller-allocated objects first field, in this case the stamp attribute of the GtkTreeIter. The other attributes seem left at 0. When changing the direction of the iter argument to "inout", the function should become do_get_iter(self, iter, path). However, iter is always None in this case and thus cannot be modified. Setting the direction to "in" works and one can edit the properties of the caller-allocated iter. I think a similar problem occurs for the TreeModel.do_get_value function, which should return a GValue. However, it is again caller-allocated, so returning a string or a corresponding new GObject.Value() does not work. When again changing the direction to "in", the method is not called as the GValue is not yet initialized which raises a "TypeError: unknown type (null)". These problems effectively hinder development of custom TreeModels for python.
Here is a simple test-case for the problem, throwing a segmentation fault: import gi from gi.repository import Gtk as gtk, GObject class TreeModel(GObject.GObject, gtk.TreeModel): def do_get_value(self, iter, column): x = GObject.Value() x.init(GObject.TYPE_STRING) x.set_string("foo") return x t = TreeModel() print t.get_value(gtk.TreeIter(), 1)
So a little more results. Consider the following: def do_get_value(self, iter, column): return "bar" which raises the error TypeError: unknown type (null) in pygtype.c:1153 Turns out the return value is correctly marshalled into a GValue object, which is then stored as a GIArgument. Now when the object is to be marshalled to a python object in _invoke_marshal_out_args, somehow the GIArgument is assumed to be a GValue already and thus the error is raised. I think (but I’m not so sure), that the error has somehow to do with the double indirection: out_args in _pygi_closure_set_out_arguments is a GIArgument list. Now out_args[0].v_pointer points again to GIArgument pointing to the GValue. Don't know though how and where exactly the cause for the bug is though…
So coming to a conclusion: the direction=out arguments for these methods with caller-allocates=1 should be direction=in, so that they are passed to the function and the function can manipulate them (i.e. set the GValue). However, the problem with the get_value method persists as it is tried to marshall the argument to the python type (causing the "TypeError: unknown type (null)" error). Even if the value were initialized already, the python-value of it would be passed instead of the GObject.Value object and then the callee wouldn't be able to manipulate the object. To avoid having other side-effects the marshalling could only be disabled if caller-allocates is set. Other than that there could be a special handling of these cases, copying the whole object that was returned from the function to the corresponding original pointer argument.
I've been running into similar issues trying to implement a TreeModel as well. However, your current example seems to work fine on the latest pygobject source repository. Also note that inout and out parameters should be returned from the methods in question in a tuple along with the regular return value. So do_get_iter should return (True, iter). This bug (and patch) may also be of interest: https://bugzilla.gnome.org/show_bug.cgi?id=680812
The example given no longer produces errors. Please re-open with new steps and the pygobject version you are using if you are still seeing this problem.