[uiprops] test and fix reloading of modified css files; update c-c newcube; deprecates config.has_resource.
--- a/devtools/__init__.py Mon May 03 14:17:45 2010 +0200
+++ b/devtools/__init__.py Wed May 05 10:22:11 2010 +0200
@@ -181,10 +181,6 @@
def available_languages(self, *args):
return ('en', 'fr', 'de')
- def ext_resources_file(self):
- """return instance's external resources file"""
- return join(self.apphome, 'data', 'external_resources')
-
def pyro_enabled(self):
# but export PYRO_MULTITHREAD=0 or you get problems with sqlite and threads
return True
--- a/devtools/devctl.py Mon May 03 14:17:45 2010 +0200
+++ b/devtools/devctl.py Wed May 05 10:22:11 2010 +0200
@@ -595,7 +595,7 @@
exclude = SKEL_EXCLUDE
if self['layout'] == 'simple':
exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*',
- 'cubes.*', 'external_resources*')
+ 'cubes.*', 'uiprops.py*')
copy_skeleton(skeldir, cubedir, context, exclude=exclude)
def _ask_for_dependencies(self):
--- a/skeleton/data/external_resources.tmpl Mon May 03 14:17:45 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-# -*- shell-script -*-
-###############################################################################
-#
-# put here information about external resources used by your components,
-# or to overides existing external resources configuration
-#
-###############################################################################
-
-# CSS stylesheets to include in HTML headers
-# uncomment the line below to use template specific stylesheet
-# STYLESHEETS = DATADIR/cubes.%(cubename)s.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/skeleton/uiprops.py.tmpl Wed May 05 10:22:11 2010 +0200
@@ -0,0 +1,15 @@
+###############################################################################
+#
+# Put here information about external resources / styles used by your cube,
+# or to overides existing UI properties.
+#
+# Existing properties are available through the `sheet` dictionary available
+# in the global namespace. You also have access to a `data` function which
+# will return proper url for resources in the 'data' directory.
+#
+# /!\ this file should not be imported /!\
+###############################################################################
+
+# CSS stylesheets to include in HTML headers
+# uncomment the line below to use template specific stylesheet
+# STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.%(cubename)s.css')]
--- a/test/unittest_vregistry.py Mon May 03 14:17:45 2010 +0200
+++ b/test/unittest_vregistry.py Wed May 05 10:22:11 2010 +0200
@@ -56,21 +56,25 @@
def test_load_subinterface_based_appobjects(self):
- self.vreg.reset()
self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
# check progressbar was kicked
self.failIf(self.vreg['views'].get('progressbar'))
+ # we've to emulate register_objects to add custom MyCard objects
+ path = [join(BASE, 'entities', '__init__.py'),
+ join(BASE, 'web', 'views', 'iprogress.py')]
+ filemods = self.vreg.init_registration(path, None)
+ for filepath, modname in filemods:
+ self.vreg.load_file(filepath, modname)
class MyCard(Card):
__implements__ = (IMileStone,)
- self.vreg.reset()
self.vreg._loadedmods[__name__] = {}
self.vreg.register(MyCard)
- self.vreg.register_objects([join(BASE, 'entities', '__init__.py'),
- join(BASE, 'web', 'views', 'iprogress.py')])
+ self.vreg.initialization_completed()
# check progressbar isn't kicked
self.assertEquals(len(self.vreg['views']['progressbar']), 1)
def test_properties(self):
+ self.vreg.reset()
self.failIf('system.version.cubicweb' in self.vreg['propertydefs'])
self.failUnless(self.vreg.property_info('system.version.cubicweb'))
self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key')
--- a/web/propertysheet.py Mon May 03 14:17:45 2010 +0200
+++ b/web/propertysheet.py Wed May 05 10:22:11 2010 +0200
@@ -47,12 +47,12 @@
self._ordered_propfiles.append(fpath)
def need_reload(self):
+ for rid, (adirectory, rdirectory, mtime) in self._cache.items():
+ if os.stat(osp.join(rdirectory, rid))[-2] > mtime:
+ del self._cache[rid]
for fpath, mtime in self._propfile_mtime.iteritems():
if os.stat(fpath)[-2] > mtime:
return True
- for rid, (directory, mtime) in self._cache.items():
- if os.stat(osp.join(directory, rid))[-2] > mtime:
- del self._cache[rid]
return False
def reload(self):
@@ -70,7 +70,7 @@
return self._cache[rid][0]
except KeyError:
cachefile = osp.join(self._cache_directory, rid)
- self.debug('caching processed css %s/%s into %s',
+ self.debug('caching processed %s/%s into %s',
rdirectory, rid, cachefile)
rcachedir = osp.dirname(cachefile)
if not osp.exists(rcachedir):
@@ -83,13 +83,14 @@
content = self.compile(content)
except ValueError, ex:
self.error("can't process %s/%s: %s", rdirectory, rid, ex)
+ adirectory = rdirectory
else:
stream = file(cachefile, 'w')
stream.write(content)
stream.close()
- rdirectory = self._cache_directory
- self._cache[rid] = (rdirectory, os.stat(sourcefile)[-2])
- return rdirectory
+ adirectory = self._cache_directory
+ self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile)[-2])
+ return adirectory
def compile(self, content):
return self._percent_rgx.sub('%%', content) % self
--- a/web/test/unittest_propertysheet.py Mon May 03 14:17:45 2010 +0200
+++ b/web/test/unittest_propertysheet.py Wed May 05 10:22:11 2010 +0200
@@ -1,12 +1,21 @@
+import os
from os.path import join, dirname
+from shutil import rmtree
+
from logilab.common.testlib import TestCase, unittest_main
+
from cubicweb.web.propertysheet import *
DATADIR = join(dirname(__file__), 'data')
+CACHEDIR = join(DATADIR, 'uicache')
+
class PropertySheetTC(TestCase):
+ def tearDown(self):
+ rmtree(CACHEDIR)
+
def test(self):
- ps = PropertySheet(None, datadir_url='http://cwtest.com')
+ ps = PropertySheet(CACHEDIR, datadir_url='http://cwtest.com')
ps.load(join(DATADIR, 'sheet1.py'))
ps.load(join(DATADIR, 'sheet2.py'))
# defined by sheet1
@@ -20,6 +29,21 @@
'http://cwtest.com/mycube.css'])
self.assertEquals(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'),
'a {bgcolor: #FFFFFF; size: 1%;}')
+ self.assertEquals(ps.process_resource(DATADIR, 'pouet.css'),
+ CACHEDIR)
+ self.failUnless('pouet.css' in ps._cache)
+ self.failIf(ps.need_reload())
+ os.utime(join(DATADIR, 'sheet1.py'), None)
+ self.failUnless('pouet.css' in ps._cache)
+ self.failUnless(ps.need_reload())
+ self.failUnless('pouet.css' in ps._cache)
+ ps.reload()
+ self.failIf('pouet.css' in ps._cache)
+ self.failIf(ps.need_reload())
+ ps.process_resource(DATADIR, 'pouet.css') # put in cache
+ os.utime(join(DATADIR, 'pouet.css'), None)
+ self.failIf(ps.need_reload())
+ self.failIf('pouet.css' in ps._cache)
if __name__ == '__main__':
unittest_main()
--- a/web/webconfig.py Mon May 03 14:17:45 2010 +0200
+++ b/web/webconfig.py Wed May 05 10:22:11 2010 +0200
@@ -26,6 +26,7 @@
from warnings import warn
from logilab.common.decorators import cached
+from logilab.common.deprecation import deprecated
from cubicweb.toolsutils import read_config
from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options
@@ -253,29 +254,30 @@
user = unicode(user)
return user, passwd
- def has_resource(self, rid):
- """return true if an external resource is defined"""
- return bool(self.uiprops.get(rid))
-
- @cached
def locate_resource(self, rid):
"""return the directory where the given resource may be found"""
return self._fs_locate(rid, 'data')
- @cached
def locate_doc_file(self, fname):
"""return the directory where the given resource may be found"""
return self._fs_locate(fname, 'wdoc')
- def _fs_locate(self, rid, rdirectory):
+ @cached
+ def _fs_path_locate(self, rid, rdirectory):
"""return the directory where the given resource may be found"""
path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())]
for directory in path:
if exists(join(directory, rdirectory, rid)):
- if rdirectory == 'data' and rid.endswith('.css'):
- return self.uiprops.process_resource(join(directory, rdirectory),
- rid)
- return join(directory, rdirectory)
+ return directory
+
+ def _fs_locate(self, rid, rdirectory):
+ """return the directory where the given resource may be found"""
+ directory = self._fs_path_locate(rid, rdirectory)
+ if directory is None:
+ return None
+ if rdirectory == 'data' and rid.endswith('.css'):
+ return self.uiprops.process_resource(join(directory, rdirectory), rid)
+ return join(directory, rdirectory)
def locate_all_files(self, rid, rdirectory='wdoc'):
"""return all files corresponding to the given resource"""
@@ -319,11 +321,11 @@
libuiprops = join(self.shared_dir(), 'data', 'uiprops.py')
self.uiprops.load(libuiprops)
for path in reversed([self.apphome] + self.cubes_path()):
- self._load_ui_properties(join(path, 'data'))
+ self._load_ui_properties(path)
self._load_ui_properties(self.apphome)
def _load_ui_properties(self, path):
- resourcesfile = join(path, 'external_resources')
+ resourcesfile = join(path, 'data', 'external_resources')
if exists(resourcesfile):
warn('[3.9] %s file is deprecated, use an uiprops.py file'
% resourcesfile, DeprecationWarning)
@@ -367,3 +369,8 @@
def static_file_del(self, rpath):
if self.static_file_exists(rpath):
os.remove(join(self.static_directory, rpath))
+
+ @deprecated('[3.9] use _cw.uiprops.get(rid)')
+ def has_resource(self, rid):
+ """return true if an external resource is defined"""
+ return bool(self.uiprops.get(rid))