diff options
author | Christoph Reiter <creiter@src.gnome.org> | 2015-09-06 05:35:03 +0200 |
---|---|---|
committer | Garrett Regier <garrett.regier@riftio.com> | 2015-09-22 13:33:57 -0700 |
commit | ea75a89a7d2bdabc7a29f7f20f792211765f2ac7 (patch) | |
tree | 23c3fc162f1d7758bc42ea96edc81dc9a11ba35c | |
parent | 65726314de2833ce0364a3f3e23f344d122b342f (diff) | |
download | pygobject-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.py | 93 | ||||
-rw-r--r-- | gi/pygi-repository.c | 19 | ||||
-rw-r--r-- | tests/test_import_machinery.py | 9 | ||||
-rw-r--r-- | tests/test_repository.py | 11 |
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() |