[pygobject] Add a overrides registry so we can refrence overrides inside the module



commit 89c104d17d79d7b935cd76101cba19d49390f7be
Author: John (J5) Palmieri <johnp redhat com>
Date:   Thu Nov 4 12:00:14 2010 -0400

    Add a overrides registry so we can refrence overrides inside the module
    
    * Overrides have a reentrancy issue when doing inheritance.  If an override
      inherits from another override down the stack it won't see the override
      because the module is not finished loading and will inherit from the
      non-overriden object instead.  This causes type errors later.
    * By adding the overrides to a registry outside of the module we can order
      registration and make the override available as soon as the class is parsed,
      not when the whole module is parsed.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=633347

 gi/module.py                       |   12 +++++++++-
 gi/overrides/GIMarshallingTests.py |    2 +-
 gi/overrides/Gdk.py                |    2 +-
 gi/overrides/Gtk.py                |    2 +-
 gi/overrides/__init__.py           |   43 ++++++++++++++++++++++++++++++++++++
 gi/types.py                        |    8 ------
 tests/test_overrides.py            |   27 ++++++++++++++++++++++
 7 files changed, 84 insertions(+), 12 deletions(-)
---
diff --git a/gi/module.py b/gi/module.py
index 0f21bed..c7b6557 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -25,6 +25,8 @@ from __future__ import absolute_import
 import os
 import gobject
 
+from .overrides import registry
+
 from ._gi import \
     Repository, \
     FunctionInfo, \
@@ -47,7 +49,6 @@ from .types import \
 
 repository = Repository.get_default()
 
-
 def get_parent_for_object(object_info):
     parent_object_info = object_info.get_parent()
 
@@ -236,6 +237,15 @@ class DynamicModule(object):
             override_exports = getattr(self._overrides_module, '__all__', ())
             if name in override_exports:
                 return getattr(self._overrides_module, name, None)
+        else:
+            # check the registry just in case the module hasn't loaded yet
+            # TODO: Only gtypes are registered in the registry right now 
+            #       but it would be nice to register all overrides and 
+            #       get rid of the module imports. We might actually see a 
+            #       speedup.
+            key = '%s.%s' % (self._namespace, name)
+            if key in registry:
+                return registry[key]
 
         return getattr(self.introspection_module, name)
 
diff --git a/gi/overrides/GIMarshallingTests.py b/gi/overrides/GIMarshallingTests.py
index ee01495..25a882f 100644
--- a/gi/overrides/GIMarshallingTests.py
+++ b/gi/overrides/GIMarshallingTests.py
@@ -18,7 +18,7 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 # USA
 
-from ..types import override
+from ..overrides import override
 from ..importer import modules
 
 GIMarshallingTests = modules['GIMarshallingTests'].introspection_module
diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py
index 23a9d8e..08141d7 100644
--- a/gi/overrides/Gdk.py
+++ b/gi/overrides/Gdk.py
@@ -19,7 +19,7 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 # USA
 
-from ..types import override
+from ..overrides import override
 from ..importer import modules
 
 Gdk = modules['Gdk'].introspection_module
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
index 7113478..69392b6 100644
--- a/gi/overrides/Gtk.py
+++ b/gi/overrides/Gtk.py
@@ -23,7 +23,7 @@ import sys
 import gobject
 from gi.repository import Gdk
 from gi.repository import GObject
-from ..types import override
+from ..overrides import override
 from ..importer import modules
 
 if sys.version_info >= (3, 0):
diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py
index e69de29..d4cd80b 100644
--- a/gi/overrides/__init__.py
+++ b/gi/overrides/__init__.py
@@ -0,0 +1,43 @@
+import gobject
+
+registry = None
+class _Registry(dict):
+    def __setitem__(self, key, value):
+        '''We do checks here to make sure only submodules of the override 
+        module are added.  Key and value should be the same object and come
+        from the gi.override module.  
+
+        We add the override to the dict as "override_module.name".  For instance
+        if we were overriding Gtk.Button you would retrive it as such:
+        registry['Gtk.Button']
+        ''' 
+        if not key == value:
+            raise KeyError('You have tried to modify the registry.  This should only be done by the override decorator')
+
+        info = getattr(value, '__info__')
+        if info == None:
+            raise KeyError('Can not override a type %s, which is not in a gobject introspection typelib' % value.__name__)
+
+        if not value.__module__.startswith('gi.overrides'):
+            raise KeyError('You have tried to modify the registry outside of the overrides module.  This is not allowed')
+
+        g_type = info.get_g_type()
+        assert g_type != gobject.TYPE_NONE
+        if g_type != gobject.TYPE_INVALID:
+            g_type.pytype = value 
+
+            # strip gi.overrides from module name
+            module =  value.__module__[13:]
+            key = "%s.%s" % (module, value.__name__)
+            super(_Registry, self).__setitem__(key, value)
+
+    def register(self, override_class):
+        self[override_class] = override_class
+
+registry = _Registry()
+
+def override(type_):
+    '''Decorator for registering an override'''
+    registry.register(type_)
+    return type_
+
diff --git a/gi/types.py b/gi/types.py
index 0a8768c..687e5d5 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -162,14 +162,6 @@ class StructMeta(type, MetaClassHelper):
         cls._setup_methods()
         cls._setup_constructors()
 
-
-def override(type_):
-    g_type = type_.__info__.get_g_type()
-    assert g_type != gobject.TYPE_NONE
-    if g_type != gobject.TYPE_INVALID:
-        g_type.pytype = type_
-    return type_
-
 class Enum(int):
     __info__ = None
     def __init__(self, value):
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index 33ec95e..869a28a 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -14,6 +14,7 @@ from gi.repository import GObject
 from gi.repository import Gdk
 from gi.repository import Gtk
 import gi.overrides as overrides
+import gi.types
 
 class TestGLib(unittest.TestCase):
 
@@ -550,3 +551,29 @@ class TestGtk(unittest.TestCase):
         self.assertEquals(Gtk.STOCK_CLOSE, button.get_label())
         self.assertTrue(button.get_use_stock())
         self.assertTrue(button.get_use_underline())
+
+    def test_inheritance(self):
+        for name in overrides.Gtk.__all__:
+            over = getattr(overrides.Gtk, name)
+            for element in dir(Gtk):
+                try:
+                    klass = getattr(Gtk, element)
+                    info = klass.__info__
+                except (NotImplementedError, AttributeError):
+                    continue
+
+                # Get all parent classes and interfaces klass inherits from
+                if isinstance(info, gi.types.ObjectInfo):
+                    classes = list(info.get_interfaces())
+                    parent = info.get_parent()
+                    while parent.get_name() != "Object":
+                        classes.append(parent)
+                        parent = parent.get_parent()
+                    classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
+                else:
+                    continue
+
+                for kl in classes:
+                    if kl.get_name() == name:
+                        self.assertTrue(issubclass(klass, over,),
+                            "%r does not inherit from override %r" % (klass, over,))



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