summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Reiter <creiter@src.gnome.org>2015-09-06 05:35:03 +0200
committerGarrett Regier <garrett.regier@riftio.com>2015-09-22 13:33:57 -0700
commitea75a89a7d2bdabc7a29f7f20f792211765f2ac7 (patch)
tree23c3fc162f1d7758bc42ea96edc81dc9a11ba35c
parent65726314de2833ce0364a3f3e23f344d122b342f (diff)
downloadpygobject-ea75a89a7d2bdabc7a29f7f20f792211765f2ac7.tar.gz
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
-rw-r--r--gi/importer.py93
-rw-r--r--gi/pygi-repository.c19
-rw-r--r--tests/test_import_machinery.py9
-rw-r--r--tests/test_repository.py11
4 files changed, 54 insertions, 78 deletions
diff --git a/gi/importer.py b/gi/importer.py
index 0acbc23e..22c272b5 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 a1f1ca66..b8a19316 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 a1adab16..de9f1e94 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 8710ce7d..4c83acdf 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()