else:
self.autoescape = _DEFAULT_AUTOESCAPE
self.namespace = loader.namespace if loader else {}
- reader = _TemplateReader(name, escape.native_str(template_string))
+ reader = _TemplateReader(name, escape.native_str(template_string),
+ compress_whitespace)
self.file = _File(self, _parse(reader, self))
- self.code = self._generate_python(loader, compress_whitespace)
+ self.code = self._generate_python(loader)
self.loader = loader
try:
# Under python2.5, the fake filename used here must match
linecache.clearcache()
return execute()
- def _generate_python(self, loader, compress_whitespace):
+ def _generate_python(self, loader):
buffer = StringIO()
try:
# named_blocks maps from names to _NamedBlock objects
ancestors.reverse()
for ancestor in ancestors:
ancestor.find_named_blocks(loader, named_blocks)
- writer = _CodeWriter(buffer, named_blocks, loader, ancestors[0].template,
- compress_whitespace)
+ writer = _CodeWriter(buffer, named_blocks, loader,
+ ancestors[0].template)
ancestors[0].generate(writer)
return buffer.getvalue()
finally:
class _Text(_Node):
- def __init__(self, value, line):
+ def __init__(self, value, line, compress_whitespace):
self.value = value
self.line = line
+ self.compress_whitespace = compress_whitespace
def generate(self, writer):
value = self.value
# Compress lots of white space to a single character. If the whitespace
# breaks a line, have it continue to break a line, but just with a
# single \n character
- if writer.compress_whitespace and "<pre>" not in value:
+ if self.compress_whitespace and "<pre>" not in value:
value = re.sub(r"([\t ]+)", " ", value)
value = re.sub(r"(\s*\n\s*)", "\n", value)
class _CodeWriter(object):
- def __init__(self, file, named_blocks, loader, current_template,
- compress_whitespace):
+ def __init__(self, file, named_blocks, loader, current_template):
self.file = file
self.named_blocks = named_blocks
self.loader = loader
self.current_template = current_template
- self.compress_whitespace = compress_whitespace
self.apply_counter = 0
self.include_stack = []
self._indent = 0
class _TemplateReader(object):
- def __init__(self, name, text):
+ def __init__(self, name, text, compress_whitespace):
self.name = name
self.text = text
+ self.compress_whitespace = compress_whitespace
self.line = 1
self.pos = 0
if in_block:
reader.raise_parse_error(
"Missing {%% end %%} block for %s" % in_block)
- body.chunks.append(_Text(reader.consume(), reader.line))
+ body.chunks.append(_Text(reader.consume(), reader.line,
+ reader.compress_whitespace))
return body
# If the first curly brace is not the start of a special token,
# start searching from the character after it
# Append any text before the special token
if curly > 0:
cons = reader.consume(curly)
- body.chunks.append(_Text(cons, reader.line))
+ body.chunks.append(_Text(cons, reader.line,
+ reader.compress_whitespace))
start_brace = reader.consume(2)
line = reader.line
# which also use double braces.
if reader.remaining() and reader[0] == "!":
reader.consume(1)
- body.chunks.append(_Text(start_brace, line))
+ body.chunks.append(_Text(start_brace, line,
+ reader.compress_whitespace))
continue
# Comment
self.assertEqual(render("foo.py", ["not a string"]),
b"""s = "['not a string']"\n""")
- def test_minimize_whitespace(self):
+ def test_manual_minimize_whitespace(self):
# Whitespace including newlines is allowed within template tags
# and directives, and this is one way to avoid long lines while
# keeping extra whitespace out of the rendered output.
self.assertEqual(loader.load("foo.txt").generate(items=range(5)),
b"0, 1, 2, 3, 4")
+ def test_whitespace_by_filename(self):
+ # Default whitespace handling depends on the template filename.
+ loader = DictLoader({
+ "foo.html": " \n\t\n asdf\t ",
+ "bar.js": " \n\n\n\t qwer ",
+ "baz.txt": "\t zxcv\n\n",
+ "include.html": " {% include baz.txt %} \n ",
+ "include.txt": "\t\t{% include foo.html %} ",
+ })
+
+ # HTML and JS files have whitespace compressed by default.
+ self.assertEqual(loader.load("foo.html").generate(),
+ b"\nasdf ")
+ self.assertEqual(loader.load("bar.js").generate(),
+ b"\nqwer ")
+ # TXT files do not.
+ self.assertEqual(loader.load("baz.txt").generate(),
+ b"\t zxcv\n\n")
+
+ # Each file maintains its own status even when included in
+ # a file of the other type.
+ self.assertEqual(loader.load("include.html").generate(),
+ b" \t zxcv\n\n\n")
+ self.assertEqual(loader.load("include.txt").generate(),
+ b"\t\t\nasdf ")
+
class TemplateLoaderTest(unittest.TestCase):
def setUp(self):