[pygobject/gsoc2009: 30/160] Large refactoring of Python code and more



commit b7cabdb9cdc9146c5c173357f4c7b24f50418a6c
Author: Simon van der Linden <svdlinden src gnome org>
Date:   Thu Jul 9 17:20:37 2009 +0200

    Large refactoring of Python code and more
    
    Make the non-default constructors work, even for subclasses.
    Add instance checking for methods.
    Add class checking for constructors.
    Add tests for Python subclassing.

 girepository/bank-info.c      |  195 ++++++++++++++++++++++++--------
 girepository/btypes.py        |  237 +++++++++++++--------------------------
 girepository/module.py        |  251 ++++++++++++++---------------------------
 girepository/overrides/Gdk.py |    5 +-
 girepository/overrides/Gtk.py |    5 +-
 tests/test_girepository.py    |  154 ++++++++++++++++++++-----
 6 files changed, 439 insertions(+), 408 deletions(-)
---
diff --git a/girepository/bank-info.c b/girepository/bank-info.c
index 2a63274..b3fcebe 100644
--- a/girepository/bank-info.c
+++ b/girepository/bank-info.c
@@ -21,6 +21,8 @@
 #include "bank.h"
 #include <pygobject.h>
 
+static PyTypeObject *PyGObject_Type = NULL;
+
 static void      pyg_base_info_dealloc(PyGIBaseInfo *self);
 static void      pyg_base_info_free(PyObject *op);
 static PyObject* pyg_base_info_repr(PyGIBaseInfo *self);
@@ -469,8 +471,133 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
         }
 
         /* Check argument types. */
-        py_args_pos = (is_method || is_constructor) ? 1 : 0;
-        /* TODO: check the methods' first argument. */
+        py_args_pos = 0;
+        if (is_constructor) {
+            PyObject *py_arg;
+
+            g_assert(n_py_args > 0);
+            py_arg = PyTuple_GetItem(args, py_args_pos);
+            g_assert(py_arg != NULL);
+
+            if (PyGObject_Type == NULL) {
+                PyObject *module;
+                if ((module = PyImport_ImportModule("gobject")) != NULL) {
+                    PyGObject_Type = (PyTypeObject *)PyObject_GetAttrString(module, "GObject");
+                }
+            }
+
+            if (!PyType_Check(py_arg)) {
+                PyErr_Format(PyExc_TypeError, "%s.%s() argument %zd: Must be type, not %s",
+                    g_base_info_get_namespace(self->info), g_base_info_get_name(self->info),
+                    py_args_pos, ((PyTypeObject *)py_arg)->tp_name);
+            } else if (!PyType_IsSubtype((PyTypeObject *)py_arg, PyGObject_Type)) {
+                PyErr_Format(PyExc_TypeError, "%s.%s() argument %zd: Must be a non-strict subclass of %s",
+                    g_base_info_get_namespace(self->info), g_base_info_get_name(self->info),
+                    py_args_pos, PyGObject_Type->tp_name);
+            } else {
+                GIBaseInfo *interface_info;
+                GType interface_g_type;
+                GType arg_g_type;
+
+                interface_info = g_type_info_get_interface(return_info);
+
+                interface_g_type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)interface_info);
+                arg_g_type = pyg_type_from_object(py_arg);
+
+                if (!g_type_is_a(arg_g_type, interface_g_type)) {
+                    PyErr_Format(PyExc_TypeError, "%s.%s() argument %zd: Must be a non-strict subclass of %s",
+                        g_base_info_get_namespace(self->info), g_base_info_get_name(self->info),
+                        py_args_pos, g_type_name(interface_g_type));
+                }
+
+                g_base_info_unref(interface_info);
+            }
+
+            if (PyErr_Occurred()) {
+                g_base_info_unref((GIBaseInfo *)return_info);
+                return NULL;
+            }
+
+            py_args_pos += 1;
+        } else if (is_method) {
+            PyObject *py_arg;
+            GIBaseInfo *container_info;
+            GIInfoType container_info_type;
+
+            g_assert(n_py_args > 0);
+            py_arg = PyTuple_GetItem(args, py_args_pos);
+            g_assert(py_arg != NULL);
+
+            container_info = g_base_info_get_container(self->info);
+            container_info_type = g_base_info_get_type(container_info);
+
+            /* FIXME: this could take place in pyg_argument_from_pyobject, but we need to create an
+               independant function because it needs a GITypeInfo to be passed. */
+
+            switch(container_info_type) {
+                case GI_INFO_TYPE_OBJECT:
+                {
+                    PyObject *py_type;
+                    GType container_g_type;
+                    GType arg_g_type;
+
+                    py_type = PyObject_Type(py_arg);
+                    g_assert(py_type != NULL);
+
+                    container_g_type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)container_info);
+                    arg_g_type = pyg_type_from_object(py_arg);
+
+                    /* Note: If the first argument is not an instance, its type hasn't got a gtype. */
+                    if (!g_type_is_a(arg_g_type, container_g_type)) {
+                        PyErr_Format(PyExc_TypeError, "%s.%s() argument %zd: Must be %s, not %s",
+                            g_base_info_get_namespace(self->info), g_base_info_get_name(self->info),
+                            py_args_pos, g_base_info_get_name(container_info), ((PyTypeObject *)py_type)->tp_name);
+                    }
+
+                    Py_DECREF(py_type);
+
+                    break;
+                }
+                case GI_INFO_TYPE_BOXED:
+                case GI_INFO_TYPE_STRUCT:
+                {
+                    GIBaseInfo *info;
+
+                    info = pyg_base_info_from_object(py_arg);
+                    if (info == NULL || !g_base_info_equals(info, container_info)) {
+                        PyObject *py_type;
+
+                        py_type = PyObject_Type(py_arg);
+                        g_assert(py_type != NULL);
+
+                        PyErr_Format(PyExc_TypeError, "%s.%s() argument %zd: Must be %s, not %s",
+                            g_base_info_get_namespace(self->info), g_base_info_get_name(self->info),
+                            py_args_pos, g_base_info_get_name(container_info), ((PyTypeObject *)py_type)->tp_name);
+
+                        Py_DECREF(py_type);
+                    }
+
+                    if (info != NULL) {
+                        g_base_info_unref(info);
+                    }
+
+                    break;
+                }
+                case GI_INFO_TYPE_UNION:
+                    /* TODO */
+                default:
+                    /* The other info types haven't got methods. */
+                    g_assert_not_reached();
+            }
+
+            g_base_info_unref(container_info);
+
+            if (PyErr_Occurred()) {
+                return NULL;
+            }
+
+            py_args_pos += 1;
+        }
         for (i = 0; i < n_args; i++) {
             GIArgInfo *arg_info;
             GITypeInfo *type_info;
@@ -758,58 +885,32 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
 
             g_assert(return_value != NULL);
         } else {
-            /* Wrap the return value inside the first argument. */
+            /* Instanciate the class passed as first argument and attach the GObject instance. */
+            PyTypeObject *py_type;
+            PyGObject *self;
 
             g_assert(n_py_args > 0);
-            return_value = PyTuple_GetItem(args, 0);
-            g_assert(return_value != NULL);
-
-            Py_INCREF(return_value);
-
-            if (return_tag == GI_TYPE_TAG_INTERFACE) {
-                GIBaseInfo *interface_info;
-                GIInfoType interface_info_type;
-
-                interface_info = g_type_info_get_interface(return_info);
-                interface_info_type = g_base_info_get_type(interface_info);
-
-                if (interface_info_type == GI_INFO_TYPE_STRUCT || interface_info_type == GI_INFO_TYPE_BOXED) {
-                    /* FIXME: We should reuse this. Perhaps by separating the
-                     * wrapper creation from the binding to the wrapper.
-                     */
-                    GIStructInfo *struct_info;
-                    gsize size;
-                    PyObject *buffer;
-                    int retval;
-
-                    struct_info = g_interface_info_get_iface_struct((GIInterfaceInfo *)interface_info);
-
-                    size = g_struct_info_get_size (struct_info);
-                    g_assert(size > 0);
+            py_type = (PyTypeObject *)PyTuple_GetItem(args, 0);
+            g_assert(py_type != NULL);
 
-                    buffer = PyBuffer_FromReadWriteMemory(return_arg.v_pointer, size);
-
-                    retval = PyObject_SetAttrString(return_value, "__buffer__", buffer);
-                    g_assert(retval != -1);
+            if (py_type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+                Py_INCREF(py_type);
+            }
+            self = PyObject_GC_New(PyGObject, py_type);
+            self->inst_dict = NULL;
+            self->weakreflist = NULL;
+            self->private_flags.flags = 0;
 
-                    g_base_info_unref((GIBaseInfo *)struct_info);
-                } else {
-                    PyGObject *gobject;
+            self->obj = return_arg.v_pointer;
 
-                    gobject = (PyGObject *) return_value;
-                    gobject->obj = return_arg.v_pointer;
+            if (g_object_is_floating(self->obj)) {
+                g_object_ref_sink(self->obj);
+            }
+            pygobject_register_wrapper((PyObject *)self);
 
-                    g_object_ref(gobject->obj);
-                    pygobject_register_wrapper(return_value);
-                }
+            PyObject_GC_Track((PyObject *)self);
 
-                g_base_info_unref(interface_info);
-            } else {
-                /* TODO */
-                g_base_info_unref((GIBaseInfo *)return_info);
-                PyErr_SetString(PyExc_NotImplementedError, "constructor return_tag != GI_TYPE_TAG_INTERFACE");
-                return NULL;
-            }
+            return_value = (PyObject *)self;
         }
     } else {
         return_value = NULL;
diff --git a/girepository/btypes.py b/girepository/btypes.py
index 54b5268..f4673bd 100644
--- a/girepository/btypes.py
+++ b/girepository/btypes.py
@@ -19,200 +19,117 @@
 
 import gobject
 
-import new
+from new import instancemethod
 
 from . import repo
-
+from .repo import InterfaceInfo, ObjectInfo, StructInfo, EnumInfo
 from .repository import repository
 
-class Callable(object):
-
-    # Types of callables
-    INSTANCE_METHOD = 'method'
-    STATIC_METHOD = 'static'
-    CLASS_METHOD = 'class'
-    FUNTION = 'function'
 
-    def __init__(self, info):
-        self.info = info
-        self.call_type = None
+def Function(info):
 
-    def __call__(self, *args, **kwargs):
-        # TODO: put the kwargs in their right positions
-        totalInArgs = args + tuple(kwargs.values())
+    def function(*args):
+        return info.invoke(*args)
+    function.__info__ = info
+    function.__name__ = info.getName()
+    function.__module__ = info.getNamespace()
 
-        retval = self.info.invoke(*totalInArgs)
+    return function
 
-        if self.info.isConstructor():
-            return None
 
-        return retval
+class Field(object):
 
-class Function(Callable):
     def __init__(self, info):
-        Callable.__init__(self, info)
         self.info = info
-        self.static = True
-
-    def __repr__(self):
-        return "<function %s>" % (self.info.getName(),)
-
 
-class Method(Callable):
+    def __get__(self, instance, owner):
+        return self.info.getValue(instance)
 
-    def __init__(self, info, className, call_type=Callable.INSTANCE_METHOD):
-        Callable.__init__(self, info)
-        self.object = None
-        self.className = className
-        self.call_type = call_type
-        self.__name__ = info.getName()
-        self.__module__ = info.getNamespace()
+    def __set__(self, instance, value):
+        return self.info.setValue(instance, value)
 
-    def newType(self, retval, type_info=None):
-        if type_info == None:
-            type_info = self.info.getReturnType()
 
-        info = type_info.getInterface()
-        klass = getClass(info)
-        obj = klass.__new__(klass)
-        obj._object = retval
-        return obj
+class GObjectIntrospectionMeta(gobject.GObjectMeta):
 
-    #def __get__(self, instance, type):
-        #if instance is None:
-            #return self
-
-        #def wrapper(*args, **kwargs):
-            #return self(instance, *args, **kwargs)
-
-        #return wrapper
-
-    def __repr__(self):
-        return "<method %s of %s.%s object>" % (
-            self.__name__,
-            self.__module__,
-            self.className)
-
-class FieldDescriptor(object):
-    def __init__(self, info):
-        self._info = info
-
-    def __get__(self, obj, klass=None):
-        return self._info.getValue(obj)
-
-    def __set__(self, obj, value):
-        return self._info.setValue(obj, value)
-
-class PyBankMeta(gobject.GObjectMeta):
     def __init__(cls, name, bases, dict_):
-        gobject.GObjectMeta.__init__(cls, name, bases, dict_)
+        super(GObjectIntrospectionMeta, cls).__init__(name, bases, dict_)
 
         if hasattr(cls, '__gtype__'):
             repo.setObjectHasNewConstructor(cls.__gtype__)
 
-        # Only set up the wrapper methods and fields in their base classes
-        if name == cls.__info__.getName():
-            needs_constructor = not '__init__' in dict_
-            cls._setup_methods(needs_constructor)
+        # Only set up the wrapper methods and fields in their base classes.
+        if cls.__name__ == cls.__info__.getName():
+            if isinstance(cls.__info__, InterfaceInfo):
+                cls._setup_methods()
 
-            if hasattr(cls.__info__, 'getFields'):
+            if isinstance(cls.__info__, ObjectInfo):
                 cls._setup_fields()
+                cls._setup_methods()
 
-    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)
-
-        if hasattr(info, 'getInterfaces'):
-            for interface in info.getInterfaces():
-                for method in interface.getMethods():
-                    name = method.getName()
-                    if method.isMethod():
-                        func = Method(method, interface.getName())
-                        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]
+            if isinstance(cls.__info__, StructInfo):
+                cls._setup_fields()
+                cls._setup_methods()
+
+            if isinstance(cls.__info__, EnumInfo):
+                cls._setup_values()
+
+    def _setup_methods(cls):
+        constructor_infos = []
+        method_infos = cls.__info__.getMethods()
+        if hasattr(cls.__info__, 'getInterfaces'):
+            method_infos += reduce(lambda x, y: x + y, [interface_info.getMethods() for interface_info in cls.__info__.getInterfaces()], ())
+
+        for method_info in method_infos:
+            name = method_info.getName()
+            function = Function(method_info)
+            if method_info.isMethod():
+                method = instancemethod(function, None, cls)
+            elif method_info.isConstructor():
+                method = classmethod(function)
             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)
-            # TODO: do we want the constructor as a static method?
-            #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))
+                method = staticmethod(function)
+            setattr(cls, name, method)
+
+            if method_info.isConstructor():
+                constructor_infos.append(method_info)
+
+        default_constructor_info = None
+        if len(constructor_infos) == 1:
+            (default_constructor_info,) = constructor_infos
+        else:
+            for constructor_info in constructor_infos:
+                if constructor_info.getName() == 'new':
+                    default_constructor_info = constructor_info
+                    break
+
+        if default_constructor_info is not None:
+            function = Function(default_constructor_info)
+            cls.__new__ = staticmethod(function)
+            # Override the initializer because of the constructor's arguments
+            cls.__init__ = lambda self, *args, **kwargs: super(cls, self).__init__()
 
     def _setup_fields(cls):
-        info = cls.__info__
-        for field in info.getFields():
-            name = field.getName().replace('-', '_')
-            setattr(cls, name, FieldDescriptor(field))
-
-_classDict = {}
-
-def getClass(info):
-    className = info.getName()
-    namespaceName = info.getNamespace()
-    fullName = namespaceName + '.' + className
-
-    klass = _classDict.get(fullName)
-    if klass is None:
-        module = repository.get_module(info.getNamespace())
-        klass = getattr(module, className)
-    return klass
-
-def buildType(info, bases):
-    className = info.getName()
-    namespaceName = info.getNamespace()
-    fullName = namespaceName + '.' + className
-
-    if _classDict.has_key(fullName):
-        return _classDict[fullName]
+        for field_info in cls.__info__.getFields():
+            name = field_info.getName().replace('-', '_')
+            setattr(cls, name, Field(field_info))
 
-    namespace = {}
-    namespace['__info__'] = info
-    namespace['__module__'] = namespaceName
-    newType = PyBankMeta(className, bases, namespace)
+    def _setup_values(cls):
+        for value_info in cls.__info__.getValues():
+            name = value_info.getName().upper()
+            setattr(cls, name, value_info.getValue())
 
-    _classDict[fullName] = newType
 
-    return newType
+class GIStruct(object):
 
-class BaseBlob(object):
-    """Base class for Struct, Boxed and Union.
-    """
-    def __init__(self, buf=None):
-        if buf is None:
-            buf = self.__info__.newBuffer()
-        self.__buffer__ = buf
+    def __init__(self, buffer=None):
+        if buffer is None:
+            buffer = self.__info__.newBuffer()
+        self.__buffer__ = buffer
 
     def __eq__(self, other):
-        for field in self.__info__.getFields():
-            if getattr(self, field.getName()) != getattr(other, field.getName()):
+        for field_info in self.__info__.getFields():
+            name = field_info.getName()
+            if getattr(self, name) != getattr(other, name):
                 return False
         return True
 
diff --git a/girepository/module.py b/girepository/module.py
index 6b6b875..d8a086f 100644
--- a/girepository/module.py
+++ b/girepository/module.py
@@ -20,19 +20,54 @@
 import os
 
 import gobject
-from gobject import GEnum
+from gobject import \
+    GObject, \
+    GInterface, \
+    GEnum
 
-from .btypes import Function, BaseBlob, buildType
-from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, \
-                  InterfaceInfo, StructInfo, BoxedInfo
 from .repository import repository
+from .btypes import \
+    GObjectIntrospectionMeta, \
+    GIStruct, \
+    Function
+from .repo import \
+    UnresolvedInfo, \
+    FunctionInfo, \
+    RegisteredTypeInfo, \
+    EnumInfo, \
+    ObjectInfo, \
+    InterfaceInfo, \
+    StructInfo, \
+    BoxedInfo
+
+
+def get_parent_for_object(object_info):
+    parent_object_info = object_info.getParent()
+
+    if not parent_object_info:
+        return object
+
+    namespace = parent_object_info.getNamespace()
+    if isinstance(parent_object_info, UnresolvedInfo):
+        # Import the module and try again.
+        __import__(namespace)
+        parent_object_info = object_info.getParent()
+
+    module = repository.get_module(namespace)
+    name = parent_object_info.getName()
+    # Workaround for gobject.Object.
+    if module == gobject and name == 'Object' or name == 'InitiallyUnowned':
+        return GObject
+
+    return getattr(module, name)
+
 
 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):
@@ -50,12 +85,53 @@ class DynamicModule(object):
         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:
+        info = repository.get_by_name(self._namespace, name)
+        if not info:
             raise AttributeError("%r object has no attribute %r" % (
                     self.__class__.__name__, name))
 
-        value = self._create_attribute(name, type_info)
+        if isinstance(info, StructInfo):
+            # FIXME: This could be wrong for structures that are registered (like GValue or GClosure).
+            bases = (GIStruct,)
+            name = info.getName()
+            dict_ = {
+                '__info__': info,
+                '__module__': info.getNamespace()
+            }
+            value = GObjectIntrospectionMeta(name, bases, dict_)
+        elif isinstance(info, RegisteredTypeInfo):
+            # Check if there is already a Python wrapper.
+            gtype = info.getGType()
+            if gtype.pytype is not None:
+                self.__dict__[name] = gtype.pytype
+                return
+
+            # Create a wrapper.
+            if isinstance(info, ObjectInfo):
+                parent = get_parent_for_object(info)
+                bases = (parent,)
+            elif isinstance(info, InterfaceInfo):
+                bases = (GInterface,)
+            elif isinstance(info, EnumInfo):
+                bases = (GEnum,)
+            elif isinstance(info, BoxedInfo):
+                bases = (GBoxed,)
+            else:
+                raise NotImplementedError(info)
+
+            name = info.getName()
+            dict_ = {
+                '__info__': info,
+                '__module__': info.getNamespace(),
+                '__gtype__': gtype
+            }
+            value = GObjectIntrospectionMeta(name, bases, dict_)
+            gtype.pytype = value
+        elif isinstance(info, FunctionInfo):
+            value = Function(info)
+        else:
+            raise NotImplementedError(info)
+
         self.__dict__[name] = value
         return value
 
@@ -68,162 +144,3 @@ class DynamicModule(object):
             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
-
-        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 None:
-            gtype = boxed_info.getGType()
-
-        klass.__gtype__ = gtype
-        gtype.pytype = klass
-
-        self.__dict__[name] = klass
-
-        return klass
-
diff --git a/girepository/overrides/Gdk.py b/girepository/overrides/Gdk.py
index 304817b..94b0eaf 100644
--- a/girepository/overrides/Gdk.py
+++ b/girepository/overrides/Gdk.py
@@ -3,7 +3,10 @@ import sys
 from girepository.module import DynamicModule
 
 class GdkModule(DynamicModule):
-    def created(self):
+
+    def __init__(self, *args):
+        super(GdkModule, self).__init__(*args)
+
         initialized, argv = self.init_check(tuple(sys.argv))
         if not initialized:
             raise RuntimeError("Gdk couldn't be initialized")
diff --git a/girepository/overrides/Gtk.py b/girepository/overrides/Gtk.py
index a819183..51c93f8 100644
--- a/girepository/overrides/Gtk.py
+++ b/girepository/overrides/Gtk.py
@@ -3,7 +3,10 @@ import sys
 from girepository.module import DynamicModule
 
 class GtkModule(DynamicModule):
-    def created(self):
+
+    def __init__(self, *args):
+        super(GtkModule, self).__init__(*args)
+
         initialized, argv = self.init_check(tuple(sys.argv))
         if not initialized:
             raise RuntimeError("Gtk couldn't be initialized")
diff --git a/tests/test_girepository.py b/tests/test_girepository.py
index d489949..a9cbdb0 100644
--- a/tests/test_girepository.py
+++ b/tests/test_girepository.py
@@ -426,6 +426,9 @@ class TestGIEverything(unittest.TestCase):
         self.assertRaises(TypeError, o.connect, 'invalid-signal', signal_handler)
         self.assertRaises(TypeError, o.emit, 'invalid-signal')
 
+
+# Structures
+
     def testStructA(self):
         a = createStructA()
         self.assertEquals(a.some_int, 3)
@@ -441,6 +444,9 @@ class TestGIEverything(unittest.TestCase):
         a.clone(a_out)
         self.assertEquals(a, a_out)
 
+        # Test instance checking by passing a wrong instance.
+        self.assertRaises(TypeError, Everything.TestStructA.clone, 'a', a_out)
+
     def testStructB(self):
         b = Everything.TestStructB()
         b.some_int8 = 3
@@ -448,9 +454,9 @@ class TestGIEverything(unittest.TestCase):
         b.nested_a = a
         self.assertEquals(a, b.nested_a)
 
+        # Test assignment checking.
         self.assertRaises(TypeError, setattr, b, 'nested_a', 'a')
-        # FIXME: Doesn't work because there is no other GType than Void associated with non-boxed structures.
-        #self.assertRaises(TypeError, setattr, b, 'nested_a', Everything.TestStructB())
+        self.assertRaises(TypeError, setattr, b, 'nested_a', Everything.TestStructB())
 
         b_out = Everything.TestStructB()
         b.clone(b_out)
@@ -479,6 +485,11 @@ class TestGIEverything(unittest.TestCase):
         self.assertTrue(a.equals(a_out))
         self.assertEquals(a, a_out)
 
+        # Test instance checking by passing a wrong instance.
+        self.assertRaises(TypeError, Everything.TestSimpleBoxedA.copy, 'a')
+        self.assertRaises(TypeError, Everything.TestSimpleBoxedA.copy, gobject.GObject())
+
+        # Test boxed as return value.
         a_const = Everything.test_simple_boxed_a_const_return()
         self.assertEquals(5, a_const.some_int)
         self.assertEquals(6, a_const.some_int8)
@@ -499,58 +510,137 @@ class TestGIEverything(unittest.TestCase):
         self.assertEquals(b, b_out)
 
 
-    def testInterface(self):
-        self.assertTrue(issubclass(Everything.TestInterface, gobject.GInterface))
-        self.assertRaises(NotImplementedError, Everything.TestInterface)
-        self.assertEquals(Everything.TestInterface.__gtype__.name, 'EverythingTestInterface')
+# GObject
+
+    def testObj(self):
+        # Test inheritance.
+        self.assertTrue(issubclass(Everything.TestObj, gobject.GObject))
+        self.assertEquals(Everything.TestObj.__gtype__, Everything.TestObj.__info__.getGType())
 
-    def testConstructor(self):
-        self.assertTrue(isinstance(Everything.TestObj("foo"), Everything.TestObj))
+    def testDefaultConstructor(self):
+        # Test instanciation.
+        obj = Everything.TestObj('foo')
+        self.assertTrue(isinstance(obj, Everything.TestObj))
+
+        # Test the argument count.
         self.assertRaises(TypeError, Everything.TestObj)
-        self.assertRaises(TypeError, Everything.TestObj.__init__, None, 'foo')
         self.assertRaises(TypeError, Everything.TestObj, 'foo', 'bar')
-        self.assertRaises(TypeError, Everything.TestObj, 42)
+
+    def testAlternateConstructor(self):
+        # Test instanciation.
+        obj = Everything.TestObj.new_from_file('foo')
+        self.assertTrue(isinstance(obj, Everything.TestObj))
+
+        obj = obj.new_from_file('foo')
+        self.assertTrue(isinstance(obj, Everything.TestObj))
+
+        # Test the argument count.
+        self.assertRaises(TypeError, Everything.TestObj.new_from_file)
+        self.assertRaises(TypeError, Everything.TestObj.new_from_file, 'foo', 'bar')
 
     def testInstanceMethod(self):
-        o = Everything.TestObj('foo')
-        self.assertEquals(-1, o.instance_method())
-        self.assertRaises(TypeError, o.instance_method, 'foo')
-        self.assertRaises(TypeError, Everything.TestObj.instance_method, gobject.GObject())
+        obj = Everything.TestObj('foo')
 
-    def testlVirtualMethod(self):
-        o = Everything.TestObj('foo')
-        self.assertEquals(42, o.do_matrix('matrix'))
-        self.assertRaises(TypeError, o.do_matrix)
-        self.assertRaises(TypeError, o.do_matrix, 'matrix', 'foo')
+        # Test call.
+        self.assertEquals(-1, obj.instance_method())
+
+        # Test argument count.
+        self.assertRaises(TypeError, obj.instance_method, 'foo')
+
+        # Test instance checking by passing a wrong instance.
+        obj = gobject.GObject()
+        self.assertRaises(TypeError, Everything.TestObj.instance_method)
+
+    def testVirtualMethod(self):
+        obj = Everything.TestObj('foo')
+
+        # Test call.
+        self.assertEquals(42, obj.do_matrix('matrix'))
+
+        # Test argument count.
+        self.assertRaises(TypeError, obj.do_matrix)
+        self.assertRaises(TypeError, obj.do_matrix, 'matrix', 'foo')
         self.assertRaises(TypeError, Everything.TestObj.do_matrix, 'matrix')
-        self.assertRaises(TypeError, Everything.TestObj.do_matrix, None, 'matrix')
+
+        # Test instance checking by passing a wrong instance.
+        obj = gobject.GObject()
+        self.assertRaises(TypeError, Everything.TestObj.do_matrix, obj, 'matrix')
 
     def testStaticMethod(self):
+        obj = Everything.TestObj('foo')
+
+        # Test calls.
         self.assertEquals(42, Everything.TestObj.static_method(42))
+        self.assertEquals(42, obj.static_method(42))
+
+        # Test argument count.
         self.assertRaises(TypeError, Everything.TestObj.static_method)
-        self.assertRaises(TypeError, Everything.TestObj.static_method, 'foo')
         self.assertRaises(TypeError, Everything.TestObj.static_method, 'foo', 'bar')
-        o = Everything.TestObj('foo')
-        self.assertEquals(42, o.static_method(42))
+
+
+# Inheritance
 
     def testSubObj(self):
+        # Test subclassing.
         self.assertTrue(issubclass(Everything.TestSubObj, Everything.TestObj))
+
+        # Test static method.
         self.assertEquals(42, Everything.TestSubObj.static_method(42))
 
-        self.assertRaises(TypeError, Everything.TestSubObj, 'foo')
+        # Test constructor.
+        subobj = Everything.TestSubObj()
+        self.assertTrue(isinstance(subobj, Everything.TestSubObj))
+        self.assertTrue(isinstance(subobj, Everything.TestObj))
+
+        # Test alternate constructor.
+        subobj = Everything.TestSubObj.new_from_file('foo')
+        self.assertTrue(isinstance(subobj, Everything.TestSubObj))
+
+        # Test method inheritance.
+        self.assertTrue(hasattr(subobj, 'set_bare'))
+        self.assertEquals(42, subobj.do_matrix('foo'))
+
+        # Test method overriding.
+        self.assertEquals(0, subobj.instance_method())
+
+        # Test instance checking by passing a wrong instance.
+        obj = Everything.TestObj('foo')
+        self.assertRaises(TypeError, Everything.TestSubObj.instance_method, obj)
 
-        s = Everything.TestSubObj()
-        self.assertTrue(isinstance(s, Everything.TestSubObj))
-        self.assertTrue(isinstance(s, Everything.TestObj))
+    def testPythonSubObj(self):
+        class PythonSubObj(Everything.TestObj):
+            def __new__(cls):
+                return super(PythonSubObj, cls).__new__(cls, 'foo')
+        gobject.type_register(PythonSubObj)
 
-        self.assertTrue(hasattr(s, 'set_bare'))
+        # Test subclassing.
+        self.assertTrue(issubclass(PythonSubObj, Everything.TestObj))
+        self.assertTrue(PythonSubObj.__gtype__ != Everything.TestObj.__gtype__)
+        self.assertTrue(PythonSubObj.__gtype__.is_a(Everything.TestObj.__gtype__))
 
-        self.assertEquals(42, s.do_matrix('foo'))
+        # Test static method.
+        self.assertEquals(42, PythonSubObj.static_method(42))
 
-        self.assertTrue(hasattr(s, 'unset_bare'))
+        # Test instanciation.
+        subobj = PythonSubObj()
+        self.assertTrue(isinstance(subobj, PythonSubObj))
 
-        self.assertEquals(0, s.instance_method())
-        self.assertRaises(TypeError, Everything.TestObj.instance_method, Everything.TestObj('foo'))
+        subobj = PythonSubObj.new_from_file('foo')
+        self.assertTrue(isinstance(subobj, PythonSubObj))
+
+        # Test method inheritance.
+        self.assertTrue(hasattr(subobj, 'set_bare'))
+        self.assertEquals(42, subobj.do_matrix('foo'))
+
+
+# Interface
+
+    def testInterface(self):
+        self.assertTrue(issubclass(Everything.TestInterface, gobject.GInterface))
+        self.assertEquals(Everything.TestInterface.__gtype__.name, 'EverythingTestInterface')
+
+        # Test instanciation.
+        self.assertRaises(NotImplementedError, Everything.TestInterface)
 
 
 if __name__ == '__main__':



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