diff options
author | Graydon, Tracy <tracy.graydon@intel.com> | 2012-11-30 12:11:38 -0800 |
---|---|---|
committer | Graydon, Tracy <tracy.graydon@intel.com> | 2012-11-30 12:11:38 -0800 |
commit | 1a48cb6e7504163228442a2894af21af66e93eb2 (patch) | |
tree | 8d117e9778e44c485d187679bf5250c52e02975d /gi/module.py | |
parent | e319390cebb45884f62ca3c2b22984d8ed82b941 (diff) | |
download | pygobject2-1a48cb6e7504163228442a2894af21af66e93eb2.tar.gz pygobject2-1a48cb6e7504163228442a2894af21af66e93eb2.tar.bz2 pygobject2-1a48cb6e7504163228442a2894af21af66e93eb2.zip |
Update to 2.28 for TINF-96
Diffstat (limited to 'gi/module.py')
-rw-r--r-- | gi/module.py | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/gi/module.py b/gi/module.py new file mode 100644 index 0000000..70df76c --- /dev/null +++ b/gi/module.py @@ -0,0 +1,287 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2007-2009 Johan Dahlin <johan@gnome.org> +# +# module.py: dynamic module for introspected libraries. +# +# 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 + +from __future__ import absolute_import + +import os +import gobject +import string + +import gi +from .overrides import registry + +from ._gi import \ + Repository, \ + FunctionInfo, \ + RegisteredTypeInfo, \ + EnumInfo, \ + ObjectInfo, \ + InterfaceInfo, \ + ConstantInfo, \ + StructInfo, \ + UnionInfo, \ + Struct, \ + Boxed, \ + enum_add, \ + enum_register_new_gtype_and_add, \ + flags_add, \ + flags_register_new_gtype_and_add +from .types import \ + GObjectMeta, \ + StructMeta, \ + Function + +repository = Repository.get_default() + +def get_parent_for_object(object_info): + parent_object_info = object_info.get_parent() + + if not parent_object_info: + return object + + namespace = parent_object_info.get_namespace() + name = parent_object_info.get_name() + + # Workaround for GObject.Object and GObject.InitiallyUnowned. + if namespace == 'GObject' and name == 'Object' or name == 'InitiallyUnowned': + return gobject.GObject + + module = __import__('gi.repository.%s' % namespace, fromlist=[name]) + return getattr(module, name) + + +def get_interfaces_for_object(object_info): + interfaces = [] + for interface_info in object_info.get_interfaces(): + namespace = interface_info.get_namespace() + name = interface_info.get_name() + + module = __import__('gi.repository.%s' % namespace, fromlist=[name]) + interfaces.append(getattr(module, name)) + return interfaces + + +class IntrospectionModule(object): + + def __init__(self, namespace, version=None): + repository.require(namespace, version) + self._namespace = namespace + self._version = version + self.__name__ = 'gi.repository.' + namespace + + repository.require(self._namespace, self._version) + self.__path__ = repository.get_typelib_path(self._namespace) + + if self._version is None: + self._version = repository.get_version(self._namespace) + + def __getattr__(self, name): + info = repository.find_by_name(self._namespace, name) + if not info: + raise AttributeError("%r object has no attribute %r" % ( + self.__name__, name)) + + if isinstance(info, EnumInfo): + g_type = info.get_g_type() + wrapper = g_type.pytype + + if wrapper is None: + if info.is_flags(): + if g_type.is_a(gobject.TYPE_FLAGS): + wrapper = flags_add(g_type) + else: + assert g_type == gobject.TYPE_NONE + wrapper = flags_register_new_gtype_and_add(info) + else: + if g_type.is_a(gobject.TYPE_ENUM): + wrapper = enum_add(g_type) + else: + assert g_type == gobject.TYPE_NONE + wrapper = enum_register_new_gtype_and_add(info) + + wrapper.__info__ = info + wrapper.__module__ = 'gi.repository.' + info.get_namespace() + + # Don't use upper() here to avoid locale specific + # identifier conversion (e. g. in Turkish 'i'.upper() == 'i') + # see https://bugzilla.gnome.org/show_bug.cgi?id=649165 + ascii_upper_trans = string.maketrans( + 'abcdefgjhijklmnopqrstuvwxyz', + 'ABCDEFGJHIJKLMNOPQRSTUVWXYZ') + for value_info in info.get_values(): + value_name = value_info.get_name().translate(ascii_upper_trans) + setattr(wrapper, value_name, wrapper(value_info.get_value())) + + if g_type != gobject.TYPE_NONE: + g_type.pytype = wrapper + + elif isinstance(info, RegisteredTypeInfo): + g_type = info.get_g_type() + + # Check if there is already a Python wrapper. + if g_type != gobject.TYPE_NONE: + type_ = g_type.pytype + if type_ is not None: + self.__dict__[name] = type_ + return type_ + + # Create a wrapper. + if isinstance(info, ObjectInfo): + parent = get_parent_for_object(info) + interfaces = tuple(interface for interface in get_interfaces_for_object(info) + if not issubclass(parent, interface)) + bases = (parent,) + interfaces + metaclass = GObjectMeta + elif isinstance(info, InterfaceInfo): + bases = (gobject.GInterface,) + metaclass = GObjectMeta + elif isinstance(info, (StructInfo, UnionInfo)): + if g_type.is_a(gobject.TYPE_BOXED): + bases = (Boxed,) + elif g_type.is_a(gobject.TYPE_POINTER) or \ + g_type == gobject.TYPE_NONE or \ + g_type.fundamental == g_type: + bases = (Struct,) + else: + raise TypeError("unable to create a wrapper for %s.%s" % (info.get_namespace(), info.get_name())) + metaclass = StructMeta + else: + raise NotImplementedError(info) + + name = info.get_name() + dict_ = { + '__info__': info, + '__module__': 'gi.repository.' + self._namespace, + '__gtype__': g_type + } + wrapper = metaclass(name, bases, dict_) + + # Register the new Python wrapper. + if g_type != gobject.TYPE_NONE: + g_type.pytype = wrapper + + elif isinstance(info, FunctionInfo): + wrapper = Function(info) + elif isinstance(info, ConstantInfo): + wrapper = info.get_value() + else: + raise NotImplementedError(info) + + self.__dict__[name] = wrapper + return wrapper + + def __repr__(self): + path = repository.get_typelib_path(self._namespace) + return "<IntrospectionModule %r from %r>" % (self._namespace, path) + + def __dir__ (self): + # Python's default dir() is just dir(self.__class__) + self.__dict__.keys() + result = set(dir(self.__class__)) + result.update(self.__dict__.keys()) + + # update *set* because some repository attributes have already been + # wrapped by __getattr__() and included in self.__dict__ + namespace_infos = repository.get_infos(self._namespace) + result.update(info.get_name() for info in namespace_infos) + + return list(result) + + +class DynamicGObjectModule(IntrospectionModule): + """Wrapper for the GObject module + + This class allows us to access both the static PyGObject module and the GI GObject module + through the same interface. It is returned when by importing GObject from the gi repository: + + from gi.repository import GObject + + We use this because some PyGI interfaces generated from the GIR require GObject types not wrapped + by the static bindings. This also allows access to module attributes in a way that is more + familiar to GI application developers. Take signal flags as an example. The G_SIGNAL_RUN_FIRST + flag would be accessed as GObject.SIGNAL_RUN_FIRST in the static bindings but in the dynamic bindings + can be accessed as GObject.SignalFlags.RUN_FIRST. The latter follows a GI naming convention which + would be familiar to GI application developers in a number of languages. + """ + + def __init__(self): + IntrospectionModule.__init__(self, namespace='GObject') + + def __getattr__(self, name): + # first see if this attr is in the gobject module + attr = getattr(gobject, name, None) + + # if not in module assume request for an attr exported through GI + if attr is None: + attr = super(DynamicGObjectModule, self).__getattr__(name) + + return attr + + +class DynamicModule(object): + def __init__(self, namespace): + self._namespace = namespace + self._introspection_module = None + self._overrides_module = None + self.__path__ = None + + def _load(self): + version = gi.get_required_version(self._namespace) + self._introspection_module = IntrospectionModule(self._namespace, + version) + + overrides_modules = __import__('gi.overrides', fromlist=[self._namespace]) + self._overrides_module = getattr(overrides_modules, self._namespace, None) + self.__path__ = repository.get_typelib_path(self._namespace) + + def __getattr__(self, name): + if self._overrides_module is not None: + override_exports = getattr(self._overrides_module, '__all__', ()) + if name in override_exports: + return getattr(self._overrides_module, name, None) + else: + # check the registry just in case the module hasn't loaded yet + # TODO: Only gtypes are registered in the registry right now + # but it would be nice to register all overrides and + # get rid of the module imports. We might actually see a + # speedup. + key = '%s.%s' % (self._namespace, name) + if key in registry: + return registry[key] + + return getattr(self._introspection_module, name) + + def __dir__ (self): + # Python's default dir() is just dir(self.__class__) + self.__dict__.keys() + result = set(dir(self.__class__)) + result.update(self.__dict__.keys()) + + result.update(dir(self._introspection_module)) + override_exports = getattr(self._overrides_module, '__all__', ()) + result.update(override_exports) + return list(result) + + def __repr__(self): + path = repository.get_typelib_path(self._namespace) + return "<%s.%s %r from %r>" % (self.__class__.__module__, + self.__class__.__name__, + self._namespace, + path) |