--- a/_exceptions.py Thu Apr 15 14:07:25 2010 +0200
+++ b/_exceptions.py Thu Apr 15 14:07:47 2010 +0200
@@ -125,8 +125,6 @@
class UnknownProperty(RegistryException):
"""property found in database but unknown in registry"""
-class RegistryOutOfDate(RegistryException):
- """raised when a source file modification is detected"""
# query exception #############################################################
--- a/cwvreg.py Thu Apr 15 14:07:25 2010 +0200
+++ b/cwvreg.py Thu Apr 15 14:07:47 2010 +0200
@@ -185,7 +185,7 @@
from cubicweb import (ETYPE_NAME_MAP, Binary, UnknownProperty, UnknownEid,
ObjectNotFound, NoSelectableObject, RegistryNotFound,
- RegistryOutOfDate, CW_EVENT_MANAGER, onevent)
+ CW_EVENT_MANAGER, onevent)
from cubicweb.utils import dump_class
from cubicweb.vregistry import VRegistry, Registry, class_regid
from cubicweb.rtags import RTAGS
@@ -456,8 +456,8 @@
def itervalues(self):
return (value for key, value in self.items())
- def reset(self, path=None, force_reload=None):
- super(CubicWebVRegistry, self).reset(path, force_reload)
+ def reset(self):
+ super(CubicWebVRegistry, self).reset()
self._needs_iface = {}
# two special registries, propertydefs which care all the property
# definitions, and propertyvals which contains values for those
@@ -467,7 +467,29 @@
self['propertyvalues'] = self.eprop_values = {}
for key, propdef in self.config.eproperty_definitions():
self.register_property(key, **propdef)
- if path is not None and force_reload:
+
+ def set_schema(self, schema):
+ """set instance'schema and load application objects"""
+ self._set_schema(schema)
+ # now we can load application's web objects
+ self.reload(self.config.vregistry_path(), force_reload=False)
+ # map lowered entity type names to their actual name
+ self.case_insensitive_etypes = {}
+ for eschema in self.schema.entities():
+ etype = str(eschema)
+ self.case_insensitive_etypes[etype.lower()] = etype
+ clear_cache(eschema, 'ordered_relations')
+ clear_cache(eschema, 'meta_attributes')
+
+ def reload_if_needed(self):
+ path = self.config.vregistry_path()
+ if self.is_reload_needed(path):
+ self.reload(path)
+
+ 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)
cubes = self.config.cubes()
# if the fs code use some cubes not yet registered into the instance
@@ -478,26 +500,8 @@
if not cube in cubes:
cpath = cfg.build_vregistry_cube_path([cfg.cube_dir(cube)])
cleanup_sys_modules(cpath)
-
- def set_schema(self, schema):
- """set instance'schema and load application objects"""
- self._set_schema(schema)
- # now we can load application's web objects
- self._reload(self.config.vregistry_path(), force_reload=False)
- # map lowered entity type names to their actual name
- self.case_insensitive_etypes = {}
- for eschema in self.schema.entities():
- etype = str(eschema)
- self.case_insensitive_etypes[etype.lower()] = etype
- clear_cache(eschema, 'ordered_relations')
- clear_cache(eschema, 'meta_attributes')
-
- def _reload(self, path, force_reload):
- CW_EVENT_MANAGER.emit('before-registry-reload')
- # modification detected, reset and reload
- self.reset(path, force_reload)
- super(CubicWebVRegistry, self).register_objects(
- path, force_reload, self.config.extrapath)
+ self.reset()
+ self.register_objects(path, force_reload)
CW_EVENT_MANAGER.emit('after-registry-reload')
def _set_schema(self, schema):
@@ -542,15 +546,10 @@
if ifaces:
self._needs_iface[obj] = ifaces
- def register_objects(self, path, force_reload=None):
+ def register_objects(self, path, force_reload=False):
"""overriden to remove objects requiring a missing interface"""
- if force_reload is None:
- force_reload = self.config.debugmode
- try:
- super(CubicWebVRegistry, self).register_objects(
- path, force_reload, self.config.extrapath)
- except RegistryOutOfDate:
- self._reload(path, force_reload)
+ super(CubicWebVRegistry, self).register_objects(
+ path, force_reload, self.config.extrapath)
def initialization_completed(self):
"""cw specific code once vreg initialization is completed:
--- a/etwist/server.py Thu Apr 15 14:07:25 2010 +0200
+++ b/etwist/server.py Thu Apr 15 14:07:47 2010 +0200
@@ -179,7 +179,7 @@
"""Render a page from the root resource"""
# reload modified files in debug mode
if self.debugmode:
- self.appli.vreg.register_objects(self.config.vregistry_path())
+ self.appli.vreg.reload_if_needed()
if self.config['profile']: # default profiler don't trace threads
return self.render_request(request)
else:
--- a/vregistry.py Thu Apr 15 14:07:25 2010 +0200
+++ b/vregistry.py Thu Apr 15 14:07:47 2010 +0200
@@ -31,8 +31,7 @@
from logilab.common.logging_ext import set_log_methods
from cubicweb import CW_SOFTWARE_ROOT
-from cubicweb import (RegistryNotFound, ObjectNotFound, NoSelectableObject,
- RegistryOutOfDate)
+from cubicweb import RegistryNotFound, ObjectNotFound, NoSelectableObject
from cubicweb.appobject import AppObject
def _toload_info(path, extrapath, _toload=None):
@@ -246,8 +245,18 @@
def __init__(self, config):
super(VRegistry, self).__init__()
self.config = config
+ # need to clean sys.path this to avoid import confusion pb (i.e. having
+ # the same module loaded as 'cubicweb.web.views' subpackage and as
+ # views' or 'web.views' subpackage. This is mainly for testing purpose,
+ # we should'nt need this in production environment
+ for webdir in (join(dirname(realpath(__file__)), 'web'),
+ join(dirname(__file__), 'web')):
+ if webdir in sys.path:
+ sys.path.remove(webdir)
+ if CW_SOFTWARE_ROOT in sys.path:
+ sys.path.remove(CW_SOFTWARE_ROOT)
- def reset(self, path=None, force_reload=None):
+ def reset(self):
# don't use self.clear, we want to keep existing subdictionaries
for subdict in self.itervalues():
subdict.clear()
@@ -392,60 +401,61 @@
self._loadedmods = {}
return filemods
- def register_objects(self, path, force_reload, extrapath=None):
- # need to clean sys.path this to avoid import confusion pb (i.e.
- # having the same module loaded as 'cubicweb.web.views' subpackage and
- # as views' or 'web.views' subpackage
- # this is mainly for testing purpose, we should'nt need this in
- # production environment
- for webdir in (join(dirname(realpath(__file__)), 'web'),
- join(dirname(__file__), 'web')):
- if webdir in sys.path:
- sys.path.remove(webdir)
- if CW_SOFTWARE_ROOT in sys.path:
- sys.path.remove(CW_SOFTWARE_ROOT)
+ def register_objects(self, path, force_reload=False, extrapath=None):
# load views from each directory in the instance's path
filemods = self.init_registration(path, extrapath)
- change = False
for filepath, modname in filemods:
- if self.load_file(filepath, modname, force_reload):
- change = True
- if change:
- self.initialization_completed()
- return change
+ self.load_file(filepath, modname, force_reload)
+ self.initialization_completed()
def initialization_completed(self):
for regname, reg in self.iteritems():
reg.initialization_completed()
+ def _mdate(self, filepath):
+ try:
+ return stat(filepath)[-2]
+ except OSError:
+ # this typically happens on emacs backup files (.#foo.py)
+ self.warning('Unable to load %s. It is likely to be a backup file',
+ filepath)
+ return None
+
+ def is_reload_needed(self, path):
+ """return True if something module changed and the registry should be
+ reloaded
+ """
+ lastmodifs = self._lastmodifs
+ for fileordir in path:
+ if isdir(fileordir) and exists(join(fileordir, '__init__.py')):
+ if self.is_reload_needed([join(fileordir, fname)
+ for fname in listdir(fileordir)]):
+ return True
+ elif fileordir[-3:] == '.py':
+ mdate = self._mdate(fileordir)
+ if mdate is None:
+ continue # backup file, see _mdate implementation
+ if fileordir not in lastmodifs or lastmodifs[fileordir] < mdate:
+ self.info('File %s changed since last visit', fileordir)
+ return True
+ return False
+
def load_file(self, filepath, modname, force_reload=False):
"""load app objects from a python file"""
from logilab.common.modutils import load_module_from_name
if modname in self._loadedmods:
return
self._loadedmods[modname] = {}
- try:
- modified_on = stat(filepath)[-2]
- except OSError:
- # this typically happens on emacs backup files (.#foo.py)
- self.warning('Unable to load %s. It is likely to be a backup file',
- filepath)
- return False
- if filepath in self._lastmodifs:
- # only load file if it was modified
- if modified_on <= self._lastmodifs[filepath]:
- return
- # if it was modified, raise RegistryOutOfDate to reload everything
- self.info('File %s changed since last visit', filepath)
- raise RegistryOutOfDate()
+ mdate = self._mdate(filepath)
+ if mdate is None:
+ return # backup file, see _mdate implementation
# set update time before module loading, else we get some reloading
# weirdness in case of syntax error or other error while importing the
# module
- self._lastmodifs[filepath] = modified_on
+ self._lastmodifs[filepath] = mdate
# load the module
module = load_module_from_name(modname, use_sys=not force_reload)
self.load_module(module)
- return True
def load_module(self, module):
self.info('loading %s', module)