From e25f24def56e3e54b6ddf6e7213f4b810769586d Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 19 May 2008 11:20:41 +0200 Subject: [PATCH] more thread safety in LRUCache --HG-- branch : trunk --- docs/templates.rst | 2 +- jinja2/utils.py | 28 ++++++++++++++++++++++++++-- tests/test_filters.py | 12 +++++++++++- tests/test_imports.py | 15 +++++++++++++++ tests/test_inheritance.py | 5 +++++ tests/test_lrucache.py | 25 +++++++++++++++++++++++++ tests/test_various.py | 12 ------------ 7 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 tests/test_lrucache.py diff --git a/docs/templates.rst b/docs/templates.rst index 935eff7..56c20f9 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -1019,6 +1019,6 @@ do If the expression-statement extension is loaded a tag called `do` is available that works exactly like the regular variable expression (``{{ ... }}``) just -that it doesn't print anything. This can be used to modify lists: +that it doesn't print anything. This can be used to modify lists:: {% do navigation.append('a string') %} diff --git a/jinja2/utils.py b/jinja2/utils.py index 9d46639..529abd2 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -465,12 +465,36 @@ class LRUCache(object): finally: self._wlock.release() - def __iter__(self): - """Iterate over all values in the cache dict, ordered by + def items(self): + """Return a list of items.""" + result = [(key, self._mapping[key]) for key in list(self._queue)] + result.reverse() + return result + + def iteritems(self): + """Iterate over all items.""" + return iter(self.items()) + + def values(self): + """Return a list of all values.""" + return [x[1] for x in self.items()] + + def itervalue(self): + """Iterate over all values.""" + return iter(self.values()) + + def keys(self): + """Return a list of all keys ordered by most recent usage.""" + return list(self) + + def iterkeys(self): + """Iterate over all keys in the cache dict, ordered by the most recent usage. """ return reversed(tuple(self._queue)) + __iter__ = iterkeys + def __reversed__(self): """Iterate over the values in the cache dict, oldest items coming first. diff --git a/tests/test_filters.py b/tests/test_filters.py index 824346e..6592027 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -13,6 +13,7 @@ :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ +from jinja2 import Markup CAPITALIZE = '''{{ "foo bar"|capitalize }}''' CENTER = '''{{ "foo"|center(9) }}''' @@ -69,7 +70,6 @@ GROUPBY = '''{% for grouper, list in [{'foo': 1, 'bar': 2}, FILTERTAG = '''{% filter upper|replace('FOO', 'foo') %}foobar{% endfilter %}''' - def test_capitalize(env): tmpl = env.from_string(CAPITALIZE) assert tmpl.render() == 'Foo bar' @@ -291,3 +291,13 @@ def test_groupby(env): def test_filtertag(env): tmpl = env.from_string(FILTERTAG) assert tmpl.render() == 'fooBAR' + + +def test_replace(env): + tmpl = env.from_string('{{ "foo"|replace("o", 42)}}') + assert tmpl.render() == 'f4242' + + +def test_forceescape(env): + tmpl = env.from_string('{{ x|forceescape }}') + assert tmpl.render(x=Markup('
')) == u'<div />' diff --git a/tests/test_imports.py b/tests/test_imports.py index 92495e5..2afab2e 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -46,3 +46,18 @@ def test_trailing_comma(): test_env.from_string('{% from "foo" import bar, with context %}') test_env.from_string('{% from "foo" import bar, with, context %}') test_env.from_string('{% from "foo" import bar, with with context %}') + + +def test_exports(): + m = test_env.from_string(''' + {% macro toplevel() %}...{% endmacro %} + {% macro __private() %}...{% endmacro %} + {% set variable = 42 %} + {% for item in [1] %} + {% macro notthere() %}{% endmacro %} + {% endfor %} + ''').module + assert m.toplevel() == '...' + assert not hasattr(m, '__missing') + assert m.variable == 42 + assert not hasattr(m, 'notthere') diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index 34e5738..114ec9c 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -93,3 +93,8 @@ def test_super(): def test_working(env): tmpl = env.get_template('working') + + +def test_reuse_blocks(env): + tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42{% endblock %}|{{ self.foo() }}') + assert tmpl.render() == '42|42|42' diff --git a/tests/test_lrucache.py b/tests/test_lrucache.py new file mode 100644 index 0000000..6617e5c --- /dev/null +++ b/tests/test_lrucache.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" + Tests the LRUCache + ~~~~~~~~~~~~~~~~~~ + + This module tests the LRU Cache + + :copyright: Copyright 2008 by Armin Ronacher. + :license: GNU GPL. +""" +import thread +import time +import random +from jinja2.utils import LRUCache + + +def test_simple(): + d = LRUCache(3) + d["a"] = 1 + d["b"] = 2 + d["c"] = 3 + d["a"] + d["d"] = 4 + assert len(d) == 3 + assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d diff --git a/tests/test_various.py b/tests/test_various.py index 9235a29..e81dfc0 100644 --- a/tests/test_various.py +++ b/tests/test_various.py @@ -30,18 +30,6 @@ def test_raw(env): assert tmpl.render() == '{{ FOO }} and {% BAR %}' -def test_lru_cache(): - from jinja2.utils import LRUCache - d = LRUCache(3) - d["a"] = 1 - d["b"] = 2 - d["c"] = 3 - d["a"] - d["d"] = 4 - assert len(d) == 3 - assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d - - def test_const(env): tmpl = env.from_string(CONST) assert tmpl.render() == 'True|False|None|True|False' -- 2.26.2