Skip to content

Commit

Permalink
Merge branch 'issue_32' into development: closing issue #32
Browse files Browse the repository at this point in the history
Template and View classes now support disabling HTML escaping.
  • Loading branch information
cjerdonek committed Dec 19, 2011
2 parents fd2f53d + 5bdba9c commit c776698
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 6 deletions.
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ History

Next Release (version TBD)
--------------------------
* Feature: Template and View support disabling HTML escape. [cjerdonek]
* Bugfix: context values no longer processed as template strings. [jakearchibald]
* API change: pass the context to render to Template.render() instead of
Template.__init__(). [cjerdonek]
Expand Down
18 changes: 14 additions & 4 deletions pystache/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ class Template(object):

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.
Expand All @@ -85,12 +86,19 @@ def __init__(self, template=None, load_template=None, output_encoding=None):
loader = Loader()
load_template = loader.load_template

self.disable_escape = disable_escape
self.load_template = load_template
self.output_encoding = output_encoding
self.template = template

self._compile_regexps()

def escape(self, text):
return escape(text)

def literal(self, text):
return literal(text)

def _initialize_context(self, context, **kwargs):
"""
Initialize the context attribute.
Expand Down Expand Up @@ -206,7 +214,7 @@ def _render_tags(self, template):
def _render_dictionary(self, template, 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)

self.context.pop()
Expand Down Expand Up @@ -236,7 +244,7 @@ def _render_tag(self, tag_name):
else:
return ''

return escape(raw)
return self._render_value(raw)

@modifiers.set('!')
def _render_comment(self, tag_name):
Expand All @@ -245,7 +253,7 @@ def _render_comment(self, tag_name):
@modifiers.set('>')
def _render_partial(self, 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)

@modifiers.set('=')
Expand Down Expand Up @@ -286,6 +294,8 @@ def render(self, context=None, **kwargs):
"""
self._initialize_context(context, **kwargs)

self._render_value = self.literal if self.disable_escape else self.escape

result = self._render(self.template)

if self.output_encoding is not None:
Expand Down
5 changes: 3 additions & 2 deletions pystache/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ def repl(match):

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.
"""
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)

def get(self, key, default=None):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def test_unicode_input(self):
def test_escaped(self):
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):
self.assertEquals(Unescaped().render(), "<h1>Bear > Shark</h1>")

Expand Down
42 changes: 42 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ class TemplateTestCase(unittest.TestCase):

"""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):
template = Template(u'foo')
actual = template.render()
Expand Down Expand Up @@ -117,3 +125,37 @@ def test_render__section__lambda__tag_in_output(self):
context = {'test': (lambda text: '{{hi}} %s' % text)}
actual = template.render(context)
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')

0 comments on commit c776698

Please sign in to comment.