Commit c7766983 by Chris Jerdonek

Merge branch 'issue_32' into development: closing issue #32

Template and View classes now support disabling HTML escaping.
parents fd2f53da 5bdba9c5
...@@ -3,6 +3,7 @@ History ...@@ -3,6 +3,7 @@ History
Next Release (version TBD) Next Release (version TBD)
-------------------------- --------------------------
* Feature: Template and View support disabling HTML escape. [cjerdonek]
* Bugfix: context values no longer processed as template strings. [jakearchibald] * Bugfix: context values no longer processed as template strings. [jakearchibald]
* API change: pass the context to render to Template.render() instead of * API change: pass the context to render to Template.render() instead of
Template.__init__(). [cjerdonek] Template.__init__(). [cjerdonek]
......
...@@ -62,7 +62,8 @@ class Template(object): ...@@ -62,7 +62,8 @@ class Template(object):
modifiers = Modifiers() modifiers = Modifiers()
def __init__(self, template=None, load_template=None, output_encoding=None): def __init__(self, template=None, load_template=None, output_encoding=None,
disable_escape=False):
""" """
Construct a Template instance. Construct a Template instance.
...@@ -85,12 +86,19 @@ class Template(object): ...@@ -85,12 +86,19 @@ class Template(object):
loader = Loader() loader = Loader()
load_template = loader.load_template load_template = loader.load_template
self.disable_escape = disable_escape
self.load_template = load_template self.load_template = load_template
self.output_encoding = output_encoding self.output_encoding = output_encoding
self.template = template self.template = template
self._compile_regexps() self._compile_regexps()
def escape(self, text):
return escape(text)
def literal(self, text):
return literal(text)
def _initialize_context(self, context, **kwargs): def _initialize_context(self, context, **kwargs):
""" """
Initialize the context attribute. Initialize the context attribute.
...@@ -206,7 +214,7 @@ class Template(object): ...@@ -206,7 +214,7 @@ class Template(object):
def _render_dictionary(self, template, context): def _render_dictionary(self, template, context):
self.context.push(context) self.context.push(context)
template = Template(template, load_template=self.load_template) template = Template(template, load_template=self.load_template, disable_escape=self.disable_escape)
out = template.render(self.context) out = template.render(self.context)
self.context.pop() self.context.pop()
...@@ -236,7 +244,7 @@ class Template(object): ...@@ -236,7 +244,7 @@ class Template(object):
else: else:
return '' return ''
return escape(raw) return self._render_value(raw)
@modifiers.set('!') @modifiers.set('!')
def _render_comment(self, tag_name): def _render_comment(self, tag_name):
...@@ -245,7 +253,7 @@ class Template(object): ...@@ -245,7 +253,7 @@ class Template(object):
@modifiers.set('>') @modifiers.set('>')
def _render_partial(self, template_name): def _render_partial(self, template_name):
markup = self.load_template(template_name) markup = self.load_template(template_name)
template = Template(markup, load_template=self.load_template) template = Template(markup, load_template=self.load_template, disable_escape=self.disable_escape)
return template.render(self.context) return template.render(self.context)
@modifiers.set('=') @modifiers.set('=')
...@@ -286,6 +294,8 @@ class Template(object): ...@@ -286,6 +294,8 @@ class Template(object):
""" """
self._initialize_context(context, **kwargs) self._initialize_context(context, **kwargs)
self._render_value = self.literal if self.disable_escape else self.escape
result = self._render(self.template) result = self._render(self.template)
if self.output_encoding is not None: if self.output_encoding is not None:
......
...@@ -88,12 +88,13 @@ class View(object): ...@@ -88,12 +88,13 @@ class View(object):
return re.sub('[A-Z]', repl, template_name)[1:] return re.sub('[A-Z]', repl, template_name)[1:]
def render(self, encoding=None): def render(self, encoding=None, disable_escape=False):
""" """
Return the view rendered using the current context. Return the view rendered using the current context.
""" """
template = Template(self.get_template(), self.load_template, output_encoding=encoding) template = Template(self.get_template(), self.load_template, output_encoding=encoding,
disable_escape=disable_escape)
return template.render(self.context) return template.render(self.context)
def get(self, key, default=None): def get(self, key, default=None):
......
...@@ -34,6 +34,9 @@ class TestView(unittest.TestCase): ...@@ -34,6 +34,9 @@ class TestView(unittest.TestCase):
def test_escaped(self): def test_escaped(self):
self.assertEquals(Escaped().render(), "<h1>Bear &gt; Shark</h1>") self.assertEquals(Escaped().render(), "<h1>Bear &gt; Shark</h1>")
def test_escaped_disabling(self):
self.assertEquals(Escaped().render(disable_escape=True), "<h1>Bear > Shark</h1>")
def test_unescaped(self): def test_unescaped(self):
self.assertEquals(Unescaped().render(), "<h1>Bear > Shark</h1>") self.assertEquals(Unescaped().render(), "<h1>Bear > Shark</h1>")
......
...@@ -15,6 +15,14 @@ class TemplateTestCase(unittest.TestCase): ...@@ -15,6 +15,14 @@ class TemplateTestCase(unittest.TestCase):
"""Test the Template class.""" """Test the Template class."""
def test_init__disable_escape(self):
# Test default value.
template = Template()
self.assertEquals(template.disable_escape, False)
template = Template(disable_escape=True)
self.assertEquals(template.disable_escape, True)
def test_render__unicode(self): def test_render__unicode(self):
template = Template(u'foo') template = Template(u'foo')
actual = template.render() actual = template.render()
...@@ -117,3 +125,37 @@ class TemplateTestCase(unittest.TestCase): ...@@ -117,3 +125,37 @@ class TemplateTestCase(unittest.TestCase):
context = {'test': (lambda text: '{{hi}} %s' % text)} context = {'test': (lambda text: '{{hi}} %s' % text)}
actual = template.render(context) actual = template.render(context)
self.assertEquals(actual, '{{hi}} Mom') self.assertEquals(actual, '{{hi}} Mom')
def test_render__html_escape(self):
context = {'test': '1 < 2'}
template = Template('{{test}}')
self.assertEquals(template.render(context), '1 &lt; 2')
def test_render__html_escape_disabled(self):
context = {'test': '1 < 2'}
template = Template('{{test}}')
self.assertEquals(template.render(context), '1 &lt; 2')
template.disable_escape = True
self.assertEquals(template.render(context), '1 < 2')
def test_render__html_escape_disabled_with_partial(self):
context = {'test': '1 < 2'}
load_template = lambda name: '{{test}}'
template = Template('{{>partial}}', load_template=load_template)
self.assertEquals(template.render(context), '1 &lt; 2')
template.disable_escape = True
self.assertEquals(template.render(context), '1 < 2')
def test_render__html_escape_disabled_with_non_false_value(self):
context = {'section': {'test': '1 < 2'}}
template = Template('{{#section}}{{test}}{{/section}}')
self.assertEquals(template.render(context), '1 &lt; 2')
template.disable_escape = True
self.assertEquals(template.render(context), '1 < 2')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment