From: Armin Ronacher Date: Sun, 29 Apr 2007 17:56:52 +0000 (+0200) Subject: [svn] fixed bug reported by stefan ebner and implemented cache_keys to fix problems... X-Git-Tag: 2.0rc1~331 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ce513f26683207df996de03b4208d7d40186962c;p=jinja2.git [svn] fixed bug reported by stefan ebner and implemented cache_keys to fix problems with multiple laoders caching in the same folder --HG-- branch : trunk --- diff --git a/CHANGES b/CHANGES index 8dcac27..0a7a011 100644 --- a/CHANGES +++ b/CHANGES @@ -83,6 +83,12 @@ Version 1.1 - fixed a corner case when defining a block inside of a condition +- the cached loader mixin is now able to cache multiple templates from + different loaders in the same cache folder. + +- Translatable strings returned by ``_()`` will leave their string formatting + signs untouched. Thanks to Stefan Ebner for reporting. + Version 1.0 ----------- diff --git a/THANKS b/THANKS index e9d865c..2bbb74e 100644 --- a/THANKS +++ b/THANKS @@ -4,5 +4,7 @@ Thanks To All the people listed here helped improving Jinja a lot, provided patches, helped working out solutions etc. Thanks to all of you! +- Ronny Pfannschmidt - Axel Böhm - Alexey Melchakov +- Stefan Ebner diff --git a/docs/src/loaders.txt b/docs/src/loaders.txt index 20c69e2..29da849 100644 --- a/docs/src/loaders.txt +++ b/docs/src/loaders.txt @@ -61,11 +61,14 @@ Note that you have to give it a higher priority in the MRO than the def __init__(self, path): self.path = path - CachedLoaderMixin.__init__( + CachedLoaderMixin.__init__(self, True, # use memory caching 40, # for up to 40 templates '/tmp', # additionally save the compiled templates in /tmp - True # and reload cached templates automatically if changed + True, # and reload cached templates automatically if changed + 'foo' # optional salt used to keep templates with the same + # name in the same cache folder, but from different + # loaders. New in Jinja 1.1 and can be omitted. ) def get_source(self, environment, name, parent): @@ -88,4 +91,4 @@ You don't have to provide the `check_source_changed` method. If it doesn't exist the option `auto_reload` won't have an effect. Also note that the `check_source_changed` method must not raise an exception if the template does not exist but return ``-1``. The return value ``-1`` is considered -"always reload" whereas ``0`` means "do not reload". \ No newline at end of file +"always reload" whereas ``0`` means "do not reload". diff --git a/jinja/datastructure.py b/jinja/datastructure.py index 86b74c7..5aa6b2c 100644 --- a/jinja/datastructure.py +++ b/jinja/datastructure.py @@ -276,8 +276,15 @@ class Context(BaseContext): translator = self.environment.get_translator(self) def translate(s, p=None, n=None, r=None): if p is None: - return translator.gettext(s) % (r or {}) - return translator.ngettext(s, p, r[n]) % (r or {}) + s = translator.gettext(s) + else: + s = translator.ngettext(s, p, r[n]) + # apply replacement substitution only if replacements + # are given. This is the case for {% trans %}...{% endtras %} + # but for the "_()" syntax and a trans tag without a body. + if r is not None: + s %= r + return s self._translate_func = translate return self._translate_func translate_func = property(translate_func, doc=translate_func.__doc__) diff --git a/jinja/loaders.py b/jinja/loaders.py index 7bd63a8..6836b32 100644 --- a/jinja/loaders.py +++ b/jinja/loaders.py @@ -38,12 +38,13 @@ def get_template_filename(searchpath, name): if p and p[0] != '.'])) -def get_cachename(cachepath, name): +def get_cachename(cachepath, name, salt=None): """ Return the filename for a cached file. """ return path.join(cachepath, 'jinja_%s.cache' % - sha.new('jinja(%s)tmpl' % name).hexdigest()) + sha.new('jinja(%s|%s)tmpl' % + (name, salt or '')).hexdigest()) class LoaderWrapper(object): @@ -130,7 +131,8 @@ class CachedLoaderMixin(object): Mixin this class to implement simple memory and disk caching. """ - def __init__(self, use_memcache, cache_size, cache_folder, auto_reload): + def __init__(self, use_memcache, cache_size, cache_folder, auto_reload, + cache_salt=None): if use_memcache: self.__memcache = CacheDict(cache_size) else: @@ -140,6 +142,7 @@ class CachedLoaderMixin(object): self.__auto_reload = False else: self.__auto_reload = auto_reload + self.__salt = cache_salt self.__times = {} self.__lock = Lock() @@ -186,7 +189,7 @@ class CachedLoaderMixin(object): # mem cache disabled or not cached by now # try to load if from the disk cache if tmpl is None and self.__cache_folder is not None: - cache_fn = get_cachename(self.__cache_folder, name) + cache_fn = get_cachename(self.__cache_folder, name, self.__salt) if last_change is not None: try: cache_time = path.getmtime(cache_fn) @@ -261,14 +264,20 @@ class FileSystemLoader(CachedLoaderMixin, BaseLoader): ``auto_reload`` Set this to `False` for a slightly better performance. In that case Jinja won't check for template changes on the filesystem. + ``cache_salt`` Optional unique number to not confuse the + caching system when caching more than one + template loader in the same folder. Defaults + to the searchpath. *New in Jinja 1.1* =================== ================================================= """ def __init__(self, searchpath, use_memcache=False, memcache_size=40, - cache_folder=None, auto_reload=True): + cache_folder=None, auto_reload=True, cache_salt=None): + if cache_salt is None: + cache_salt = searchpath self.searchpath = searchpath CachedLoaderMixin.__init__(self, use_memcache, memcache_size, - cache_folder, auto_reload) + cache_folder, auto_reload, cache_salt) def get_source(self, environment, name, parent): filename = get_template_filename(self.searchpath, name) @@ -321,22 +330,30 @@ class PackageLoader(CachedLoaderMixin, BaseLoader): template changes on the filesystem. If the templates are inside of an egg file this won't have an effect. + ``cache_salt`` Optional unique number to not confuse the + caching system when caching more than one + template loader in the same folder. Defaults + to ``package_name + '/' + package_path``. + *New in Jinja 1.1* =================== ================================================= """ def __init__(self, package_name, package_path, use_memcache=False, - memcache_size=40, cache_folder=None, auto_reload=True): + memcache_size=40, cache_folder=None, auto_reload=True, + cache_salt=None): if resource_filename is None: raise ImportError('setuptools not found') self.package_name = package_name self.package_path = package_path + if cache_salt is None: + cache_salt = package_name + '/' + package_path # if we have an loader we probably retrieved it from an egg # file. In that case don't use the auto_reload! if auto_reload and getattr(__import__(package_name, '', '', ['']), '__loader__', None) is not None: auto_reload = False CachedLoaderMixin.__init__(self, use_memcache, memcache_size, - cache_folder, auto_reload) + cache_folder, auto_reload, cache_salt) def get_source(self, environment, name, parent): name = '/'.join([self.package_path] + [p for p in name.split('/') @@ -401,11 +418,15 @@ class FunctionLoader(CachedLoaderMixin, BaseLoader): ``auto_reload`` Set this to `False` for a slightly better performance. In that case of `getmtime_func` not being provided this won't have an effect. + ``cache_salt`` Optional unique number to not confuse the + caching system when caching more than one + template loader in the same folder. =================== ================================================= """ def __init__(self, loader_func, getmtime_func=None, use_memcache=False, - memcache_size=40, cache_folder=None, auto_reload=True): + memcache_size=40, cache_folder=None, auto_reload=True, + cache_salt=None): # when changing the signature also check the jinja.plugin function # loader instantiation. self.loader_func = loader_func @@ -413,7 +434,7 @@ class FunctionLoader(CachedLoaderMixin, BaseLoader): if auto_reload and getmtime_func is None: auto_reload = False CachedLoaderMixin.__init__(self, use_memcache, memcache_size, - cache_folder, auto_reload) + cache_folder, auto_reload, cache_salt) def get_source(self, environment, name, parent): rv = self.loader_func(name) diff --git a/tests/test_i18n.py b/tests/test_i18n.py index ddd5841..040f7ba 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -14,7 +14,8 @@ templates = { 'child.html': '{% extends "master.html" %}{% block body %}' '{% trans "watch out" %}{% endblock %}', 'plural.html': '{% trans user_count %}One user online{% pluralize %}' - '{{ user_count }} users online{% endtrans %}' + '{{ user_count }} users online{% endtrans %}', + 'stringformat.html': '{{ _("User: %d")|format(user_count) }}' } @@ -23,7 +24,8 @@ languages = { 'missing': 'fehlend', 'watch out': 'pass auf', 'One user online': 'Ein Benutzer online', - '%(user_count)s users online': '%(user_count)s Benutzer online' + '%(user_count)s users online': '%(user_count)s Benutzer online', + 'User: %d': 'Benutzer: %d' } } @@ -77,3 +79,8 @@ def test_trans_plural(): tmpl = i18n_env.get_template('plural.html') assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' + + +def test_trans_stringformatting(): + tmpl = i18n_env.get_template('stringformat.html') + assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'