[pygobject] Import dependencies when importing typelibs from gi.repository



commit dba1da9b0770c7dec1abd82303b9b4266fe2ce3f
Author: Christoph Reiter <creiter src gnome org>
Date:   Sun Oct 4 10:13:35 2015 +0200

    Import dependencies when importing typelibs from gi.repository
    
    Recursively import a modules dependencies when importing from
    gi.repository.
    
    This fixes the case where a library depends on initialization
    code of dependency overrides. For example libwnck expects
    gdk_init to be called before using its API and gdk_init
    gets called in the Gdk overrrides.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=656314

 gi/importer.py                 |   12 +++++++++++-
 gi/pygi-repository.c           |   35 +++++++++++++++++++++++++++++++++++
 tests/test_import_machinery.py |   13 +++++++++++++
 tests/test_repository.py       |   10 ++++++++++
 4 files changed, 69 insertions(+), 1 deletions(-)
---
diff --git a/gi/importer.py b/gi/importer.py
index 22c272b..2c4fb9c 100644
--- a/gi/importer.py
+++ b/gi/importer.py
@@ -24,6 +24,7 @@
 from __future__ import absolute_import
 import sys
 import warnings
+import importlib
 from contextlib import contextmanager
 
 import gi
@@ -93,7 +94,11 @@ class DynamicImporter(object):
         if path != self.path:
             return
 
-        if repository.enumerate_versions(namespace):
+        # is_registered() is faster than enumerate_versions() and
+        # in the common case of a namespace getting loaded before its
+        # dependencies, is_registered() returns True for all dependencies.
+        if repository.is_registered(namespace) or \
+                repository.enumerate_versions(namespace):
             return self
         else:
             raise ImportError('cannot import name %s, '
@@ -112,6 +117,11 @@ class DynamicImporter(object):
             stacklevel = 4
         with _check_require_version(namespace, stacklevel=stacklevel):
             introspection_module = get_introspection_module(namespace)
+            # Import all dependencies first so their init functions
+            # (gdk_init, ..) in overrides get called.
+            # https://bugzilla.gnome.org/show_bug.cgi?id=656314
+            for dep in repository.get_immediate_dependencies(namespace):
+                importlib.import_module('gi.repository.' + dep.split("-")[0])
             dynamic_module = load_overrides(introspection_module)
 
         dynamic_module.__file__ = '<%s>' % fullname
diff --git a/gi/pygi-repository.c b/gi/pygi-repository.c
index b8a1931..16356f9 100644
--- a/gi/pygi-repository.c
+++ b/gi/pygi-repository.c
@@ -319,6 +319,40 @@ _wrap_g_irepository_get_dependencies (PyGIRepository *self,
     return py_namespaces;
 }
 
+
+static PyObject *
+_wrap_g_irepository_get_immediate_dependencies (PyGIRepository *self,
+                                                PyObject       *args,
+                                                PyObject       *kwargs)
+{
+    static char *kwlist[] = { "namespace", NULL };
+    const char *namespace_;
+    char **namespaces;
+    PyObject *py_namespaces;
+    gssize i;
+
+    if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+                                      "s:Repository.get_immediate_dependencies",
+                                      kwlist, &namespace_)) {
+        return NULL;
+    }
+
+    py_namespaces = PyList_New (0);
+    namespaces = g_irepository_get_immediate_dependencies (self->repository,
+                                                           namespace_);
+
+    for (i = 0; namespaces[i] != NULL; i++) {
+        PyObject *py_namespace = PYGLIB_PyUnicode_FromString (namespaces[i]);
+        PyList_Append (py_namespaces, py_namespace);
+        Py_DECREF (py_namespace);
+    }
+
+    g_strfreev (namespaces);
+
+    return py_namespaces;
+}
+
+
 static PyMethodDef _PyGIRepository_methods[] = {
     { "enumerate_versions", (PyCFunction) _wrap_g_irepository_enumerate_versions, METH_VARARGS | 
METH_KEYWORDS },
     { "get_default", (PyCFunction) _wrap_g_irepository_get_default, METH_STATIC | METH_NOARGS },
@@ -329,6 +363,7 @@ static PyMethodDef _PyGIRepository_methods[] = {
     { "get_version", (PyCFunction) _wrap_g_irepository_get_version, METH_VARARGS | METH_KEYWORDS },
     { "get_loaded_namespaces", (PyCFunction) _wrap_g_irepository_get_loaded_namespaces, METH_NOARGS },
     { "get_dependencies", (PyCFunction) _wrap_g_irepository_get_dependencies, METH_VARARGS | METH_KEYWORDS  
},
+    { "get_immediate_dependencies", (PyCFunction) _wrap_g_irepository_get_immediate_dependencies, 
METH_VARARGS | METH_KEYWORDS  },
     { "is_registered", (PyCFunction) _wrap_g_irepository_is_registered, METH_VARARGS | METH_KEYWORDS  },
     { NULL, NULL, 0 }
 };
diff --git a/tests/test_import_machinery.py b/tests/test_import_machinery.py
index de9f1e9..e1432b1 100644
--- a/tests/test_import_machinery.py
+++ b/tests/test_import_machinery.py
@@ -77,6 +77,19 @@ class TestModule(unittest.TestCase):
         # Restore the previous cache
         gi.module._introspection_modules = old_modules
 
+    def test_module_dependency_loading(self):
+        # Difficult to because this generally need to run in isolation to make
+        # sure GIMarshallingTests has not yet been loaded. But we can do this with:
+        #  make check TEST_NAMES=test_import_machinery.TestModule.test_module_dependency_loading
+        if 'gi.repository.Gio' in sys.modules:
+            return
+
+        from gi.repository import GIMarshallingTests
+        GIMarshallingTests  # PyFlakes
+
+        self.assertIn('gi.repository.Gio', sys.modules)
+        self.assertIn('gi.repository.GIMarshallingTests', sys.modules)
+
     def test_static_binding_protection(self):
         # Importing old static bindings once gi has been imported should not
         # crash but instead give back a dummy module which produces RuntimeErrors
diff --git a/tests/test_repository.py b/tests/test_repository.py
index 4c83acd..f59f86b 100644
--- a/tests/test_repository.py
+++ b/tests/test_repository.py
@@ -74,6 +74,16 @@ class Test(unittest.TestCase):
         self.assertFalse(repo.is_registered("GIRepository", "99.0"))
         self.assertFalse(repo.is_registered("GIRepository", "1.0"))
 
+    def test_repo_get_immediate_dependencies(self):
+        self.assertRaises(TypeError, repo.get_immediate_dependencies)
+        self.assertEqual(repo.get_immediate_dependencies("GLib"), [])
+        self.assertEqual(
+            repo.get_immediate_dependencies("GObject"), ["GLib-2.0"])
+        self.assertEqual(
+            repo.get_immediate_dependencies(namespace="GObject"), ["GLib-2.0"])
+        self.assertEqual(
+            repo.get_immediate_dependencies("GIMarshallingTests"), ["Gio-2.0"])
+
     def test_arg_info(self):
         func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
         args = func_info.get_arguments()


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