[pygobject/pygobject-2-28] Skip interfaces when checking for conflicts in the MRO
- From: Tomeu Vizoso <tomeuv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject/pygobject-2-28] Skip interfaces when checking for conflicts in the MRO
- Date: Mon, 28 Feb 2011 18:38:52 +0000 (UTC)
commit 6366307ba020a40f6dfa22e64fd6345b118fd2e5
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date: Wed Feb 16 09:44:12 2011 +0100
Skip interfaces when checking for conflicts in the MRO
https://bugzilla.gnome.org/show_bug.cgi?id=642437
gi/types.py | 40 ++++++++++++++++++++++++++++++++++++++++
gobject/gobjectmodule.c | 9 +++++++--
tests/test_gi.py | 16 ++++++++++++++++
3 files changed, 63 insertions(+), 2 deletions(-)
---
diff --git a/gi/types.py b/gi/types.py
index c2a8b35..ed568d1 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -229,6 +229,46 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
elif isinstance(cls.__info__, InterfaceInfo):
register_interface_info(cls.__info__.get_g_type())
+ def mro(cls):
+ return mro(cls)
+
+
+def mro(C):
+ """Compute the class precedence list (mro) according to C3
+
+ Based on http://www.python.org/download/releases/2.3/mro/
+ Modified to consider that interfaces don't create the diamond problem
+ """
+ # TODO: If this turns out being too slow, consider using generators
+ bases = []
+ bases_of_subclasses = [[C]]
+
+ if C.__bases__:
+ bases_of_subclasses += map(mro, C.__bases__) + [list(C.__bases__)]
+
+ while bases_of_subclasses:
+ for subclass_bases in bases_of_subclasses:
+ candidate = subclass_bases[0]
+ not_head = [s for s in bases_of_subclasses if candidate in s[1:]]
+ if not_head and gobject.GInterface not in candidate.__bases__:
+ candidate = None # conflict, reject candidate
+ else:
+ break
+
+ if candidate is None:
+ raise TypeError('Cannot create a consistent method resolution '
+ 'order (MRO)')
+
+ bases.append(candidate)
+
+ for subclass_bases in bases_of_subclasses[:]: # remove candidate
+ if subclass_bases and subclass_bases[0] == candidate:
+ del subclass_bases[0]
+ if not subclass_bases:
+ bases_of_subclasses.remove(subclass_bases)
+
+ return bases
+
class StructMeta(type, MetaClassHelper):
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c
index acf94ce..2a84606 100644
--- a/gobject/gobjectmodule.c
+++ b/gobject/gobjectmodule.c
@@ -1176,16 +1176,21 @@ pyg_type_register(PyTypeObject *class, const char *type_name)
/* create new typecode */
instance_type = g_type_register_static(parent_type, new_type_name,
&type_info, 0);
- if (type_name == NULL)
- g_free(new_type_name);
if (instance_type == 0) {
PyErr_Format(PyExc_RuntimeError,
"could not create new GType: %s (subclass of %s)",
new_type_name,
g_type_name(parent_type));
+
+ if (type_name == NULL)
+ g_free(new_type_name);
+
return -1;
}
+ if (type_name == NULL)
+ g_free(new_type_name);
+
/* store pointer to the class with the GType */
Py_INCREF(class);
g_type_set_qdata(instance_type, g_quark_from_string("PyGObject::class"),
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 09046b1..73eb6fc 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1609,6 +1609,22 @@ class TestInterfaces(unittest.TestCase):
GIMarshallingTests.test_interface_test_int8_in(instance, 42)
self.assertEquals(instance.val, 42)
+ def test_mro(self):
+ # there was a problem with Python bailing out because of
+ # http://en.wikipedia.org/wiki/Diamond_problem with interfaces,
+ # which shouldn't really be a problem.
+
+ class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface):
+ pass
+
+ class TestInterfaceImpl2(GIMarshallingTests.Interface,
+ TestInterfaceImpl):
+ pass
+
+ class TestInterfaceImpl3(TestInterfaceImpl,
+ GIMarshallingTests.Interface2):
+ pass
+
class TestInterfaceClash(unittest.TestCase):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]