[pybank] Refactor type creation, use a metaclass derived from GObjectMeta



commit 9576e2d88899d4dfc9c73eab333ac9819113f985
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Tue May 12 10:29:50 2009 +0200

    Refactor type creation, use a metaclass derived from GObjectMeta
---
 bank/btypes.py |  169 ++++++++++++++++++--------------------------------------
 bank/module.py |   15 +++--
 2 files changed, 63 insertions(+), 121 deletions(-)

diff --git a/bank/btypes.py b/bank/btypes.py
index a07f5f4..c0ffa1c 100644
--- a/bank/btypes.py
+++ b/bank/btypes.py
@@ -116,24 +116,10 @@ class Callable(object):
         retval = self.info.invoke(*args)
 
         if self.info.isConstructor():
-            if retval is None:
-                raise AssertionError(
-                    "Invoked constructor %s.%s.%s returned NULL " % (
-                    self.__module__, self.className, self.info.getName()))
-            print "mec %r" % retval
-            return retval
-
-        if type(retval).__name__ == 'PyCObject':
-             rinfo = self.info.getReturnType()
-             tag = rinfo.getTag()
-             if tag == repo.TYPE_TAG_INTERFACE:
-                 retval = self.newType(retval)
-             else:
-                 raise NotImplementedError
+            return None
 
         return retval
 
-
 class Function(Callable):
     def __init__(self, info):
         Callable.__init__(self, info)
@@ -179,6 +165,55 @@ class Method(Callable):
             self.__module__,
             self.className)
 
+class PyBankMeta(gobject.GObjectMeta):
+    def __init__(cls, name, bases, dict_):
+        print 'PyBankMeta() %r' % ((cls, name, bases, dict_),)
+
+        gobject.GObjectMeta.__init__(cls, name, bases, dict_)
+
+        needs_constructor = not '__init__' in dict_
+        cls._setup_methods(needs_constructor)
+
+        print 'dir(%s): %r' % (name, dir(cls))
+
+    def _setup_methods(cls, needs_constructor):
+        info = cls.__info__
+        constructors = []
+        static_methods = []
+        for method in info.getMethods():
+            name = method.getName()
+
+            if method.isConstructor():
+                constructors.append(method)
+            elif method.isMethod():
+                func = Method(method, cls.__name__)
+                setattr(cls, name, new.instancemethod(func, None, cls))
+            else:
+                static_methods.append(method)
+
+        winner = None
+        if needs_constructor:
+            if len(constructors) == 1:
+                winner = constructors[0]
+            else:
+                for constructor in constructors:
+                    if constructor.getName() == 'new':
+                        winner = constructor
+                        break
+
+        if winner is not None:
+            func = Method(winner, cls.__name__, call_type=Method.CLASS_METHOD)
+            func.__name__ = '__init__'
+            func.__orig_name__ = winner.getName()
+            cls.__init__ = new.instancemethod(func, None, cls)
+            print 'setting up %s as constructor of %s' % (winner.getName(), cls.__name__)
+            #constructors.remove(winner)
+
+        static_methods.extend(constructors)
+        for static_method in static_methods:
+            func = Method(static_method, cls.__name__, call_type=Method.STATIC_METHOD)
+            setattr(cls, static_method.getName(), staticmethod(func))
+
 _classDict = {}
 
 def getClass(info):
@@ -192,30 +227,7 @@ def getClass(info):
         klass = getattr(module, className)
     return klass
 
-def setupConstructors(className, cls, constructors):
-    if not constructors:
-        return
-
-    if len(constructors) == 1:
-        winner = constructors[0]
-    else:
-        winner = None
-        for constructor in constructors:
-            if constructor.getName() == 'new':
-                winner = constructor
-                break
-
-    if winner != None:
-        func = Method(winner, className, call_type=Method.CLASS_METHOD)
-        cls.__init__ = func
-        func.__name__ = "__init__"
-        constructors.remove(winner)
-
-    for constructor in constructors:
-        func = Method(constructor, className, call_type=Method.STATIC_METHOD)
-        setattr(cls, constructor.getName(), staticmethod(func))
-
-def buildClass(info, bases):
+def buildType(info, bases):
     className = info.getName()
     namespaceName = info.getNamespace()
     fullName = namespaceName + '.' + className
@@ -226,51 +238,12 @@ def buildClass(info, bases):
     namespace = {}
     namespace['__info__'] = info
     namespace['__module__'] = namespaceName
-    newType = type(className, bases, namespace)
-
-    constructors = []
-    for method in info.getMethods():
-        if method.isConstructor():
-            constructors.append(method)
-        elif method.isMethod():
-            methodName = method.getName()
-            setattr(newType, methodName, new.instancemethod(Method(method, className),
-                                                            None, newType))
-        else: # probably a static method
-            func = Method(method, className, call_type=Method.STATIC_METHOD)
-            setattr(newType, method.getName(), staticmethod(func))
-
-    setupConstructors(className, newType, constructors)
+    newType = PyBankMeta(className, bases, namespace)
 
     _classDict[fullName] = newType
     
     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
-
 class BaseBlob(object):
     """Base class for Struct, Boxed and Union.
     """
@@ -283,7 +256,7 @@ class BaseBlob(object):
         return self.__info__.getValue(self.__dict__['__buffer__'], name)
 
     def __setattr__(self, name, value):
-        print "__setattr__ %r %r" % (name, value)
+        print "__setattr__ %r %r %r" % (self, name, value)
         self.__info__.setValue(self.__dict__['__buffer__'], name, value)
 
     def __eq__(self, other):
@@ -292,39 +265,3 @@ class BaseBlob(object):
                 return False
         return True
 
-def buildBoxed(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
-
-    bases = (BaseBlob,)
-    if isinstance(info, repo.BoxedInfo):
-        bases += gobject.Boxed
-
-    newType = type(className, bases, namespace)
-
-    constructors = []
-    for method in info.getMethods():
-        if method.isConstructor():
-            constructors.append(method)
-        elif method.isMethod():
-            methodName = method.getName()
-            setattr(newType, methodName, new.instancemethod(Method(method, className),
-                                                            None, newType))
-        else: # probably a static method
-            func = Method(method, className, call_type=Method.STATIC_METHOD)
-            setattr(newType, method.getName(), staticmethod(func))
-
-    setupConstructors(className, newType, constructors)
-
-    _classDict[fullName] = newType
-    
-    return newType
-
diff --git a/bank/module.py b/bank/module.py
index 32d1986..65deea1 100644
--- a/bank/module.py
+++ b/bank/module.py
@@ -22,9 +22,9 @@ import os
 import gobject
 from gobject import GEnum
 
-from .btypes import Function, buildClass, buildInterface, buildBoxed
+from .btypes import Function, BaseBlob, buildType
 from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, \
-                  InterfaceInfo, StructInfo
+                  InterfaceInfo, StructInfo, BoxedInfo
 from .repository import repository
 
 class DynamicModule(object):
@@ -140,7 +140,7 @@ class DynamicModule(object):
             return klass
 
         parent = self._get_parent_for_object(object_info)
-        klass = buildClass(object_info, (parent,))
+        klass = buildType(object_info, (parent,))
         if gtype is not None:
             gtype.pytype = klass
         self.__dict__[name] = klass
@@ -178,7 +178,8 @@ class DynamicModule(object):
         if klass:
             return klass
 
-        klass = buildInterface(interface_info)
+        bases = (gobject.GInterface,)
+        klass = buildType(interface_info, bases)
         if gtype is not None:
             klass.__gtype__ = gtype
             gtype.pytype = klass
@@ -207,7 +208,11 @@ class DynamicModule(object):
         if klass:
             return klass
 
-        klass = buildBoxed(boxed_info)
+        bases = (BaseBlob,)
+        if isinstance(boxed_info, BoxedInfo):
+            bases += gobject.Boxed
+
+        klass = buildType(boxed_info, bases)
         if gtype is not None:
             gtype.pytype = klass
         self.__dict__[name] = klass



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