[pygi] Restore the overrides support



commit eaf7cb8ebb7e34f9493ac83b2f04af4dcf45f40f
Author: Simon van der Linden <svdlinden src gnome org>
Date:   Fri Jan 22 13:41:21 2010 +0100

    Restore the overrides support
    
    Add a ModuleProxy in front of the DynamicModule when an overrides module is
    present. There is no need for an overrides module to be a class; it can just be a module.
    
    Add an override decorator to override the wrapper of a registered type.
    
    Adapt Gdk and Gtk accordingly.
    
    Add tests.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=602830

 gi/importer.py      |   40 +++++++-------------
 gi/module.py        |   43 ++++++++++++++-------
 gi/overrides/Gdk.py |   42 +++++++++++++-------
 gi/overrides/Gtk.py |   16 +++----
 gi/types.py         |    6 +++
 tests/libtestgi.c   |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libtestgi.h   |   49 ++++++++++++++++++++++++
 tests/test_gi.py    |   36 +++++++++++++++++
 8 files changed, 273 insertions(+), 64 deletions(-)
---
diff --git a/gi/importer.py b/gi/importer.py
index f283a41..ad9ede2 100644
--- a/gi/importer.py
+++ b/gi/importer.py
@@ -26,10 +26,11 @@ import sys
 import gobject
 
 from ._gi import Repository, RepositoryError
-from .module import DynamicModule
+from .module import DynamicModule, ModuleProxy
 
 
 repository = Repository.get_default()
+modules = {}
 
 
 class DynamicImporter(object):
@@ -39,17 +40,6 @@ class DynamicImporter(object):
     def __init__(self, path):
         self.path = path
 
-    def _create_module(self, module_type, name, namespace):
-        module = module_type.__new__(module_type)
-        module.__dict__ = {
-            '__file__': '<%s>' % name,
-            '__name__': name,
-            '__namespace__': namespace,
-            '__loader__': self
-        }
-        module.__init__()
-        return module
-
     def find_module(self, fullname, path=None):
         if not fullname.startswith(self.path):
             return
@@ -75,23 +65,21 @@ class DynamicImporter(object):
             sys.modules[fullname] = gobject
             return gobject
 
-        module_type = DynamicModule
-        module = self._create_module(module_type, fullname, namespace)
-        sys.modules[fullname] = module
+        dynamic_module = DynamicModule(namespace)
+        modules[namespace] = dynamic_module
 
-        # Look for an overrides module
-        overrides_name = 'gi.overrides.%s' % namespace
-        overrides_type_name = '%sModule' % namespace
-        try:
+        overrides_modules = __import__('gi.overrides', fromlist=[namespace])
+        overrides_module = getattr(overrides_modules, namespace, None)
 
-            overrides_module = __import__(overrides_name, fromlist=[overrides_type_name])
-            module_type = getattr(overrides_module, overrides_type_name)
-        except ImportError, e:
-            pass
+        if overrides_module is not None:
+            module = ModuleProxy(fullname, namespace, dynamic_module, overrides_module)
+        else:
+            module = dynamic_module
 
-        if module_type is not DynamicModule:
-            module = self._create_module(module_type, fullname, namespace)
-            sys.modules[fullname] = module
+        module.__file__ = '<%s>' % fullname
+        module.__loader__ = self
+
+        sys.modules[fullname] = module
 
         return module
 
diff --git a/gi/module.py b/gi/module.py
index 72a6a53..61fbdfc 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -75,15 +75,11 @@ def get_interfaces_for_object(object_info):
 
 class DynamicModule(object):
 
-    def __str__(self):
-        path = repository.get_typelib_path(self.__namespace__)
-        return "<dynamic module %r from %r>" % (self.__name__,  path)
+    def __init__(self, namespace):
+        self._namespace = namespace
 
     def __getattr__(self, name):
-        if self.__dict__.has_key(name):
-            return self.__dict__[name]
-
-        info = repository.find_by_name(self.__namespace__, name)
+        info = repository.find_by_name(self._namespace, name)
         if not info:
             raise AttributeError("%r object has no attribute %r" % (
                     self.__class__.__name__, name))
@@ -139,7 +135,7 @@ class DynamicModule(object):
             name = info.get_name()
             dict_ = {
                 '__info__': info,
-                '__module__': self.__namespace__,
+                '__module__': self._namespace,
                 '__gtype__': g_type
             }
             value = metaclass(name, bases, dict_)
@@ -158,10 +154,29 @@ class DynamicModule(object):
         self.__dict__[name] = value
         return value
 
-    @property
-    def __members__(self):
-        r = []
-        for type_info in repository.get_infos(self.__namespace__):
-            r.append(type_info.get_name())
-        return r
+    def __repr__(self):
+        path = repository.get_typelib_path(self._namespace)
+        return "<DynamicModule %r from %r>" % (self._namespace, path)
+
+
+class ModuleProxy(object):
+
+    def __init__(self, name, namespace, dynamic_module, overrides_module):
+        self.__name__ = name
+
+        self._namespace = namespace
+        self._dynamic_module = dynamic_module
+        self._overrides_module = overrides_module
+
+    def __getattr__(self, name):
+        attribute = getattr(self._overrides_module, name, None)
+        exports = getattr(self._overrides_module, '__all__', ())
+        if attribute is not None and attribute not in exports:
+            attribute = None
+        if attribute is None:
+            attribute = getattr(self._dynamic_module, name)
+        return attribute
+
+    def __str__(self):
+        return "<ModuleProxy %r>" % self.__name__
 
diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py
index e3e2d29..2662046 100644
--- a/gi/overrides/Gdk.py
+++ b/gi/overrides/Gdk.py
@@ -1,21 +1,33 @@
-import sys
+from ..types import override
+from ..importer import modules
+
+Gdk = modules['Gdk']
+
+
+class Rectangle(Gdk.Rectangle):
 
-from ..module import DynamicModule
+    def __init__(self, x, y, width, height):
+        Gdk.Rectangle.__init__(self)
+        self.x = x
+        self.y = y
+        self.width = width
+        self.height = height
 
-class GdkModule(DynamicModule):
+    def __new__(cls, *args, **kwargs):
+        return Gdk.Rectangle.__new__(cls)
 
-    def __init__(self):
-        super(GdkModule, self).__init__()
+    def __repr__(self):
+        return '<Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)>' % (
+		    self.x, self.y, self.width, self.height)
 
-        initialized, argv = self.init_check(tuple(sys.argv))
-        if not initialized:
-            raise RuntimeError("Gdk couldn't be initialized")
+Rectangle = override(Rectangle)
 
-    def rectangle_new(self, x, y, width, height):
-        rectangle = self.Rectangle()
-        rectangle.x = x
-        rectangle.y = y
-        rectangle.width = width
-        rectangle.height = height
-        return rectangle
 
+__all__ = [Rectangle]
+
+
+import sys
+
+initialized, argv = Gdk.init_check(sys.argv)
+if not initialized:
+    raise RuntimeError("Gdk couldn't be initialized")
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
index b4e9596..0f5d46a 100644
--- a/gi/overrides/Gtk.py
+++ b/gi/overrides/Gtk.py
@@ -1,15 +1,13 @@
-import sys
+from ..importer import modules
 
-from ..module import DynamicModule
+Gtk = modules['Gtk']
 
-class GtkModule(DynamicModule):
 
-    import keysyms
+__all__ = []
 
-    def __init__(self):
-        super(GtkModule, self).__init__()
 
-        initialized, argv = self.init_check(tuple(sys.argv))
-        if not initialized:
-            raise RuntimeError("Gtk couldn't be initialized")
+import sys
 
+initialized, argv = Gtk.init_check(sys.argv)
+if not initialized:
+    raise RuntimeError("Gtk couldn't be initialized")
diff --git a/gi/types.py b/gi/types.py
index e4d7c5f..b7061bd 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -126,3 +126,9 @@ class StructMeta(type, MetaClassHelper):
         cls._setup_methods()
         cls._setup_constructors()
 
+
+def override(type_):
+    g_type = type_.__info__.get_g_type()
+    if g_type != gobject.TYPE_INVALID:
+        g_type.pytype = type_
+    return type_
diff --git a/tests/libtestgi.c b/tests/libtestgi.c
index a8a77a5..c3899a6 100644
--- a/tests/libtestgi.c
+++ b/tests/libtestgi.c
@@ -3477,3 +3477,108 @@ test_gi_int_return_ptr_null (void)
     return NULL;
 }
 
+
+TestGIOverridesStruct *
+test_gi_overrides_struct_copy (TestGIOverridesStruct *struct_)
+{
+    TestGIOverridesStruct *new_struct;
+
+    new_struct = g_slice_new (TestGIOverridesStruct);
+
+    *new_struct = *struct_;
+
+    return new_struct;
+}
+
+static void
+test_gi_overrides_struct_free (TestGIOverridesStruct *struct_)
+{
+    g_slice_free (TestGIOverridesStruct, struct_);
+}
+
+GType
+test_gi_overrides_struct_get_type (void)
+{
+    static GType type = 0;
+
+    if (type == 0) {
+        type = g_boxed_type_register_static ("TestGIOverridesStruct",
+                (GBoxedCopyFunc) test_gi_overrides_struct_copy,
+                (GBoxedFreeFunc) test_gi_overrides_struct_free);
+    }
+
+    return type;
+}
+
+TestGIOverridesStruct *
+test_gi_overrides_struct_new (void)
+{
+    return g_slice_new (TestGIOverridesStruct);
+}
+
+glong
+test_gi_overrides_struct_method (TestGIOverridesStruct *struct_)
+{
+    return 42;
+}
+
+
+/**
+ * test_gi__overrides_struct_return:
+ *
+ * Returns: (transfer full):
+ */
+TestGIOverridesStruct *
+test_gi__overrides_struct_return (void)
+{
+    return test_gi_overrides_struct_new();
+}
+
+
+G_DEFINE_TYPE (TestGIOverridesObject, test_gi_overrides_object, G_TYPE_OBJECT);
+
+static void
+test_gi_overrides_object_init (TestGIOverridesObject *object)
+{
+}
+
+static void
+test_gi_overrides_object_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (test_gi_overrides_object_parent_class)->finalize (object);
+}
+
+static void
+test_gi_overrides_object_class_init (TestGIOverridesObjectClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+#if 0
+	GObjectClass* parent_class = G_OBJECT_CLASS (klass);
+#endif
+
+	object_class->finalize = test_gi_overrides_object_finalize;
+}
+
+TestGIOverridesObject *
+test_gi_overrides_object_new (void)
+{
+    return g_object_new (TESTGI_TYPE_OVERRIDES_OBJECT, NULL);
+}
+
+glong
+test_gi_overrides_object_method (TestGIOverridesObject *object)
+{
+    return 42;
+}
+
+
+/**
+ * test_gi__overrides_object_return:
+ *
+ * Returns: (transfer full):
+ */
+TestGIOverridesObject *
+test_gi__overrides_object_return (void)
+{
+    return g_object_new (TESTGI_TYPE_OVERRIDES_OBJECT, NULL);
+}
diff --git a/tests/libtestgi.h b/tests/libtestgi.h
index 1620096..970d01b 100644
--- a/tests/libtestgi.h
+++ b/tests/libtestgi.h
@@ -662,4 +662,53 @@ gint *test_gi_int_return_ptr_null (void);
 void test_gi_int_in_ptr_null (gint *int_);
 
 
+/* Overrides */
+
+#define TESTGI_OVERRIDES_CONSTANT 42
+
+
+typedef struct {
+    glong long_;
+} TestGIOverridesStruct;
+
+GType test_gi_overrides_struct_get_type (void) G_GNUC_CONST;
+
+TestGIOverridesStruct *test_gi_overrides_struct_new (void);
+
+glong test_gi_overrides_struct_method (TestGIOverridesStruct *struct_);
+
+TestGIOverridesStruct *test_gi__overrides_struct_return (void);
+
+
+#define TESTGI_TYPE_OVERRIDES_OBJECT             (test_gi_overrides_object_get_type ())
+#define TESTGI_OVERRIDES_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TESTGI_TYPE_OVERRIDES_OBJECT, TestGIOverridesObject))
+#define TESTGI_OVERRIDES_OBJECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), TESTGI_TYPE_OVERRIDES_OBJECT, TestGIOverridesObjectClass))
+#define TESTGI_IS_OVERRIDES_OBJECT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TESTGI_TYPE_OVERRIDES_OBJECT))
+#define TESTGI_IS_OVERRIDES_OBJECT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), TESTGI_TYPE_OVERRIDES_OBJECT))
+#define TESTGI_OVERRIDES_OBJECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), TESTGI_TYPE_OVERRIDES_OBJECT, TestGIOverridesObjectClass))
+
+typedef struct _TestGIOverridesObjectClass TestGIOverridesObjectClass;
+typedef struct _TestGIOverridesObject TestGIOverridesObject;
+
+struct _TestGIOverridesObjectClass
+{
+	GObjectClass parent_class;
+};
+
+struct _TestGIOverridesObject
+{
+	GObject parent_instance;
+
+    glong long_;
+};
+
+GType test_gi_overrides_object_get_type (void) G_GNUC_CONST;
+
+TestGIOverridesObject *test_gi_overrides_object_new (void);
+
+glong test_gi_overrides_object_method (TestGIOverridesObject *object);
+
+
+TestGIOverridesObject *test_gi__overrides_object_return (void);
+
 #endif /* __TEST_GI_H__ */
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 2cbb2eb..0d97915 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1500,3 +1500,39 @@ class TestInterfaces(unittest.TestCase):
         instance = TestInterfaceImpl()
         self.assertTrue(isinstance(instance, TestGI.Interface))
 
+
+class TestOverrides(unittest.TestCase):
+
+    def test_constant(self):
+        self.assertEquals(TestGI.OVERRIDES_CONSTANT, 7)
+
+    def test_struct(self):
+        # Test that the constructor has been overridden.
+        struct = TestGI.OverridesStruct(42)
+
+        # Test that the method has been overridden.
+        self.assertEquals(6, struct.method())
+
+        del struct
+
+        # Test that the overrides wrapper has been registered.
+        struct = TestGI.overrides_struct_return()
+
+        self.assertTrue(isinstance(struct, TestGI.OverridesStruct))
+
+        del struct
+
+    def test_struct(self):
+        # Test that the constructor has been overridden.
+        object_ = TestGI.OverridesObject(42)
+
+        # Test that the alternate constructor has been overridden.
+        object_ = TestGI.OverridesObject.new(42)
+
+        # Test that the method has been overridden.
+        self.assertEquals(6, object_.method())
+
+        # Test that the overrides wrapper has been registered.
+        object_ = TestGI.overrides_object_return()
+
+        self.assertTrue(isinstance(object_, TestGI.OverridesObject))



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