diff options
Diffstat (limited to 'girepository/module.py')
-rw-r--r-- | girepository/module.py | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/girepository/module.py b/girepository/module.py new file mode 100644 index 0000000..2a87816 --- /dev/null +++ b/girepository/module.py @@ -0,0 +1,224 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2007 Johan Dahlin <johan@gnome.org> +# +# 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 "<dyn-module %r from %r>" % (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 + |