[pygobject/pygobject-3-18] Don't emit require_version warning if namespace was loaded previously using g_irepository_require



commit 5da4041629f833f66b76dc7dfcf5400153d22eb4
Author: Christoph Reiter <creiter src gnome org>
Date:   Sun Sep 6 05:35:03 2015 +0200

    Don't emit require_version warning if namespace was loaded previously using g_irepository_require
    
    Instead of tracking loaded dependencies ourself to hide warnings if they
    were loaded by a previous import just look if the namespace was loaded
    before the import. This (a) makes the implementation much simpler and
    (b) also takes into account namespaces loaded outside of Python/PyGObject
    using the libgirepository C API (as is common in applications using
    libpeas with Python plugins)
    
    This also introduces a new Python wrapper for g_irepository_is_registered()
    to allow checking the loading state of namespaces before imports.
    
    This fixes unnecessary require_version warnings in gedit, gnome-builder,
    totem, rhythmbox etc.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754491

 gi/importer.py                 |   93 ++++++++++-----------------------------
 gi/pygi-repository.c           |   19 ++++++++
 tests/test_import_machinery.py |    9 ----
 tests/test_repository.py       |   11 +++++
 4 files changed, 54 insertions(+), 78 deletions(-)
---
diff --git a/gi/importer.py b/gi/importer.py
index 0acbc23..22c272b 100644
--- a/gi/importer.py
+++ b/gi/importer.py
@@ -39,34 +39,6 @@ repository = Repository.get_default()
 modules = {}
 
 
-def _get_all_dependencies(namespace):
-    """Like get_dependencies() but will recurse and get all dependencies.
-    The namespace has to be loaded before this can be called.
-
-    ::
-
-        _get_all_dependencies('Gtk') -> ['Atk-1.0', 'GObject-2.0', ...]
-    """
-
-    todo = repository.get_dependencies(namespace)
-    dependencies = []
-
-    while todo:
-        current = todo.pop()
-        if current in dependencies:
-            continue
-        ns, version = current.split("-", 1)
-        todo.extend(repository.get_dependencies(ns))
-        dependencies.append(current)
-
-    return dependencies
-
-
-# See _check_require_version()
-_active_imports = []
-_implicit_required = {}
-
-
 @contextmanager
 def _check_require_version(namespace, stacklevel):
     """A context manager which tries to give helpful warnings
@@ -80,47 +52,30 @@ def _check_require_version(namespace, stacklevel):
             load_namespace_and_overrides()
     """
 
-    global _active_imports, _implicit_required
-
-    # This keeps track of the recursion level so we only check for
-    # explicitly imported namespaces and not the ones imported in overrides
-    _active_imports.append(namespace)
-
-    try:
-        yield
-    except:
-        raise
-    else:
-        # Keep track of all dependency versions forced due to this import, so
-        # we don't warn for them in the future. This mirrors the import
-        # behavior where importing will get an older version if a previous
-        # import depended on it.
-        for dependency in _get_all_dependencies(namespace):
-            ns, version = dependency.split("-", 1)
-            _implicit_required[ns] = version
-    finally:
-        _active_imports.remove(namespace)
-
-    # Warn in case:
-    #  * this namespace was explicitly imported
-    #  * the version wasn't forced using require_version()
-    #  * the version wasn't forced implicitly by a previous import
-    #  * this namespace isn't part of glib (we have bigger problems if
-    #    versions change there)
-    is_explicit_import = not _active_imports
-    version_required = gi.get_required_version(namespace) is not None
-    version_implicit = namespace in _implicit_required
-    is_in_glib = namespace in ("GLib", "GObject", "Gio")
-
-    if is_explicit_import and not version_required and \
-            not version_implicit and not is_in_glib:
-        version = repository.get_version(namespace)
-        warnings.warn(
-            "%(namespace)s was imported without specifying a version first. "
-            "Use gi.require_version('%(namespace)s', '%(version)s') before "
-            "import to ensure that the right version gets loaded."
-            % {"namespace": namespace, "version": version},
-            PyGIWarning, stacklevel=stacklevel)
+    was_loaded = repository.is_registered(namespace)
+
+    yield
+
+    if was_loaded:
+        # it was loaded before by another import which depended on this
+        # namespace or by C code like libpeas
+        return
+
+    if namespace in ("GLib", "GObject", "Gio"):
+        # part of glib (we have bigger problems if versions change there)
+        return
+
+    if gi.get_required_version(namespace) is not None:
+        # the version was forced using require_version()
+        return
+
+    version = repository.get_version(namespace)
+    warnings.warn(
+        "%(namespace)s was imported without specifying a version first. "
+        "Use gi.require_version('%(namespace)s', '%(version)s') before "
+        "import to ensure that the right version gets loaded."
+        % {"namespace": namespace, "version": version},
+        PyGIWarning, stacklevel=stacklevel)
 
 
 class DynamicImporter(object):
diff --git a/gi/pygi-repository.c b/gi/pygi-repository.c
index a1f1ca6..b8a1931 100644
--- a/gi/pygi-repository.c
+++ b/gi/pygi-repository.c
@@ -108,6 +108,24 @@ _wrap_g_irepository_require (PyGIRepository *self,
 }
 
 static PyObject *
+_wrap_g_irepository_is_registered (PyGIRepository *self,
+                                   PyObject       *args,
+                                   PyObject       *kwargs)
+{
+    static char *kwlist[] = { "namespace", "version", NULL };
+    const char *namespace_;
+    const char *version = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s|z:Repository.is_registered",
+                                      kwlist, &namespace_, &version)) {
+        return NULL;
+    }
+
+    return PyBool_FromLong (g_irepository_is_registered (self->repository,
+                                                         namespace_, version));
+}
+
+static PyObject *
 _wrap_g_irepository_find_by_name (PyGIRepository *self,
                                   PyObject       *args,
                                   PyObject       *kwargs)
@@ -311,6 +329,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  
},
+    { "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 a1adab1..de9f1e9 100644
--- a/tests/test_import_machinery.py
+++ b/tests/test_import_machinery.py
@@ -118,15 +118,6 @@ class TestImporter(unittest.TestCase):
         else:
             self.assertTrue('introspection typelib' in exception_string)
 
-    def test__get_all_dependencies(self):
-        get_all_dependencies = gi.importer._get_all_dependencies
-        deps = set(get_all_dependencies("Regress"))
-
-        self.assertTrue('Gio-2.0' in deps)
-        self.assertTrue('GObject-2.0' in deps)
-        self.assertTrue('GLib-2.0' in deps)
-        self.assertTrue('cairo-1.0' in deps)
-
     def test_require_version_warning(self):
         check = gi.importer._check_require_version
 
diff --git a/tests/test_repository.py b/tests/test_repository.py
index 8710ce7..4c83acd 100644
--- a/tests/test_repository.py
+++ b/tests/test_repository.py
@@ -63,6 +63,17 @@ class Test(unittest.TestCase):
         self.assertEqual(repo.get_dependencies("GLib"), [])
         self.assertEqual(repo.get_dependencies("GObject"), ["GLib-2.0"])
 
+    def test_repo_is_registered(self):
+        self.assertRaises(TypeError, repo.is_registered)
+        self.assertRaises(TypeError, repo.is_registered, None)
+        self.assertTrue(repo.is_registered("GIRepository"))
+        self.assertTrue(repo.is_registered("GIRepository", None))
+        self.assertTrue(isinstance(repo.is_registered("GIRepository"), bool))
+        self.assertTrue(repo.is_registered("GIRepository", "2.0"))
+        self.assertFalse(repo.is_registered("GIRepository", ""))
+        self.assertFalse(repo.is_registered("GIRepository", "99.0"))
+        self.assertFalse(repo.is_registered("GIRepository", "1.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]