[pygobject] refactor Jonathan Matthew recurse vfunc patch so it applys and clean up a bit



commit 94e8befc935d4a6c7f766e34195e10fc3fb3b93a
Author: John (J5) Palmieri <johnp redhat com>
Date:   Tue Nov 30 16:57:05 2010 -0500

    refactor Jonathan Matthew recurse vfunc patch so it applys and clean up a bit
    
    * this patch does the recursion using the previous patche's support functions

 gi/types.py |   55 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 45 insertions(+), 10 deletions(-)
---
diff --git a/gi/types.py b/gi/types.py
index 18b4013..1ebc194 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -31,7 +31,8 @@ from ._gi import \
     StructInfo, \
     set_object_has_new_constructor, \
     register_interface_info, \
-    hook_up_vfunc_implementation
+    hook_up_vfunc_implementation, \
+    has_vfunc_implementation
 
 
 def Function(info):
@@ -92,28 +93,62 @@ class MetaClassHelper(object):
             value = constant_info.get_value()
             setattr(cls, name, value)
 
-    def _setup_vfuncs(cls):
+    def _setup_vfuncs(cls, impl):
         for base in cls.__bases__:
             if not hasattr(base, '__info__') or \
                     not hasattr(base.__info__, 'get_vfuncs'):
                 continue
             for vfunc_info in base.__info__.get_vfuncs():
-                vfunc = getattr(cls, 'do_' + vfunc_info.get_name(), None)
+                vfunc_name = 'do_' + vfunc_info.get_name()
+                vfunc = getattr(impl, vfunc_name, None)
                 if vfunc is None and isinstance(base.__info__, InterfaceInfo) and \
-                        (not hasattr(cls, vfunc_info.get_name()) and not vfunc_info.get_invoker()):
+                    impl.__module__.startswith('gi.overrides') is False and \
+                        not has_vfunc_implementation(vfunc_info, impl.__gtype__):
                     raise TypeError('Class implementing %s.%s should implement '
-                            'the method do_%s()' % (base.__info__.get_namespace(),
-                                                    base.__info__.get_name(),
-                                                    vfunc_info.get_name()))
+                                    'the method %s()' % (base.__info__.get_namespace(),
+                                                         base.__info__.get_name(),
+                                                         vfunc_name()))
                 elif vfunc is not None:
+                    # check to see if there are vfuncs with the same name in the bases
+                    # we have no way of specifying which one we are supposed to override
+                    ambiguous_base = find_vfunc_conflict_in_bases(vfunc_info, cls.__bases__)
+                    if ambiguous_base is not None:
+                        raise TypeError('Method %s() on class %s.%s is ambiguous '
+                                'with methods in base classes %s.%s and %s.%s' %
+                                (vfunc_name,
+                                 impl.__info__.get_namespace(),
+                                 impl.__info__.get_name(),
+                                 base.__info__.get_namespace(),
+                                 base.__info__.get_name(),
+                                 ambiguous_base.__info__.get_namespace(),
+                                 ambiguous_base.__info__.get_name()))
+
                     function = vfunc
                     if sys.version_info < (3, 0):
                         function = vfunc.im_func
  
-                    if not is_function_in_classes(function, cls.__bases__):
-                        hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
+                    if not is_function_in_classes(function, impl.__bases__):
+                        hook_up_vfunc_implementation(vfunc_info, impl.__gtype__,
                                                      vfunc)
 
+            base._setup_vfuncs(impl)
+
+def find_vfunc_conflict_in_bases(vfunc, bases):
+    for klass in bases:
+        if not hasattr(klass, '__info__') or \
+                not hasattr(klass.__info__, 'get_vfuncs'):
+            continue
+        vfuncs = klass.__info__.get_vfuncs()
+        vfunc_name = vfunc.get_name()
+        for v in vfuncs:
+            if v.get_name() == vfunc_name and v != vfunc:
+                return klass
+
+        aklass = find_vfunc_conflict_in_bases(vfunc, klass.__bases__)
+        if aklass is not None:
+            return aklass
+    return None
+
 def is_function_in_classes(function, classes):
     for klass in classes:
         if function in klass.__dict__.values():
@@ -136,7 +171,7 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
             is_python_defined = True
 
         if is_python_defined:
-            cls._setup_vfuncs()
+            cls._setup_vfuncs(cls)
         elif is_gi_defined:
             cls._setup_methods()
             cls._setup_constants()



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