# -*- Mode: Python; py-indent-offset: 4 -*- # # Copyright (C) 2007 Johan Dahlin # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import os import gobject from gobject import GEnum from .btypes import Function, BaseBlob, buildType from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, \ InterfaceInfo, StructInfo, BoxedInfo from .repository import repository class DynamicModule(object): def __init__(self, namespace, path): self._namespace = namespace self._path = path repository.register(self, namespace, path) self.created() @property def __file__(self): return self._namespace @property def __name__(self): return self._namespace @property def __path__(self): return [os.path.dirname(self.__file__)] def __repr__(self): return "" % (self._namespace, self._path) def __getattr__(self, name): type_info = repository.get_by_name(self._namespace, name) if not type_info: raise AttributeError("%r object has no attribute %r" % ( self.__class__.__name__, name)) value = self._create_attribute(name, type_info) self.__dict__[name] = value return value @property def __members__(self): r = [] for type_info in repository.get_infos(self._namespace): if type_info is None: continue r.append(type_info.getName()) return r # Override this in a subclass def created(self): pass # Private API def _create_attribute(self, attr, type_info): if isinstance(type_info, ObjectInfo): return self._create_object(type_info) elif isinstance(type_info, EnumInfo): 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) elif isinstance(type_info, StructInfo) or \ isinstance(type_info, BoxedInfo): return self._create_boxed(type_info) else: raise NotImplementedError(type_info) def _get_parent_for_object(self, object_info): parent_info = object_info.getParent() if isinstance(parent_info, UnresolvedInfo): namespace = parent_info.getNamespace() __import__(namespace) parent_info = object_info.getParent() if not parent_info: parent = object else: namespace = parent_info.getNamespace() module = repository.get_module(namespace) name = parent_info.getName() try: # Hack for gobject.Object if module == gobject and name == 'Object': name = 'GObject' parent = getattr(module, name) except AttributeError: return self._get_parent_for_object(parent_info) if parent is None: parent = object return parent def _create_object(self, object_info): name = object_info.getName() namespace = repository.get_c_prefix(object_info.getNamespace()) full_name = namespace + name object_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 parent = self._get_parent_for_object(object_info) klass = buildType(object_info, (parent,)) if gtype is not None: klass.__gtype__ = gtype gtype.pytype = klass self.__dict__[name] = klass return klass def _create_enum(self, enum_info): ns = dict(__name__=enum_info.getName(), __module__=enum_info.getNamespace()) for value in enum_info.getValues(): ns[value.getName().upper()] = value.getValue() return type(enum_info.getName(), (GEnum,), ns) 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 bases = (gobject.GInterface,) klass = buildType(interface_info, bases) if gtype is not None: klass.__gtype__ = gtype gtype.pytype = klass interface_info.register() self.__dict__[name] = klass return klass def _create_boxed(self, boxed_info): name = boxed_info.getName() namespace = repository.get_c_prefix(boxed_info.getNamespace()) full_name = namespace + name boxed_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 bases = (BaseBlob,) if isinstance(boxed_info, BoxedInfo): bases += gobject.Boxed klass = buildType(boxed_info, bases) if gtype is not None: klass.__gtype__ = gtype gtype.pytype = klass self.__dict__[name] = klass return klass