diff options
author | Tomeu Vizoso <tomeu@sugarlabs.org> | 2009-05-12 08:29:50 (GMT) |
---|---|---|
committer | Tomeu Vizoso <tomeu@sugarlabs.org> | 2009-05-12 08:29:50 (GMT) |
commit | 9576e2d88899d4dfc9c73eab333ac9819113f985 (patch) | |
tree | 4fc7dcd151aaf392e2e068f987a576196c6f7abc | |
parent | f80b39aa1b969c7e7d4a8088e7fb55c755bace7d (diff) |
Refactor type creation, use a metaclass derived from GObjectMeta
-rw-r--r-- | bank/btypes.py | 169 | ||||
-rw-r--r-- | 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 |