summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-01-16 13:02:51 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2012-01-16 13:02:51 -0500
commit2879f8bcc02d75d256bf7db97251a8708ef2466e (patch)
treeb64ad6ab41312ce66147818802e218a8057e50e7
parent3266c0160d9103703400123b81a713db21ccd5be (diff)
downloadmako-2879f8bcc02d75d256bf7db97251a8708ef2466e.tar.gz
- [feature/bug] Can now refer to context variables
within extra arguments to <%block>, <%def>, i.e. <%block name="foo" cache_key="${somekey}">. Filters can also be used in this way, i.e. <%def name="foo()" filter="myfilter"> then template.render(myfilter=some_callable) [ticket:180]
-rw-r--r--CHANGES10
-rw-r--r--mako/__init__.py2
-rw-r--r--mako/codegen.py8
-rw-r--r--mako/parsetree.py14
-rw-r--r--test/test_cache.py31
-rw-r--r--test/test_filters.py37
6 files changed, 92 insertions, 10 deletions
diff --git a/CHANGES b/CHANGES
index 07c9ff4..c24d19b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,12 @@
-0.5.1
+0.6.0
+- [feature/bug] Can now refer to context variables
+ within extra arguments to <%block>, <%def>, i.e.
+ <%block name="foo" cache_key="${somekey}">.
+ Filters can also be used in this way, i.e.
+ <%def name="foo()" filter="myfilter">
+ then template.render(myfilter=some_callable)
+ [ticket:180]
+
- Template caching has been converted into a plugin
system, whereby the usage of Beaker is just the
default plugin. Template and TemplateLookup
diff --git a/mako/__init__.py b/mako/__init__.py
index d3c2796..2362d3a 100644
--- a/mako/__init__.py
+++ b/mako/__init__.py
@@ -5,5 +5,5 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-__version__ = '0.5.1'
+__version__ = '0.6.0'
diff --git a/mako/codegen.py b/mako/codegen.py
index 0310964..5a7737b 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -414,7 +414,7 @@ class _GenerateRenderMethod(object):
# (this is used for the caching decorator)
if limit is not None:
to_write = to_write.intersection(limit)
-
+
if toplevel and getattr(self.compiler, 'has_ns_imports', False):
self.printer.writeline("_import_ns = {}")
self.compiler.has_imports = True
@@ -866,7 +866,6 @@ class _Identifiers(object):
"""tracks the status of identifier names as template code is rendered."""
def __init__(self, node=None, parent=None, nested=False):
-
if parent is not None:
# if we are the branch created in write_namespaces(),
# we don't share any context from the main body().
@@ -1000,6 +999,7 @@ class _Identifiers(object):
if node is self.node:
for ident in node.declared_identifiers():
self.argument_declared.add(ident)
+
for n in node.nodes:
n.accept_visitor(self)
@@ -1016,6 +1016,10 @@ class _Identifiers(object):
"Named block '%s' not allowed inside of <%%call> tag"
% (node.name, ), **node.exception_kwargs)
+ for ident in node.undeclared_identifiers():
+ if ident != 'context' and ident not in self.declared.union(self.locally_declared):
+ self.undeclared.add(ident)
+
if not node.is_anonymous:
self._check_name_exists(self.topleveldefs, node)
self.undeclared.add(node.funcname)
diff --git a/mako/parsetree.py b/mako/parsetree.py
index 9896dd8..98a8701 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -431,10 +431,13 @@ class DefTag(Tag):
for c in self.function_decl.defaults:
res += list(ast.PythonCode(c, **self.exception_kwargs).
undeclared_identifiers)
- return res + list(self.filter_args.\
+ return set(res).union(
+ self.filter_args.\
undeclared_identifiers.\
difference(filters.DEFAULT_ESCAPES.keys())
- )
+ ).union(
+ self.expression_undeclared_identifiers
+ )
class BlockTag(Tag):
__keyword__ = 'block'
@@ -487,7 +490,12 @@ class BlockTag(Tag):
return self.body_decl.argnames
def undeclared_identifiers(self):
- return []
+ return (self.filter_args.\
+ undeclared_identifiers.\
+ difference(filters.DEFAULT_ESCAPES.keys())
+ ).union(self.expression_undeclared_identifiers)
+
+
class CallTag(Tag):
__keyword__ = 'call'
diff --git a/test/test_cache.py b/test/test_cache.py
index d898b02..1c7b42a 100644
--- a/test/test_cache.py
+++ b/test/test_cache.py
@@ -139,6 +139,37 @@ class CacheTest(TemplateTest):
]
assert m.kwargs == {}
+ def test_dynamic_key_with_context(self):
+ t = Template("""
+ <%block name="foo" cached="True" cache_key="${mykey}">
+ some block
+ </%block>
+ """)
+ m = self._install_mock_cache(t)
+ t.render(mykey="thekey")
+ t.render(mykey="thekey")
+ eq_(
+ result_lines(t.render(mykey="thekey")),
+ ["some block"]
+ )
+ eq_(m.key, "thekey")
+
+ t = Template("""
+ <%def name="foo()" cached="True" cache_key="${mykey}">
+ some def
+ </%def>
+ ${foo()}
+ """)
+ m = self._install_mock_cache(t)
+ t.render(mykey="thekey")
+ t.render(mykey="thekey")
+ eq_(
+ result_lines(t.render(mykey="thekey")),
+ ["some def"]
+ )
+ eq_(m.key, "thekey")
+
+
def test_dynamic_key_with_funcargs(self):
t = Template("""
<%def name="foo(num=5)" cached="True" cache_key="foo_${str(num)}">
diff --git a/test/test_filters.py b/test/test_filters.py
index 13492d8..684705d 100644
--- a/test/test_filters.py
+++ b/test/test_filters.py
@@ -3,7 +3,7 @@
from mako.template import Template
import unittest
from mako import util
-from test import TemplateTest, eq_, skip_if
+from test import TemplateTest, eq_, skip_if, assert_raises
from util import result_lines, flatten_result
class FilterTest(TemplateTest):
@@ -60,7 +60,11 @@ class FilterTest(TemplateTest):
${foo()}
""")
- assert flatten_result(t.render(x="this is x", myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)) == "MYFILTER-> this is foo <-MYFILTER"
+ eq_(
+ flatten_result(t.render(x="this is x",
+ myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)),
+ "MYFILTER-> this is foo <-MYFILTER"
+ )
def test_import(self):
t = Template("""
@@ -104,6 +108,33 @@ class FilterTest(TemplateTest):
""")
assert t.render().strip() == "&lt;tag&gt;this is html&lt;/tag&gt;"
+ def test_block_via_context(self):
+ t = Template("""
+ <%block name="foo" filter="myfilter">
+ some text
+ </%block>
+ """)
+ def myfilter(text):
+ return "MYTEXT" + text
+ eq_(
+ result_lines(t.render(myfilter=myfilter)),
+ ["MYTEXT", "some text"]
+ )
+
+ def test_def_via_context(self):
+ t = Template("""
+ <%def name="foo()" filter="myfilter">
+ some text
+ </%def>
+ ${foo()}
+ """)
+ def myfilter(text):
+ return "MYTEXT" + text
+ eq_(
+ result_lines(t.render(myfilter=myfilter)),
+ ["MYTEXT", "some text"]
+ )
+
def test_nflag(self):
t = Template("""
${"<tag>this is html</tag>" | n}
@@ -122,7 +153,7 @@ class FilterTest(TemplateTest):
""")
assert t.render().strip() == "&lt;tag&gt;this is html&lt;/tag&gt;"
- def testnonexpression(self):
+ def test_non_expression(self):
t = Template("""
<%!
def a(text):