[pybank] Add support for interfaces



commit 5bc86e4b48415128d8bcef9559ad6be8898535b9
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Wed May 6 15:16:32 2009 +0200

    Add support for interfaces
---
 bank/bank-info.c       |   22 ++++++++++++++++++++++
 bank/btypes.py         |   26 ++++++++++++++++++++++++++
 bank/module.py         |   35 +++++++++++++++++++++++++++++++++--
 everything_unittest.py |    5 +++++
 4 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/bank/bank-info.c b/bank/bank-info.c
index 041ff06..77f6be4 100644
--- a/bank/bank-info.c
+++ b/bank/bank-info.c
@@ -601,7 +601,29 @@ static PyMethodDef _PyGIObjectInfo_methods[] = {
 /* GIInterfaceInfo */
 NEW_CLASS("InterfaceInfo", GIInterfaceInfo);
 
+static PyObject *
+_wrap_g_interface_info_get_methods(PyGIBaseInfo *self)
+{
+    int i, length;
+    PyObject *retval;
+
+    g_base_info_ref(self->info);
+    length = g_interface_info_get_n_methods((GIInterfaceInfo*)self->info);
+    retval = PyTuple_New(length);
+
+    for (i = 0; i < length; i++) {
+        GIFunctionInfo *function;
+        function = g_interface_info_get_method((GIInterfaceInfo*)self->info, i);
+        PyTuple_SetItem(retval, i, pyg_info_new(function));
+        g_base_info_unref((GIBaseInfo*)function);
+    }
+    g_base_info_unref(self->info);
+
+    return retval;
+}
+
 static PyMethodDef _PyGIInterfaceInfo_methods[] = {
+    { "getMethods", (PyCFunction)_wrap_g_interface_info_get_methods, METH_NOARGS },
     { NULL, NULL, 0 }
 };
 
diff --git a/bank/btypes.py b/bank/btypes.py
index c9a68da..8a8b35b 100644
--- a/bank/btypes.py
+++ b/bank/btypes.py
@@ -17,6 +17,8 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
 
+import gobject
+
 import new
 
 from bank import repo
@@ -255,4 +257,28 @@ def buildClass(info, bases):
     
     return newType
 
+def buildInterface(info):
+    className = info.getName()
+    namespaceName = info.getNamespace()
+    fullName = namespaceName + '.' + className
+
+    if _classDict.has_key(fullName):
+        return _classDict[fullName]
+
+    namespace = {}
+    namespace['__info__'] = info
+    namespace['__module__'] = namespaceName
+    newType = type(className, (gobject.GInterface,), namespace)
+
+    for method in info.getMethods():
+        if method.isMethod():
+            methodName = method.getName()
+            setattr(newType, methodName, new.instancemethod(Method(method, className),
+                                                            None, newType))
+        else:
+            raise ValueError('Interfaces can only have regular methods')
+
+    _classDict[fullName] = newType
+
+    return newType
 
diff --git a/bank/module.py b/bank/module.py
index 14bf656..523504c 100644
--- a/bank/module.py
+++ b/bank/module.py
@@ -22,8 +22,8 @@ import os
 import gobject
 from gobject import GEnum
 
-from .btypes import Function, buildClass
-from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo
+from .btypes import Function, buildClass, buildInterface
+from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, InterfaceInfo
 from .repository import repository
 
 class DynamicModule(object):
@@ -83,6 +83,8 @@ class DynamicModule(object):
             return self._create_enum(type_info)
         elif isinstance(type_info, FunctionInfo):
             return self._create_function(type_info)
+        elif isinstance(type_info, InterfaceInfo):
+            return self._create_interface(type_info)
         else:
             raise NotImplementedError(type_info)
 
@@ -150,3 +152,32 @@ class DynamicModule(object):
 
     def _create_function(self, function_info):
         return Function(function_info)
+
+    def _create_interface(self, interface_info):
+        name = interface_info.getName()
+
+        namespace = repository.get_c_prefix(interface_info.getNamespace())
+        full_name = namespace + name
+        interface_info.getGType()
+        gtype = None
+        try:
+            gtype = gobject.GType.from_name(full_name)
+        except RuntimeError:
+            pass
+        else:
+            if gtype.pytype is not None:
+                return gtype.pytype
+        # Check if the klass is already created, eg
+        # present in our namespace, this is necessary since we're
+        # not always entering here through the __getattr__ hook.
+        klass = self.__dict__.get(name)
+        if klass:
+            return klass
+
+        klass = buildInterface(interface_info)
+        if gtype is not None:
+            klass.__gtype__ = gtype
+            gtype.pytype = klass
+        self.__dict__[name] = klass
+
+        return klass
diff --git a/everything_unittest.py b/everything_unittest.py
index 7d946e4..384e590 100644
--- a/everything_unittest.py
+++ b/everything_unittest.py
@@ -252,5 +252,10 @@ class TestGIEverything(unittest.TestCase):
         Everything.test_struct_b_clone(b, b_out)
         self.assertEquals(b, b_out)
 
+    def testInterface(self):
+        self.assertTrue(issubclass(Everything.TestInterface, gobject.GInterface))
+        self.assertRaises(NotImplementedError, Everything.TestInterface)
+        self.assertEquals(Everything.TestInterface.__gtype__.name, 'EverythingTestInterface')
+
 if __name__ == '__main__':
     unittest.main()



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