[pygobject/pygobject-2-28] Skip interfaces when checking for conflicts in the MRO



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]