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('.') |