[pygobject] Fix lookup of vfuncs in parent classes



commit 07a08b49aae83a297e2f91240448314e4663f724
Author: Carlos Garnacho <carlos lanedo com>
Date:   Mon May 14 15:31:14 2012 +0200

    Fix lookup of vfuncs in parent classes
    
    https://bugzilla.gnome.org/show_bug.cgi?id=672864.
    
    As subclasses implemented in python override the attribute for the
    vfunc, __mro__ has to be used so subclasses of the subclass overriding
    methods may find the corresponding VFuncInfo.
    
    Co-Authored-by: Martin Pitt <martinpitt gnome org>

 gi/types.py      |    6 +++---
 tests/test_gi.py |   27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 3 deletions(-)
---
diff --git a/gi/types.py b/gi/types.py
index e44edba..95f1059 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -121,10 +121,10 @@ class MetaClassHelper(object):
 
             # If a method name starts with "do_" assume it is a vfunc, and search
             # in the base classes for a method with the same name to override.
-            # Recursion is not necessary here because getattr() searches all
-            # super class attributes as well.
+            # Recursion is necessary as overriden methods in most immediate parent
+            # classes may shadow vfuncs from classes higher in the hierarchy.
             vfunc_info = None
-            for base in cls.__bases__:
+            for base in cls.__mro__:
                 method = getattr(base, vfunc_name, None)
                 if method is not None and hasattr(method, '__info__') and \
                         isinstance(method.__info__, VFuncInfo):
diff --git a/tests/test_gi.py b/tests/test_gi.py
index e948c9d..cc6ec2d 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1696,6 +1696,33 @@ class TestPythonGObject(unittest.TestCase):
         GIMarshallingTests.SubSubObject.do_method_deep_hierarchy(sub_sub_sub_object, 5)
         self.assertEqual(sub_sub_sub_object.props.int, 5)
 
+    def test_python_subsubobject_vfunc(self):
+        class PySubObject(GIMarshallingTests.Object):
+            def __init__(self):
+                GIMarshallingTests.Object.__init__(self)
+                self.sub_method_int8_called = 0
+
+            def do_method_int8_in(self, int8):
+                self.sub_method_int8_called += 1
+
+        class PySubSubObject(PySubObject):
+            def __init__(self):
+                PySubObject.__init__(self)
+                self.subsub_method_int8_called = 0
+
+            def do_method_int8_in(self, int8):
+                self.subsub_method_int8_called += 1
+
+        so = PySubObject()
+        so.method_int8_in(1)
+        self.assertEqual(so.sub_method_int8_called, 1)
+
+        # it should call the method on the SubSub object only
+        sso = PySubSubObject()
+        sso.method_int8_in(1)
+        self.assertEqual(sso.subsub_method_int8_called, 1)
+        self.assertEqual(sso.sub_method_int8_called, 0)
+
     def test_callback_in_vfunc(self):
         class SubObject(GIMarshallingTests.Object):
             def __init__(self):



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