[pygobject] Recurse up through base classes when setting up vfuncs
- From: John Palmieri <johnp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Recurse up through base classes when setting up vfuncs
- Date: Tue, 30 Nov 2010 22:01:54 +0000 (UTC)
commit 9c5aee4f06f92457f9ae987656c0c469f76d0ee8
Author: Jonathan Matthew <jonathan d14n org>
Date: Thu Jul 22 23:19:51 2010 +1000
Recurse up through base classes when setting up vfuncs
* this patch adds the support methods to do the recursion
https://bugzilla.gnome.org/show_bug.cgi?id=625033
gi/gimodule.c | 130 +++++++++++++++++++++++++++++++++++++++---------------
tests/test_gi.py | 37 +++++++++++++++
2 files changed, 131 insertions(+), 36 deletions(-)
---
diff --git a/gi/gimodule.c b/gi/gimodule.c
index f7624ae..e61f099 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -131,39 +131,25 @@ _wrap_pyg_register_interface_info (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *
-_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+static void
+find_vfunc_info (GIBaseInfo *vfunc_info,
+ GType implementor_gtype,
+ gpointer *implementor_class_ret,
+ gpointer *implementor_vtable_ret,
+ GIFieldInfo **field_info_ret)
{
- PyGIBaseInfo *py_info;
- PyObject *py_type;
- PyObject *py_function;
- gpointer implementor_class = NULL;
GType ancestor_g_type = 0;
- GType implementor_gtype = 0;
- gpointer *method_ptr = NULL;
int length, i;
- GIBaseInfo *vfunc_info;
GIBaseInfo *ancestor_info;
GIStructInfo *struct_info;
+ gpointer implementor_class = NULL;
gboolean is_interface = FALSE;
- PyGICClosure *closure = NULL;
- if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation",
- &PyGIBaseInfo_Type, &py_info,
- &PyGTypeWrapper_Type, &py_type,
- &py_function))
- return NULL;
-
- implementor_gtype = pyg_type_from_object (py_type);
- g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
-
- vfunc_info = py_info->info;
ancestor_info = g_base_info_get_container (vfunc_info);
is_interface = g_base_info_get_type (ancestor_info) == GI_INFO_TYPE_INTERFACE;
ancestor_g_type = g_registered_type_info_get_g_type (
(GIRegisteredTypeInfo *) ancestor_info);
-
implementor_class = g_type_class_ref (implementor_gtype);
if (is_interface) {
GTypeInstance *implementor_iface_class;
@@ -175,23 +161,23 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
"Couldn't find GType of implementor of interface %s. "
"Forgot to set __gtype_name__?",
g_type_name (ancestor_g_type));
- return NULL;
+ return;
}
- g_type_class_unref (implementor_class);
- implementor_class = implementor_iface_class;
+ *implementor_vtable_ret = implementor_iface_class;
struct_info = g_interface_info_get_iface_struct ( (GIInterfaceInfo*) ancestor_info);
- } else
+ } else {
struct_info = g_object_info_get_class_struct ( (GIObjectInfo*) ancestor_info);
+ *implementor_vtable_ret = implementor_class;
+ }
+
+ *implementor_class_ret = implementor_class;
length = g_struct_info_get_n_fields (struct_info);
for (i = 0; i < length; i++) {
GIFieldInfo *field_info;
GITypeInfo *type_info;
- GIBaseInfo *interface_info;
- GICallbackInfo *callback_info;
- gint offset;
field_info = g_struct_info_get_field (struct_info, i);
@@ -208,12 +194,50 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
continue;
}
+ *field_info_ret = field_info;
+ break;
+ }
+
+ g_base_info_unref (struct_info);
+}
+
+static PyObject *
+_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+{
+ PyGIBaseInfo *py_info;
+ PyObject *py_type;
+ PyObject *py_function;
+ GType implementor_gtype = 0;
+ gpointer implementor_class = NULL;
+ gpointer implementor_vtable = NULL;
+ GIFieldInfo *field_info = NULL;
+ gpointer *method_ptr = NULL;
+ PyGICClosure *closure = NULL;
+
+ if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation",
+ &PyGIBaseInfo_Type, &py_info,
+ &PyGTypeWrapper_Type, &py_type,
+ &py_function))
+ return NULL;
+
+ implementor_gtype = pyg_type_from_object (py_type);
+ g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
+
+ find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info);
+ if (field_info != NULL) {
+ GITypeInfo *type_info;
+ GIBaseInfo *interface_info;
+ GICallbackInfo *callback_info;
+ gint offset;
+
+ type_info = g_field_info_get_type (field_info);
+
interface_info = g_type_info_get_interface (type_info);
g_assert (g_base_info_get_type (interface_info) == GI_INFO_TYPE_CALLBACK);
callback_info = (GICallbackInfo*) interface_info;
offset = g_field_info_get_offset (field_info);
- method_ptr = G_STRUCT_MEMBER_P (implementor_class, offset);
+ method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset);
closure = _pygi_make_native_closure ( (GICallableInfo*) callback_info,
GI_SCOPE_TYPE_NOTIFIED, py_function, NULL);
@@ -223,16 +247,49 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
g_base_info_unref (interface_info);
g_base_info_unref (type_info);
g_base_info_unref (field_info);
-
- break;
}
+ g_type_class_unref (implementor_class);
- g_base_info_unref (struct_info);
+ Py_RETURN_NONE;
+}
- if (!is_interface)
- g_type_class_unref (implementor_class);
+static PyObject *
+_wrap_pyg_has_vfunc_implementation (PyObject *self, PyObject *args)
+{
+ PyGIBaseInfo *py_info;
+ PyObject *py_type;
+ PyObject *py_ret;
+ gpointer implementor_class = NULL;
+ gpointer implementor_vtable = NULL;
+ GType implementor_gtype = 0;
+ GIFieldInfo *field_info = NULL;
- Py_RETURN_NONE;
+ if (!PyArg_ParseTuple (args, "O!O!:has_vfunc_implementation",
+ &PyGIBaseInfo_Type, &py_info,
+ &PyGTypeWrapper_Type, &py_type))
+ return NULL;
+
+ implementor_gtype = pyg_type_from_object (py_type);
+ g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
+
+ py_ret = Py_False;
+ find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info);
+ if (field_info != NULL) {
+ gpointer *method_ptr;
+ gint offset;
+
+ offset = g_field_info_get_offset (field_info);
+ method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset);
+ if (*method_ptr != NULL) {
+ py_ret = Py_True;
+ }
+
+ g_base_info_unref (field_info);
+ }
+ g_type_class_unref (implementor_class);
+
+ Py_INCREF(py_ret);
+ return py_ret;
}
static PyObject *
@@ -258,7 +315,7 @@ _wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args)
PyObject *value = PyTuple_GET_ITEM (py_values, i);
if (!PyObject_IsInstance (value, py_type)) {
- PyErr_Format (PyExc_TypeError, "argument %d is not a GLib.Variant", i);
+ PyErr_Format (PyExc_TypeError, "argument %" G_GSSIZE_FORMAT " is not a GLib.Variant", i);
return NULL;
}
@@ -298,6 +355,7 @@ static PyMethodDef _gi_functions[] = {
{ "set_object_has_new_constructor", (PyCFunction) _wrap_pyg_set_object_has_new_constructor, METH_VARARGS | METH_KEYWORDS },
{ "register_interface_info", (PyCFunction) _wrap_pyg_register_interface_info, METH_VARARGS },
{ "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
+ { "has_vfunc_implementation", (PyCFunction) _wrap_pyg_has_vfunc_implementation, METH_VARARGS },
{ "variant_new_tuple", (PyCFunction) _wrap_pyg_variant_new_tuple, METH_VARARGS },
{ "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS },
{ NULL, NULL, 0 }
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 66dd560..7621bbe 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1374,6 +1374,16 @@ class TestPythonGObject(unittest.TestCase):
def do_method_with_default_implementation(self, int8):
self.props.int = int8 * 2
+ class SubObject(GIMarshallingTests.SubObject):
+ __gtype_name__ = "SubObject"
+
+ def __init__(self, int):
+ GIMarshallingTests.SubObject.__init__(self)
+ self.val = None
+
+ def do_method_with_default_implementation(self, int8):
+ self.val = int8
+
def test_object(self):
self.assertTrue(issubclass(self.Object, GIMarshallingTests.Object))
@@ -1402,6 +1412,11 @@ class TestPythonGObject(unittest.TestCase):
object_.method_with_default_implementation(84)
self.assertEqual(object_.props.int, 84)
+ def test_subobject_parent_vfunc(self):
+ object_ = self.SubObject(int = 81)
+ object_.method_with_default_implementation(87)
+ self.assertEquals(object_.val, 87)
+
def test_dynamic_module(self):
from gi.module import DynamicGObjectModule
self.assertTrue(isinstance(GObject, DynamicGObjectModule))
@@ -1428,6 +1443,16 @@ class TestInterfaces(unittest.TestCase):
self.assertEquals(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface')
self.assertRaises(NotImplementedError, GIMarshallingTests.Interface)
+
+ def test_incomplete(self):
+ def create_incomplete():
+ class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface):
+ __type_name__ = 'TestInterfaceImpl'
+ def __init__(self):
+ GObject.GObject.__init__(self)
+
+ self.assertRaises(TypeError, create_incomplete)
+
def test_implementation(self):
class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface):
@@ -1467,6 +1492,18 @@ class TestInterfaces(unittest.TestCase):
self.val = int8
self.assertRaises(RuntimeError, define_implementor_without_gtype)
+# -- this needs some additions to GIMarshallingTests in gobject-introspection
+#class TestInterfaceClash(unittest.TestCase):
+#
+# def test_clash(self):
+# def create_clash():
+# class TestClash(GObject.GObject, GIMarshallingTests.Interface, GIMarshallingTests.Interface2):
+# __gtype_name__ = 'TestClash'
+# def do_test_int8_in(self, int8):
+# pass
+# TestClash()
+#
+# self.assertRaises(TypeError, create_clash)
class TestOverrides(unittest.TestCase):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]