cubicweb/cwvreg.py
changeset 11900 8496135b6dc1
parent 11767 432f87a63057
child 12497 c81e29cd8cff
child 12540 623e9dd2977f
equal deleted inserted replaced
11899:bf6106b91633 11900:8496135b6dc1
    27 
    27 
    28 from six import text_type, binary_type
    28 from six import text_type, binary_type
    29 
    29 
    30 from logilab.common.decorators import cached, clear_cache
    30 from logilab.common.decorators import cached, clear_cache
    31 from logilab.common.deprecation import class_deprecated
    31 from logilab.common.deprecation import class_deprecated
    32 from logilab.common.modutils import cleanup_sys_modules
    32 from logilab.common.modutils import clean_sys_modules
    33 from logilab.common.registry import RegistryStore, Registry, ObjectNotFound, RegistryNotFound
    33 from logilab.common.registry import RegistryStore, Registry, ObjectNotFound, RegistryNotFound
    34 
    34 
    35 from rql import RQLHelper
    35 from rql import RQLHelper
    36 from yams.constraints import BASE_CONVERTERS
    36 from yams.constraints import BASE_CONVERTERS
    37 
    37 
   415 
   415 
   416     def set_schema(self, schema):
   416     def set_schema(self, schema):
   417         """set instance'schema and load application objects"""
   417         """set instance'schema and load application objects"""
   418         self._set_schema(schema)
   418         self._set_schema(schema)
   419         # now we can load application's web objects
   419         # now we can load application's web objects
   420         self.reload(self.config.appobjects_path(), force_reload=False)
   420         self.reload(self.config.appobjects_modnames(), force_reload=False)
   421         # map lowered entity type names to their actual name
   421         # map lowered entity type names to their actual name
   422         self.case_insensitive_etypes = {}
   422         self.case_insensitive_etypes = {}
   423         for eschema in self.schema.entities():
   423         for eschema in self.schema.entities():
   424             etype = str(eschema)
   424             etype = str(eschema)
   425             self.case_insensitive_etypes[etype.lower()] = etype
   425             self.case_insensitive_etypes[etype.lower()] = etype
   426             clear_cache(eschema, 'ordered_relations')
   426             clear_cache(eschema, 'ordered_relations')
   427             clear_cache(eschema, 'meta_attributes')
   427             clear_cache(eschema, 'meta_attributes')
   428 
   428 
       
   429     def is_reload_needed(self, modnames):
       
   430         """overriden to handle modules names instead of directories"""
       
   431         lastmodifs = self._lastmodifs
       
   432         for modname in modnames:
       
   433             if modname not in sys.modules:
       
   434                 # new module to load
       
   435                 return True
       
   436             filepath = sys.modules[modname].__file__
       
   437             if filepath.endswith('.py'):
       
   438                 mdate = self._mdate(filepath)
       
   439                 if filepath not in lastmodifs or lastmodifs[filepath] < mdate:
       
   440                     self.info('File %s changed since last visit', filepath)
       
   441                     return True
       
   442         return False
       
   443 
   429     def reload_if_needed(self):
   444     def reload_if_needed(self):
   430         path = self.config.appobjects_path()
   445         modnames = self.config.appobjects_modnames()
   431         if self.is_reload_needed(path):
   446         if self.is_reload_needed(modnames):
   432             self.reload(path)
   447             self.reload(modnames)
   433 
   448 
   434     def _cleanup_sys_modules(self, path):
   449     def _cleanup_sys_modules(self, modnames):
   435         """Remove submodules of `directories` from `sys.modules` and cleanup
   450         """Remove modules and submodules of `modnames` from `sys.modules` and cleanup
   436         CW_EVENT_MANAGER accordingly.
   451         CW_EVENT_MANAGER accordingly.
   437 
   452 
   438         We take care to properly remove obsolete registry callbacks.
   453         We take care to properly remove obsolete registry callbacks.
   439 
   454 
   440         """
   455         """
   444             for callback in callbacklist:
   459             for callback in callbacklist:
   445                 func = callback[0]
   460                 func = callback[0]
   446                 # for non-function callable, we do nothing interesting
   461                 # for non-function callable, we do nothing interesting
   447                 module = getattr(func, '__module__', None)
   462                 module = getattr(func, '__module__', None)
   448                 caches[id(callback)] = module
   463                 caches[id(callback)] = module
   449         deleted_modules = set(cleanup_sys_modules(path))
   464         deleted_modules = set(clean_sys_modules(modnames))
   450         for callbacklist in callbackdata:
   465         for callbacklist in callbackdata:
   451             for callback in callbacklist[:]:
   466             for callback in callbacklist[:]:
   452                 module = caches[id(callback)]
   467                 module = caches[id(callback)]
   453                 if module and module in deleted_modules:
   468                 if module and module in deleted_modules:
   454                     callbacklist.remove(callback)
   469                     callbacklist.remove(callback)
   455 
   470 
   456     def reload(self, path, force_reload=True):
   471     def reload(self, modnames, force_reload=True):
   457         """modification detected, reset and reload the vreg"""
   472         """modification detected, reset and reload the vreg"""
   458         CW_EVENT_MANAGER.emit('before-registry-reload')
   473         CW_EVENT_MANAGER.emit('before-registry-reload')
   459         if force_reload:
   474         if force_reload:
   460             self._cleanup_sys_modules(path)
   475             self._cleanup_sys_modules(modnames)
   461             cubes = self.config.cubes()
   476             cubes = self.config.cubes()
   462             # if the fs code use some cubes not yet registered into the instance
   477             # if the fs code use some cubes not yet registered into the instance
   463             # we should cleanup sys.modules for those as well to avoid potential
   478             # we should cleanup sys.modules for those as well to avoid potential
   464             # bad class reference pb after reloading
   479             # bad class reference pb after reloading
   465             cfg = self.config
   480             cfg = self.config
   466             for cube in cfg.expand_cubes(cubes, with_recommends=True):
   481             for cube in cfg.expand_cubes(cubes, with_recommends=True):
   467                 if not cube in cubes:
   482                 if not cube in cubes:
   468                     cpath = cfg.build_appobjects_cube_path([cfg.cube_dir(cube)])
   483                     cube_modnames = cfg.appobjects_cube_modnames(cube)
   469                     self._cleanup_sys_modules(cpath)
   484                     self._cleanup_sys_modules(cube_modnames)
   470         self.register_objects(path)
   485         self.register_modnames(modnames)
   471         CW_EVENT_MANAGER.emit('after-registry-reload')
   486         CW_EVENT_MANAGER.emit('after-registry-reload')
   472 
   487 
   473     def load_file(self, filepath, modname):
   488     def load_file(self, filepath, modname):
   474         # override to allow some instrumentation (eg localperms)
   489         # override to allow some instrumentation (eg localperms)
   475         modpath = modname.split('.')
   490         modpath = modname.split('.')