diff --git a/tornado/template.py b/tornado/template.py index dded819a02..648621ed05 100644 --- a/tornado/template.py +++ b/tornado/template.py @@ -543,6 +543,15 @@ def _parse(reader, template, in_block=None): start_brace = reader.consume(2) line = reader.line + # Template directives may be escaped as "{{!" or "{%!". + # In this case output the braces and consume the "!". + # This is especially useful in conjunction with jquery templates, + # which also use double braces. + if reader.remaining() and reader[0] == "!": + reader.consume(1) + body.chunks.append(_Text(start_brace)) + continue + # Expression if start_brace == "{{": end = reader.find("}}") diff --git a/tornado/test/template_test.py b/tornado/test/template_test.py index cff4de3605..037e3625c6 100644 --- a/tornado/test/template_test.py +++ b/tornado/test/template_test.py @@ -1,5 +1,5 @@ from tornado.escape import utf8, native_str -from tornado.template import Template, DictLoader +from tornado.template import Template, DictLoader, ParseError from tornado.testing import LogTrapTestCase from tornado.util import b, bytes_type @@ -50,6 +50,15 @@ def test_relative_load(self): self.assertEqual(loader.load("a/1.html").generate(), b("ok")) + def test_escaping(self): + self.assertRaises(ParseError, lambda: Template("{{")) + self.assertRaises(ParseError, lambda: Template("{%")) + self.assertEqual(Template("{{!").generate(), b("{{")) + self.assertEqual(Template("{%!").generate(), b("{%")) + self.assertEqual(Template("{{ 'expr' }} {{!jquery expr}}").generate(), + b("expr {{jquery expr}}")) + + class AutoEscapeTest(LogTrapTestCase): def setUp(self): self.templates = {