[cwvreg] cleanup the event manager when reloading modules
Closes #3848995
The event manager callbacks are not cleaned during reloading.
So the callback defined in the reloaded module appears twice (old and new
version). This may cause problem when the old version is called.
--- a/__pkginfo__.py Tue Jul 08 14:02:43 2014 +0200
+++ b/__pkginfo__.py Wed May 21 16:14:17 2014 +0200
@@ -40,7 +40,7 @@
]
__depends__ = {
- 'logilab-common': '>= 0.59.0',
+ 'logilab-common': '>= 0.62.0',
'logilab-mtconverter': '>= 0.8.0',
'rql': '>= 0.31.2',
'yams': '>= 0.38.1',
--- a/cubicweb.spec Tue Jul 08 14:02:43 2014 +0200
+++ b/cubicweb.spec Wed May 21 16:14:17 2014 +0200
@@ -20,7 +20,7 @@
BuildArch: noarch
Requires: %{python}
-Requires: %{python}-logilab-common >= 0.59.0
+Requires: %{python}-logilab-common >= 0.62.0
Requires: %{python}-logilab-mtconverter >= 0.8.0
Requires: %{python}-rql >= 0.31.2
Requires: %{python}-yams >= 0.38.1
--- a/cwvreg.py Tue Jul 08 14:02:43 2014 +0200
+++ b/cwvreg.py Wed May 21 16:14:17 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -609,11 +609,33 @@
if self.is_reload_needed(path):
self.reload(path)
+ def _cleanup_sys_modules(self, path):
+ """Remove submodules of `directories` from `sys.modules` and cleanup
+ CW_EVENT_MANAGER accordingly.
+
+ We take care to properly remove obsolete registry callbacks.
+
+ """
+ caches = {}
+ callbackdata = CW_EVENT_MANAGER.callbacks.values()
+ for callbacklist in callbackdata:
+ for callback in callbacklist:
+ func = callback[0]
+ # for non-function callable, we do nothing interesting
+ module = getattr(func, '__module__', None)
+ caches[id(callback)] = module
+ deleted_modules = set(cleanup_sys_modules(path))
+ for callbacklist in callbackdata:
+ for callback in callbacklist[:]:
+ module = caches[id(callback)]
+ if module and module in deleted_modules:
+ callbacklist.remove(callback)
+
def reload(self, path, force_reload=True):
"""modification detected, reset and reload the vreg"""
CW_EVENT_MANAGER.emit('before-registry-reload')
if force_reload:
- cleanup_sys_modules(path)
+ self._cleanup_sys_modules(path)
cubes = self.config.cubes()
# if the fs code use some cubes not yet registered into the instance
# we should cleanup sys.modules for those as well to avoid potential
@@ -622,7 +644,7 @@
for cube in cfg.expand_cubes(cubes, with_recommends=True):
if not cube in cubes:
cpath = cfg.build_appobjects_cube_path([cfg.cube_dir(cube)])
- cleanup_sys_modules(cpath)
+ self._cleanup_sys_modules(cpath)
self.register_objects(path)
CW_EVENT_MANAGER.emit('after-registry-reload')
--- a/debian/control Tue Jul 08 14:02:43 2014 +0200
+++ b/debian/control Wed May 21 16:14:17 2014 +0200
@@ -150,7 +150,7 @@
graphviz,
gettext,
python-logilab-mtconverter (>= 0.8.0),
- python-logilab-common (>= 0.59.0),
+ python-logilab-common (>= 0.62.0),
python-yams (>= 0.38.1),
python-yams (<< 0.39),
python-rql (>= 0.31.2),