Ticket #2594: ticket-2594-template-strip-leading-whitespace-2012-06-28.diff
File ticket-2594-template-strip-leading-whitespace-2012-06-28.diff, 26.8 KB (added by , 12 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS index ea0b019..969ba49 100644
a b answer newbie questions, and generally made Django that much better: 292 292 Ian G. Kelly <ian.g.kelly@gmail.com> 293 293 Niall Kelly <duke.sam.vimes@gmail.com> 294 294 Ryan Kelly <ryan@rfk.id.au> 295 Stephen Kelly <steveire@gmail.com> 295 296 Thomas Kerpe <thomas@kerpe.net> 296 297 Wiley Kestner <wiley.kestner@gmail.com> 297 298 Ossama M. Khayat <okhayat@yahoo.com> -
django/conf/global_settings.py
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 13f7991..05bb413 100644
a b TEMPLATE_CONTEXT_PROCESSORS = ( 209 209 # Output to use in template system for invalid (e.g. misspelled) variables. 210 210 TEMPLATE_STRING_IF_INVALID = '' 211 211 212 # Remove the empty lines that had template tags on them. 213 TEMPLATE_STRIP_LEADING_WHITESPACE = False 214 212 215 # Default email address to use for various automated correspondence from 213 216 # the site managers. 214 217 DEFAULT_FROM_EMAIL = 'webmaster@localhost' -
django/template/base.py
diff --git a/django/template/base.py b/django/template/base.py index 89bc909..0964f5d 100644
a b UNKNOWN_SOURCE = '<unknown source>' 55 55 56 56 # match a variable or block tag and capture the entire tag, including start/end 57 57 # delimiters 58 tag_re = (re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % 59 (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 60 re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), 61 re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))) 58 tag_re = re.compile(''' 59 ( 60 %(BLOCK_TAG_START)s.*?%(BLOCK_TAG_END)s # block start + inner + end 61 | %(VARIABLE_TAG_START)s.*?%(VARIABLE_TAG_END)s # variable start + inner + end 62 | %(COMMENT_TAG_START)s.*?%(COMMENT_TAG_END)s # comment start + inner + end 63 ) 64 ''' % { 65 'BLOCK_TAG_START': re.escape(BLOCK_TAG_START), 66 'BLOCK_TAG_END': re.escape(BLOCK_TAG_END), 67 'VARIABLE_TAG_START': re.escape(VARIABLE_TAG_START), 68 'VARIABLE_TAG_END': re.escape(VARIABLE_TAG_END), 69 'COMMENT_TAG_START': re.escape(COMMENT_TAG_START), 70 'COMMENT_TAG_END': re.escape(COMMENT_TAG_END), 71 }, re.VERBOSE) 72 73 strip_leading_whitespace_tag_re = re.compile(''' 74 ( 75 [\n\r]{1} # 1 vertical white space (the one starting this line) 76 [ \t]*? # any number of tabs or spaces 77 (?: # group but don't match 78 %(BLOCK_TAG_START)s 79 [^\n\r%(BLOCK_TAG_START)s%(BLOCK_TAG_END)s]*? # anything *not* vertical whitespace or 80 %(BLOCK_TAG_END)s # opening/closing block tag 81 | 82 %(COMMENT_TAG_START)s 83 [^\n\r%(COMMENT_TAG_START)s%(COMMENT_TAG_END)s]*? # anything *not* vertical whitespace or 84 %(COMMENT_TAG_END)s # opening/closing comment tag 85 | 86 %(VARIABLE_TAG_START)s 87 [^\n\r%(VARIABLE_TAG_START)s%(VARIABLE_TAG_END)s]*? # anything *not* vertical whitespace or 88 %(VARIABLE_TAG_END)s # opening/closing variable tag 89 ) 90 (?= # Match this only if the previous matched 91 [ \t]*? 92 [\n\r]+ 93 )| 94 %(BLOCK_TAG_START)s.*?%(BLOCK_TAG_END)s # block start + inner + end 95 | %(VARIABLE_TAG_START)s.*?%(VARIABLE_TAG_END)s # variable start + inner + end 96 | %(COMMENT_TAG_START)s.*?%(COMMENT_TAG_END)s # comment start + inner + end 97 )''' % { 98 'BLOCK_TAG_START': re.escape(BLOCK_TAG_START), 99 'BLOCK_TAG_END': re.escape(BLOCK_TAG_END), 100 'VARIABLE_TAG_START': re.escape(VARIABLE_TAG_START), 101 'VARIABLE_TAG_END': re.escape(VARIABLE_TAG_END), 102 'COMMENT_TAG_START': re.escape(COMMENT_TAG_START), 103 'COMMENT_TAG_END': re.escape(COMMENT_TAG_END), 104 }, re.VERBOSE) 105 106 # find the command within a block tag 107 block_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END))) 108 comment_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) 109 variable_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END))) 62 110 63 111 # global dictionary of libraries that have been loaded using get_library 64 112 libraries = {} … … class Token(object): 179 227 split.append(bit) 180 228 return split 181 229 230 182 231 class Lexer(object): 183 232 def __init__(self, template_string, origin): 184 233 self.template_string = template_string 185 234 self.origin = origin 186 235 self.lineno = 1 187 self.verbatim = False 236 self.verbatim = False # or 'endverbatim' or 'endverbatim %s' % block 188 237 189 238 def tokenize(self): 190 239 """ … … class Lexer(object): 192 241 """ 193 242 in_tag = False 194 243 result = [] 195 for bit in tag_re.split(self.template_string): 244 tag_splitter = strip_leading_whitespace_tag_re if settings.TEMPLATE_STRIP_LEADING_WHITESPACE else tag_re 245 for bit in tag_splitter.split(self.template_string): 196 246 if bit: 197 247 result.append(self.create_token(bit, in_tag)) 198 248 in_tag = not in_tag … … class Lexer(object): 204 254 If in_tag is True, we are processing something that matched a tag, 205 255 otherwise it should be treated as a literal string. 206 256 """ 207 if in_tag and token_string.startswith(BLOCK_TAG_START): 257 # Extract ``block_content``, check for verbatim tag 258 if in_tag and token_string.lstrip().startswith(BLOCK_TAG_START): 208 259 # The [2:-2] ranges below strip off *_TAG_START and *_TAG_END. 209 260 # We could do len(BLOCK_TAG_START) to be more "correct", but we've 210 261 # hard-coded the 2s here for performance. And it's not like … … class Lexer(object): 212 263 block_content = token_string[2:-2].strip() 213 264 if self.verbatim and block_content == self.verbatim: 214 265 self.verbatim = False 266 267 # Create ``token`` object... 215 268 if in_tag and not self.verbatim: 216 if token_string.startswith(VARIABLE_TAG_START): 217 token = Token(TOKEN_VAR, token_string[2:-2].strip()) 218 elif token_string.startswith(BLOCK_TAG_START): 269 # ...by processing a... 270 if token_string.lstrip().startswith(VARIABLE_TAG_START): 271 # ...variable tag. 272 token_struct = variable_command_re.search(token_string) 273 token_string = token_struct.group('token_string') 274 token = Token(TOKEN_VAR, token_string.strip()) 275 elif token_string.lstrip().startswith(BLOCK_TAG_START): 276 # ...block tag. 219 277 if block_content[:9] in ('verbatim', 'verbatim '): 220 278 self.verbatim = 'end%s' % block_content 221 token = Token(TOKEN_BLOCK, block_content) 222 elif token_string.startswith(COMMENT_TAG_START): 279 token_struct = block_command_re.search(token_string) 280 token_string = token_struct.group('token_string') 281 token = Token(TOKEN_BLOCK, token_string.strip()) 282 elif token_string.lstrip().startswith(COMMENT_TAG_START): 283 # ...comment tag. 223 284 content = '' 285 token_struct = comment_command_re.search(token_string) 286 token_string = token_struct.group('token_string') 224 287 if token_string.find(TRANSLATOR_COMMENT_MARK): 225 content = token_string [2:-2].strip()288 content = token_string.strip() 226 289 token = Token(TOKEN_COMMENT, content) 227 290 else: 291 # ...from a string literal. 228 292 token = Token(TOKEN_TEXT, token_string) 293 229 294 token.lineno = self.lineno 230 295 self.lineno += token_string.count('\n') 231 296 return token 232 297 298 233 299 class Parser(object): 234 300 def __init__(self, tokens): 235 301 self.tokens = tokens -
django/template/debug.py
diff --git a/django/template/debug.py b/django/template/debug.py index 6167403..3df6681 100644
a b 1 from django.template.base import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError 1 from django.conf import settings 2 from django.template.base import Lexer, Parser, tag_re, strip_leading_whitespace_tag_re, NodeList, VariableNode, TemplateSyntaxError 2 3 from django.utils.encoding import force_unicode 3 4 from django.utils.html import escape 4 5 from django.utils.safestring import SafeData, EscapeData … … class DebugLexer(Lexer): 13 14 def tokenize(self): 14 15 "Return a list of tokens from a given template_string" 15 16 result, upto = [], 0 16 for match in tag_re.finditer(self.template_string): 17 tag_splitter = strip_leading_whitespace_tag_re if settings.TEMPLATE_STRIP_LEADING_WHITESPACE else tag_re 18 for match in tag_splitter.finditer(self.template_string): 17 19 start, end = match.span() 18 20 if start > upto: 19 21 result.append(self.create_token(self.template_string[upto:start], (upto, start), False)) -
django/template/defaulttags.py
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 83b72e1..2ca094d 100644
a b from django.template.base import (Node, NodeList, Template, Context, Library, 14 14 VARIABLE_ATTRIBUTE_SEPARATOR, get_library, token_kwargs, kwarg_re) 15 15 from django.template.smartif import IfParser, Literal 16 16 from django.template.defaultfilters import date 17 from django.utils import timezone 17 18 from django.utils.encoding import smart_unicode 18 19 from django.utils.safestring import mark_safe 19 from django.utils import timezone 20 from django.utils.text import smart_split 21 20 22 21 23 register = Library() 22 24 -
docs/ref/settings.txt
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 627aa50..ce9779e 100644
a b Default: ``''`` (Empty string) 1956 1956 Output, as a string, that the template system should use for invalid (e.g. 1957 1957 misspelled) variables. See :ref:`invalid-template-variables`.. 1958 1958 1959 .. setting:: TEMPLATE_STRIP_LEADING_WHITESPACE 1960 1961 TEMPLATE_STRIP_LEADING_WHITESPACE 1962 --------------------------------- 1963 1964 .. versionadded:: 1.5 1965 1966 Default: ``False`` 1967 1968 Whether to strip leading whitespace on template lines containing only template 1969 syntax. 1970 1971 This template code:: 1972 <h1>My list</h1> 1973 1974 {# This is a comment #} 1975 {# It describes the loop below #} 1976 {# Each line appears in the output as an empty line #} 1977 <ul> 1978 {% for item in items %} 1979 {# Description of a list item #} 1980 <li>{{ item }}</li> 1981 {% endfor %} 1982 </ul> 1983 1984 Normally evaluates to:: 1985 <h1>My list</h1> 1986 1987 1988 1989 1990 <ul> 1991 1992 1993 <li>item 1</li> 1994 1995 <li>item 2</li> 1996 1997 <li>item 3</li> 1998 1999 </ul> 2000 2001 However, if TEMPLATE_STRIP_LEADING_WHITESPACE is set to True, lines which 2002 contain only one template tag, variable or comment no not cause a newline 2003 to be inserted in the output:: 2004 2005 <h1>My list</h1> 2006 2007 <ul> 2008 <li>item 1</li> 2009 <li>item 2</li> 2010 <li>item 3</li> 2011 </ul> 2012 2013 Trailing whitespace does not get stripped, and lines which contain more 2014 than one template tag will not have their leading whitespace trimmed. 2015 1959 2016 .. setting:: TEST_RUNNER 1960 2017 1961 2018 TEST_RUNNER -
tests/regressiontests/templates/tests.py
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 35d0122..a69fa23 100644
a b class Templates(unittest.TestCase): 387 387 except TemplateSyntaxError as e: 388 388 self.assertEqual(e.args[0], "Invalid block tag: 'endblock', expected 'elif', 'else' or 'endif'") 389 389 390 def test_insignificant_whitespace(self): 391 whitespace_tests = { 392 # The test tuple contents is (template_content, context_args, stripped_output, unstripped_output) 393 # Tags on their own line should collapse the newline before them 394 # Trailing newline is not removed 395 # Leading whitespace before single template tag 396 'insignificant-whitespace01': ('\n {% templatetag openblock %}\n', {}, '{%\n', 397 '\n {%\n'), 398 'insignificant-whitespace02': ('\n{% templatetag openblock %}\n', {}, '{%\n', 399 '\n{%\n'), 400 'insignificant-whitespace03': ('{% templatetag openblock %}\n', {}, '{%\n', 401 '{%\n'), 402 'insignificant-whitespace04': ('\n\t \t {% templatetag openblock %}\n', {}, '{%\n', 403 '\n\t \t {%\n'), 404 # Leading whitespace with text before single template tag 405 'insignificant-whitespace05': ('\n some\ttext {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 406 '\n some\ttext {%\n'), 407 # Leading line with text before single template tag 408 'insignificant-whitespace06': ('\n some\ttext\n {% templatetag openblock %}\n', {}, '\n some\ttext{%\n', 409 '\n some\ttext\n {%\n'), 410 'insignificant-whitespace07': ('\n some\ttext \n \t {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 411 '\n some\ttext \n \t {%\n'), 412 # whitespace leading /before/ the newline is not stripped. 413 'insignificant-whitespace08': ('\n some\ttext \t \n {% templatetag openblock %}\n', {}, '\n some\ttext \t {%\n', 414 '\n some\ttext \t \n {%\n'), 415 # Multiple text lines before tag 416 'insignificant-whitespace09': ('\n some\ntext \t \n {% templatetag openblock %}\n', {}, '\n some\ntext \t {%\n', 417 '\n some\ntext \t \n {%\n'), 418 'insignificant-whitespace10': ('\n some \t \n \t text \t \n {% templatetag openblock %}\n', {}, '\n some \t \n \t text \t {%\n', 419 '\n some \t \n \t text \t \n {%\n'), 420 # Leading whitespace before tag, some text after 421 'insignificant-whitespace11': ('\n \t {% templatetag openblock %} some text\n', {}, '\n \t {% some text\n', 422 '\n \t {% some text\n'), 423 # Leading whitespace before tag, some text with trailing whitespace after 424 'insignificant-whitespace12': ('\n \t {% templatetag openblock %} some text \t \n', {}, '\n \t {% some text \t \n', 425 '\n \t {% some text \t \n'), 426 # Whitespace after tag is not removed 427 'insignificant-whitespace13': ('\n \t {% templatetag openblock %} \t \n \t some text \t \n', {}, '{% \t \n \t some text \t \n', 428 '\n \t {% \t \n \t some text \t \n'), 429 # Multiple lines of leading whitespace. Only one leading newline is removed 430 'insignificant-whitespace14': ('\n\n\n{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 431 '\n\n\n{%\n some text\n'), 432 # Trailing whitespace after tag 433 'insignificant-whitespace15': ('\n\n\n{% templatetag openblock %}\t \t \t\n some text\n', {}, '\n\n{%\t \t \t\n some text\n', 434 '\n\n\n{%\t \t \t\n some text\n'), 435 # Removable newline followed by leading whitespace 436 'insignificant-whitespace16': ('\n\n\n\t \t \t{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 437 '\n\n\n\t \t \t{%\n some text\n'), 438 # Removable leading whitespace and trailing whitespace 439 'insignificant-whitespace17': ('\n\n\n\t \t \t{% templatetag openblock %}\t \t \t\n some text\n', {}, '\n\n{%\t \t \t\n some text\n', 440 '\n\n\n\t \t \t{%\t \t \t\n some text\n'), 441 # Multiple lines of trailing whitespace. No trailing newline is removed. 442 'insignificant-whitespace18': ('\n{% templatetag openblock %}\n\n\n some text\n', {}, '{%\n\n\n some text\n', 443 '\n{%\n\n\n some text\n'), 444 'insignificant-whitespace19': ('\n{% templatetag openblock %}\t \n\n\n some text\n', {}, '{%\t \n\n\n some text\n', 445 '\n{%\t \n\n\n some text\n'), 446 # Consecutive trimmed lines with tags strips one newline each 447 'insignificant-whitespace20': ( 448 '\n{% templatetag openblock %}\n{% templatetag openblock %}\n{% templatetag openblock %}\n some text\n' 449 , {}, '{%{%{%\n some text\n', 450 '\n{%\n{%\n{%\n some text\n'), 451 # Consecutive trimmed lines with tags strips one newline each. Intermediate newlines are preserved 452 'insignificant-whitespace21': ( 453 '\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n some text\n' 454 , {}, '\n{%\n{%\n{%\n\n some text\n', 455 '\n\n{%\n\n{%\n\n{%\n\n some text\n'), 456 # Consecutive trimmed lines with tags strips one newline each. Leading whitespace is stripped but trailing is not 457 'insignificant-whitespace22': ( 458 '\n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n some text\n' 459 , {}, '\n{%\t \n{%\t \n{%\t \n some text\n', 460 '\n\n\t {%\t \n\n\t {%\t \n\n\t {%\t \n some text\n'), 461 # Consecutive trimmed lines with tags strips one newline each. Intermediate whitespace is stripped 462 'insignificant-whitespace23': ( 463 '\n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n some text\n' 464 , {}, '{%\t {%\t {%\t \n some text\n', 465 '\n\t {%\t \n\t {%\t \n\t {%\t \n some text\n'), 466 # Intermediate whitespace on one line is preserved 467 # Consecutive tags on one line do not have intermediate whitespace or leading whitespace stripped 468 'insignificant-whitespace24': ( 469 '\n\t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \n some text\n' 470 , {}, '\n\t {%\t \t {%\t \t {%\t \n some text\n', 471 '\n\t {%\t \t {%\t \t {%\t \n some text\n'), 472 # Still, only one leading newline is removed. 473 'insignificant-whitespace25': ( 474 '\n\n {% templatetag openblock %}\n \t {% templatetag openblock %}\n \t {% templatetag openblock %}\n some text\n' 475 , {}, '\n{%{%{%\n some text\n', 476 '\n\n {%\n \t {%\n \t {%\n some text\n'), 477 # Lines with {# comments #} have the same stripping behavior 478 'insignificant-whitespace26': ( 479 '\n\n {% templatetag openblock %}\n \t {# some comment #}\n some text\n' 480 , {}, '\n{%\n some text\n', 481 '\n\n {%\n \t \n some text\n'), 482 # Only {# comments #} 483 'insignificant-whitespace27': ( 484 '\n\n {# a comment #}\n \t {# some comment #}\n some text\n' 485 , {}, '\n\n some text\n', 486 '\n\n \n \t \n some text\n'), 487 # Consecutive newlines with tags and comments 488 'insignificant-whitespace28': ( 489 '\n\t {% templatetag openblock %}\t \n\t {# some comment #}\t \n\t {% templatetag openblock %}\t \n some text\n' 490 , {}, '{%\t \t {%\t \n some text\n', 491 '\n\t {%\t \n\t \t \n\t {%\t \n some text\n'), 492 493 # Lines with only {{ values }} have the same stripping behavior 494 'insignificant-whitespace29': ( 495 '\n {% templatetag openblock %}\t\n \t {{ spam }}\t \n \t {% templatetag openblock %}\t \n some text\n' 496 , {"spam" : "ham"}, '{%\tham\t {%\t \n some text\n', 497 '\n {%\t\n \t ham\t \n \t {%\t \n some text\n'), 498 'insignificant-whitespace30': ( 499 '\n\n {% templatetag openblock %}\t\n\n \t {{ spam }}\t \n\n \t {% templatetag openblock %}\t \n some text\n' 500 , {"spam" : "ham"}, '\n{%\t\nham\t \n{%\t \n some text\n', 501 '\n\n {%\t\n\n \t ham\t \n\n \t {%\t \n some text\n'), 502 ## Leading whitespace not stripped when followed by anything. See insignificant-whitespace24 503 'insignificant-whitespace31': ( 504 '\n {% templatetag openblock %}\t \t {{ spam }}\t \t {% templatetag openblock %}\t \n some text\n' 505 , {"spam" : "ham"}, '\n {%\t \t ham\t \t {%\t \n some text\n', 506 '\n {%\t \t ham\t \t {%\t \n some text\n'), 507 # {{ value }} {% tag %} {{ value }} this time 508 'insignificant-whitespace32': ( 509 '\n {{ spam }}\t\n \t {% templatetag openblock %}\t \n \t {{ spam }}\t \n some text\n' 510 , {"spam" : "ham"}, 'ham\t{%\t ham\t \n some text\n', 511 '\n ham\t\n \t {%\t \n \t ham\t \n some text\n'), 512 513 # Invalid stuff is still invalid 514 # Newlines inside begin-end tokens, even in {# comments #}, make it not a tag. 515 'insignificant-whitespace33': ( 516 '\n\n {# \n{% templatetag openblock #}\t \n some text\n' 517 , {}, '\n\n {# \n{% templatetag openblock #}\t \n some text\n', 518 '\n\n {# \n{% templatetag openblock #}\t \n some text\n'), 519 # Complete comment matching tags on one line are processed 520 'insignificant-whitespace34': ( 521 '\n\n {# \n{# templatetag openblock #}\t \n some text\n' 522 , {}, '\n\n {# \t \n some text\n', 523 '\n\n {# \n\t \n some text\n'), 524 'insignificant-whitespace35': ( 525 '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n' 526 , {}, '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n', 527 '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n'), 528 'insignificant-whitespace36': ( 529 '\n\n {# \n{{ some comment #}\t \n some text\n' 530 , {}, '\n\n {# \n{{ some comment #}\t \n some text\n', 531 '\n\n {# \n{{ some comment #}\t \n some text\n'), 532 'insignificant-whitespace37': ( 533 '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n' 534 , {}, '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n', 535 '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n'), 536 'insignificant-whitespace38': ( 537 "\n\n {# templatetag openblock #\n}\t \n some text\n" 538 , {}, "\n\n {# templatetag openblock #\n}\t \n some text\n", 539 "\n\n {# templatetag openblock #\n}\t \n some text\n" ), 540 'insignificant-whitespace39': ( 541 "\n\n {% templatetag openblock %\n}\t \n some text\n" 542 , {}, "\n\n {% templatetag openblock %\n}\t \n some text\n", 543 "\n\n {% templatetag openblock %\n}\t \n some text\n" ), 544 'insignificant-whitespace40': ( 545 "\n\n {{ templatetag openblock }\n}\t \n some text\n" 546 , {}, "\n\n {{ templatetag openblock }\n}\t \n some text\n", 547 "\n\n {{ templatetag openblock }\n}\t \n some text\n" ), 548 'insignificant-whitespace41': ( 549 "\n\n {\n# {# templatetag openblock #}\t \n some text\n" 550 , {}, "\n\n {\n# \t \n some text\n", 551 "\n\n {\n# \t \n some text\n"), 552 'insignificant-whitespace42': ( 553 "\n\n {\n {# templatetag openblock #}\t \n some text\n" 554 , {}, "\n\n {\t \n some text\n", 555 "\n\n {\n \t \n some text\n"), 556 'insignificant-whitespace43': ( 557 "\n{{# foo #};{# bar #}\n" 558 , {}, "\n{;\n", 559 "\n{;\n"), 560 } 561 tests = whitespace_tests.items() 562 tests.sort() 563 564 # Register our custom template loader. 565 def test_whitespace_loader(template_name, template_dirs=None): 566 "A custom template loader that loads the unit-test templates." 567 try: 568 return (whitespace_tests[template_name][0] , "test:%s" % template_name) 569 except KeyError: 570 raise template.TemplateDoesNotExist, template_name 571 572 old_template_loaders = loader.template_source_loaders 573 loader.template_source_loaders = [test_whitespace_loader] 574 575 failures = [] 576 577 old_strip_leading_whitespace = settings.TEMPLATE_STRIP_LEADING_WHITESPACE 578 579 for name, vals in tests: 580 for strip_leading_whitespace in (True, False): 581 settings.TEMPLATE_STRIP_LEADING_WHITESPACE = strip_leading_whitespace 582 test_template = loader.get_template(name) 583 result = vals[2] if strip_leading_whitespace else vals[3] 584 output = self.render(test_template, vals) 585 586 if output != result: 587 failures.append("Whitespace test: %s -- FAILED. Expected %r, got %r" % (name, result, output)) 588 589 loader.template_source_loaders = old_template_loaders 590 settings.TEMPLATE_STRIP_LEADING_WHITESPACE = old_strip_leading_whitespace 591 592 self.assertEqual(failures, [], "Tests failed:\n%s\n%s" % 593 ('-'*70, ("\n%s\n" % ('-'*70)).join(failures))) 594 390 595 def test_templates(self): 391 596 template_tests = self.get_template_tests() 392 597 filter_tests = filters.get_filter_tests()