Ticket #2594: 0001-Commiting-whitespace-patch-from-django-ticket-2594.patch
File 0001-Commiting-whitespace-patch-from-django-ticket-2594.patch, 53.0 KB (added by , 14 years ago) |
---|
-
django-apps/Django-1.3-beta-1/AUTHORS
From f4c8008acc2bea7c5b415a60b5d5b255cc1e5f51 Mon Sep 17 00:00:00 2001 From: Fahrzin Hemmati <fahhem@fahhem.com> Date: Mon, 21 Feb 2011 16:57:24 -0800 Subject: [PATCH 1/2] Commiting whitespace patch from django ticket #2594 I don't like the output without this. Needs a setting set though http://code.djangoproject.com/ticket/2594 --- django-apps/Django-1.3-beta-1/AUTHORS | 1 + .../django/conf/global_settings.py | 1 + .../Django-1.3-beta-1/django/template/base.py | 78 +++- .../Django-1.3-beta-1/django/template/debug.py | 5 +- .../django/template/defaulttags.py | 3 +- .../Django-1.3-beta-1/docs/ref/settings.txt | 55 +++ .../tests/regressiontests/templates/tests.py | 205 +++++++++ django-apps/Django-1.3-beta-1/whitespace.patch | 449 ++++++++++++++++++++ 8 files changed, 783 insertions(+), 14 deletions(-) create mode 100644 django-apps/Django-1.3-beta-1/whitespace.patch diff --git a/django-apps/Django-1.3-beta-1/AUTHORS b/django-apps/Django-1.3-beta-1/AUTHORS index d7601ca..bf73daa 100644
a b answer newbie questions, and generally made Django that much better: 261 261 Ian G. Kelly <ian.g.kelly@gmail.com> 262 262 Niall Kelly <duke.sam.vimes@gmail.com> 263 263 Ryan Kelly <ryan@rfk.id.au> 264 Stephen Kelly <steveire@gmail.com> 264 265 Thomas Kerpe <thomas@kerpe.net> 265 266 Wiley Kestner <wiley.kestner@gmail.com> 266 267 Ossama M. Khayat <okhayat@yahoo.com> -
django-apps/Django-1.3-beta-1/django/conf/global_settings.py
diff --git a/django-apps/Django-1.3-beta-1/django/conf/global_settings.py b/django-apps/Django-1.3-beta-1/django/conf/global_settings.py index 0017f46..e5c0dbf 100644
a b gettext_noop = lambda s: s 11 11 12 12 DEBUG = False 13 13 TEMPLATE_DEBUG = False 14 TEMPLATE_STRIP_LEADING_WHITESPACE = False 14 15 15 16 # Whether the framework should propagate raw exceptions rather than catching 16 17 # them. This is useful under some testing siutations and should never be used -
django-apps/Django-1.3-beta-1/django/template/base.py
diff --git a/django-apps/Django-1.3-beta-1/django/template/base.py b/django-apps/Django-1.3-beta-1/django/template/base.py index 1440869..9211ebf 100644
a b 1 import imp2 1 import re 3 2 from inspect import getargspec 4 3 … … from django.conf import settings 6 5 from django.template.context import Context, RequestContext, ContextPopException 7 6 from django.utils.importlib import import_module 8 7 from django.utils.itercompat import is_iterable 9 from django.utils.functional import curry , Promise8 from django.utils.functional import curry 10 9 from django.utils.text import smart_split, unescape_string_literal, get_text_list 11 10 from django.utils.encoding import smart_unicode, force_unicode, smart_str 12 11 from django.utils.translation import ugettext as _ … … ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01 41 40 # (e.g. strings) 42 41 UNKNOWN_SOURCE = '<unknown source>' 43 42 43 44 44 # match a variable or block tag and capture the entire tag, including start/end delimiters 45 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 46 re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), 47 re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) 45 tag_re = re.compile(''' 46 ( 47 %(BLOCK_TAG_START)s.*?%(BLOCK_TAG_END)s # block start + inner + end 48 | %(VARIABLE_TAG_START)s.*?%(VARIABLE_TAG_END)s # variable start + inner + end 49 | %(COMMENT_TAG_START)s.*?%(COMMENT_TAG_END)s # comment start + inner + end 50 ) 51 ''' % { 52 'BLOCK_TAG_START': re.escape(BLOCK_TAG_START), 53 'BLOCK_TAG_END': re.escape(BLOCK_TAG_END), 54 'VARIABLE_TAG_START': re.escape(VARIABLE_TAG_START), 55 'VARIABLE_TAG_END': re.escape(VARIABLE_TAG_END), 56 'COMMENT_TAG_START': re.escape(COMMENT_TAG_START), 57 'COMMENT_TAG_END': re.escape(COMMENT_TAG_END), 58 }, re.VERBOSE) 59 60 strip_leading_whitespace_tag_re = re.compile(''' 61 ( 62 [\n\r]{1} # 1 vertical white space (the one starting this line) 63 [ \t]*? # any number of tabs or spaces 64 (?: # group but don't match 65 %(BLOCK_TAG_START)s 66 [^\n\r%(BLOCK_TAG_START)s%(BLOCK_TAG_END)s]*? # anything *not* vertical whitespace or 67 %(BLOCK_TAG_END)s # opening/closing block tag 68 | 69 %(COMMENT_TAG_START)s 70 [^\n\r%(COMMENT_TAG_START)s%(COMMENT_TAG_END)s]*? # anything *not* vertical whitespace or 71 %(COMMENT_TAG_END)s # opening/closing comment tag 72 | 73 %(VARIABLE_TAG_START)s 74 [^\n\r%(VARIABLE_TAG_START)s%(VARIABLE_TAG_END)s]*? # anything *not* vertical whitespace or 75 %(VARIABLE_TAG_END)s # opening/closing variable tag 76 ) 77 (?= # Match this only if the previous matched 78 [ \t]*? 79 [\n\r]+ 80 )| 81 %(BLOCK_TAG_START)s.*?%(BLOCK_TAG_END)s # block start + inner + end 82 | %(VARIABLE_TAG_START)s.*?%(VARIABLE_TAG_END)s # variable start + inner + end 83 | %(COMMENT_TAG_START)s.*?%(COMMENT_TAG_END)s # comment start + inner + end 84 )''' % { 85 'BLOCK_TAG_START': re.escape(BLOCK_TAG_START), 86 'BLOCK_TAG_END': re.escape(BLOCK_TAG_END), 87 'VARIABLE_TAG_START': re.escape(VARIABLE_TAG_START), 88 'VARIABLE_TAG_END': re.escape(VARIABLE_TAG_END), 89 'COMMENT_TAG_START': re.escape(COMMENT_TAG_START), 90 'COMMENT_TAG_END': re.escape(COMMENT_TAG_END), 91 }, re.VERBOSE) 92 93 # find the command within a block tag 94 block_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END))) 95 comment_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))) 96 variable_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END))) 48 97 49 98 # global dictionary of libraries that have been loaded using get_library 50 99 libraries = {} … … class Lexer(object): 171 220 "Return a list of tokens from a given template_string." 172 221 in_tag = False 173 222 result = [] 174 for bit in tag_re.split(self.template_string): 223 tag_splitter = strip_leading_whitespace_tag_re if settings.TEMPLATE_STRIP_LEADING_WHITESPACE else tag_re 224 for bit in tag_splitter.split(self.template_string): 175 225 if bit: 176 226 result.append(self.create_token(bit, in_tag)) 177 227 in_tag = not in_tag … … class Lexer(object): 184 234 otherwise it should be treated as a literal string. 185 235 """ 186 236 if in_tag: 187 if token_string.startswith(VARIABLE_TAG_START): 188 token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip()) 189 elif token_string.startswith(BLOCK_TAG_START): 190 token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) 191 elif token_string.startswith(COMMENT_TAG_START): 237 if token_string.lstrip().startswith(VARIABLE_TAG_START): 238 token_struct = variable_command_re.search(token_string) 239 token_string = token_struct.group('token_string') 240 token = Token(TOKEN_VAR, token_string.strip()) 241 elif token_string.lstrip().startswith(BLOCK_TAG_START): 242 token_struct = block_command_re.search(token_string) 243 token_string = token_struct.group('token_string') 244 token = Token(TOKEN_BLOCK, token_string.strip()) 245 elif token_string.lstrip().startswith(COMMENT_TAG_START): 192 246 content = '' 247 token_struct = comment_command_re.search(token_string) 248 token_string = token_struct.group('token_string') 193 249 if token_string.find(TRANSLATOR_COMMENT_MARK): 194 250 content = token_string[len(COMMENT_TAG_START):-len(COMMENT_TAG_END)].strip() 195 251 token = Token(TOKEN_COMMENT, content) -
django-apps/Django-1.3-beta-1/django/template/debug.py
diff --git a/django-apps/Django-1.3-beta-1/django/template/debug.py b/django-apps/Django-1.3-beta-1/django/template/debug.py index a9e3c4f..cd42236 100644
a b 1 1 from django.conf import settings 2 from django.template.base import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError2 from django.template.base import Lexer, Parser, tag_re, strip_leading_whitespace_tag_re, NodeList, VariableNode, TemplateSyntaxError 3 3 from django.utils.encoding import force_unicode 4 4 from django.utils.html import escape 5 5 from django.utils.safestring import SafeData, EscapeData … … class DebugLexer(Lexer): 12 12 def tokenize(self): 13 13 "Return a list of tokens from a given template_string" 14 14 result, upto = [], 0 15 for match in tag_re.finditer(self.template_string): 15 tag_splitter = strip_leading_whitespace_tag_re if settings.TEMPLATE_STRIP_LEADING_WHITESPACE else tag_re 16 for match in tag_splitter.finditer(self.template_string): 16 17 start, end = match.span() 17 18 if start > upto: 18 19 result.append(self.create_token(self.template_string[upto:start], (upto, start), False)) -
django-apps/Django-1.3-beta-1/django/template/defaulttags.py
diff --git a/django-apps/Django-1.3-beta-1/django/template/defaulttags.py b/django-apps/Django-1.3-beta-1/django/template/defaulttags.py index 0662b5f..13d4759 100644
a b from django.template.smartif import IfParser, Literal 11 11 from django.conf import settings 12 12 from django.utils.encoding import smart_str, smart_unicode 13 13 from django.utils.safestring import mark_safe 14 from django.utils.text import smart_split 14 15 15 16 register = Library() 16 17 # Regex for token keyword arguments … … def token_kwargs(bits, parser, support_legacy=False): 47 48 48 49 kwargs = {} 49 50 while bits: 50 if kwarg_format: 51 if kwarg_format: 51 52 match = kwarg_re.match(bits[0]) 52 53 if not match or not match.group(1): 53 54 return kwargs -
django-apps/Django-1.3-beta-1/docs/ref/settings.txt
diff --git a/django-apps/Django-1.3-beta-1/docs/ref/settings.txt b/django-apps/Django-1.3-beta-1/docs/ref/settings.txt index e358c42..7d9a683 100644
a b misspelled) variables. See :ref:`invalid-template-variables`.. 1788 1788 1789 1789 .. setting:: TEST_RUNNER 1790 1790 1791 TEMPLATE_STRIP_LEADING_WHITESPACE 1792 --------------------------------- 1793 1794 .. versionadded:: 1.3 1795 1796 Default: ``False`` 1797 1798 Whether to strip leading whitespace on template lines containing only template 1799 syntax. 1800 1801 This template code:: 1802 <h1>My list</h1> 1803 1804 {# This is a comment #} 1805 {# It describes the loop below #} 1806 {# Each line appears in the output as an empty line #} 1807 <ul> 1808 {% for item in items %} 1809 {# Description of a list item #} 1810 <li>{{ item }}</li> 1811 {% endfor %} 1812 </ul> 1813 1814 Normally evaluates to:: 1815 <h1>My list</h1> 1816 1817 1818 1819 1820 <ul> 1821 1822 1823 <li>item 1</li> 1824 1825 <li>item 2</li> 1826 1827 <li>item 3</li> 1828 1829 </ul> 1830 1831 However, if TEMPLATE_STRIP_LEADING_WHITESPACE is set to True, lines which 1832 contain only one template tag, variable or comment no not cause a newline 1833 to be inserted in the output:: 1834 1835 <h1>My list</h1> 1836 1837 <ul> 1838 <li>item 1</li> 1839 <li>item 2</li> 1840 <li>item 3</li> 1841 </ul> 1842 1843 Trailing whitespace does not get stripped, and lines which contain more 1844 than one template tag will not have their leading whitespace trimmed. 1845 1791 1846 TEST_RUNNER 1792 1847 ----------- 1793 1848 -
django-apps/Django-1.3-beta-1/tests/regressiontests/templates/tests.py
diff --git a/django-apps/Django-1.3-beta-1/tests/regressiontests/templates/tests.py b/django-apps/Django-1.3-beta-1/tests/regressiontests/templates/tests.py index 99776e6..fb176fe 100644
a b class Templates(unittest.TestCase): 340 340 except TemplateSyntaxError, e: 341 341 self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'") 342 342 343 def test_insignificant_whitespace(self): 344 whitespace_tests = { 345 # The test tuple contents is (template_content, context_args, stripped_output, unstripped_output) 346 # Tags on their own line should collapse the newline before them 347 # Trailing newline is not removed 348 # Leading whitespace before single template tag 349 'insignificant-whitespace01': ('\n {% templatetag openblock %}\n', {}, '{%\n', 350 '\n {%\n'), 351 'insignificant-whitespace02': ('\n{% templatetag openblock %}\n', {}, '{%\n', 352 '\n{%\n'), 353 'insignificant-whitespace03': ('{% templatetag openblock %}\n', {}, '{%\n', 354 '{%\n'), 355 'insignificant-whitespace04': ('\n\t \t {% templatetag openblock %}\n', {}, '{%\n', 356 '\n\t \t {%\n'), 357 # Leading whitespace with text before single template tag 358 'insignificant-whitespace05': ('\n some\ttext {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 359 '\n some\ttext {%\n'), 360 # Leading line with text before single template tag 361 'insignificant-whitespace06': ('\n some\ttext\n {% templatetag openblock %}\n', {}, '\n some\ttext{%\n', 362 '\n some\ttext\n {%\n'), 363 'insignificant-whitespace07': ('\n some\ttext \n \t {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 364 '\n some\ttext \n \t {%\n'), 365 # whitespace leading /before/ the newline is not stripped. 366 'insignificant-whitespace08': ('\n some\ttext \t \n {% templatetag openblock %}\n', {}, '\n some\ttext \t {%\n', 367 '\n some\ttext \t \n {%\n'), 368 # Multiple text lines before tag 369 'insignificant-whitespace09': ('\n some\ntext \t \n {% templatetag openblock %}\n', {}, '\n some\ntext \t {%\n', 370 '\n some\ntext \t \n {%\n'), 371 'insignificant-whitespace10': ('\n some \t \n \t text \t \n {% templatetag openblock %}\n', {}, '\n some \t \n \t text \t {%\n', 372 '\n some \t \n \t text \t \n {%\n'), 373 # Leading whitespace before tag, some text after 374 'insignificant-whitespace11': ('\n \t {% templatetag openblock %} some text\n', {}, '\n \t {% some text\n', 375 '\n \t {% some text\n'), 376 # Leading whitespace before tag, some text with trailing whitespace after 377 'insignificant-whitespace12': ('\n \t {% templatetag openblock %} some text \t \n', {}, '\n \t {% some text \t \n', 378 '\n \t {% some text \t \n'), 379 # Whitespace after tag is not removed 380 'insignificant-whitespace13': ('\n \t {% templatetag openblock %} \t \n \t some text \t \n', {}, '{% \t \n \t some text \t \n', 381 '\n \t {% \t \n \t some text \t \n'), 382 # Multiple lines of leading whitespace. Only one leading newline is removed 383 'insignificant-whitespace14': ('\n\n\n{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 384 '\n\n\n{%\n some text\n'), 385 # Trailing whitespace after tag 386 'insignificant-whitespace15': ('\n\n\n{% templatetag openblock %}\t \t \t\n some text\n', {}, '\n\n{%\t \t \t\n some text\n', 387 '\n\n\n{%\t \t \t\n some text\n'), 388 # Removable newline followed by leading whitespace 389 'insignificant-whitespace16': ('\n\n\n\t \t \t{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 390 '\n\n\n\t \t \t{%\n some text\n'), 391 # Removable leading whitespace and trailing whitespace 392 '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', 393 '\n\n\n\t \t \t{%\t \t \t\n some text\n'), 394 # Multiple lines of trailing whitespace. No trailing newline is removed. 395 'insignificant-whitespace18': ('\n{% templatetag openblock %}\n\n\n some text\n', {}, '{%\n\n\n some text\n', 396 '\n{%\n\n\n some text\n'), 397 'insignificant-whitespace19': ('\n{% templatetag openblock %}\t \n\n\n some text\n', {}, '{%\t \n\n\n some text\n', 398 '\n{%\t \n\n\n some text\n'), 399 # Consecutive trimmed lines with tags strips one newline each 400 'insignificant-whitespace20': ( 401 '\n{% templatetag openblock %}\n{% templatetag openblock %}\n{% templatetag openblock %}\n some text\n' 402 , {}, '{%{%{%\n some text\n', 403 '\n{%\n{%\n{%\n some text\n'), 404 # Consecutive trimmed lines with tags strips one newline each. Intermediate newlines are preserved 405 'insignificant-whitespace21': ( 406 '\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n some text\n' 407 , {}, '\n{%\n{%\n{%\n\n some text\n', 408 '\n\n{%\n\n{%\n\n{%\n\n some text\n'), 409 # Consecutive trimmed lines with tags strips one newline each. Leading whitespace is stripped but trailing is not 410 'insignificant-whitespace22': ( 411 '\n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n some text\n' 412 , {}, '\n{%\t \n{%\t \n{%\t \n some text\n', 413 '\n\n\t {%\t \n\n\t {%\t \n\n\t {%\t \n some text\n'), 414 # Consecutive trimmed lines with tags strips one newline each. Intermediate whitespace is stripped 415 'insignificant-whitespace23': ( 416 '\n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n some text\n' 417 , {}, '{%\t {%\t {%\t \n some text\n', 418 '\n\t {%\t \n\t {%\t \n\t {%\t \n some text\n'), 419 # Intermediate whitespace on one line is preserved 420 # Consecutive tags on one line do not have intermediate whitespace or leading whitespace stripped 421 'insignificant-whitespace24': ( 422 '\n\t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \n some text\n' 423 , {}, '\n\t {%\t \t {%\t \t {%\t \n some text\n', 424 '\n\t {%\t \t {%\t \t {%\t \n some text\n'), 425 # Still, only one leading newline is removed. 426 'insignificant-whitespace25': ( 427 '\n\n {% templatetag openblock %}\n \t {% templatetag openblock %}\n \t {% templatetag openblock %}\n some text\n' 428 , {}, '\n{%{%{%\n some text\n', 429 '\n\n {%\n \t {%\n \t {%\n some text\n'), 430 # Lines with {# comments #} have the same stripping behavior 431 'insignificant-whitespace26': ( 432 '\n\n {% templatetag openblock %}\n \t {# some comment #}\n some text\n' 433 , {}, '\n{%\n some text\n', 434 '\n\n {%\n \t \n some text\n'), 435 # Only {# comments #} 436 'insignificant-whitespace27': ( 437 '\n\n {# a comment #}\n \t {# some comment #}\n some text\n' 438 , {}, '\n\n some text\n', 439 '\n\n \n \t \n some text\n'), 440 # Consecutive newlines with tags and comments 441 'insignificant-whitespace28': ( 442 '\n\t {% templatetag openblock %}\t \n\t {# some comment #}\t \n\t {% templatetag openblock %}\t \n some text\n' 443 , {}, '{%\t \t {%\t \n some text\n', 444 '\n\t {%\t \n\t \t \n\t {%\t \n some text\n'), 445 446 # Lines with only {{ values }} have the same stripping behavior 447 'insignificant-whitespace29': ( 448 '\n {% templatetag openblock %}\t\n \t {{ spam }}\t \n \t {% templatetag openblock %}\t \n some text\n' 449 , {"spam" : "ham"}, '{%\tham\t {%\t \n some text\n', 450 '\n {%\t\n \t ham\t \n \t {%\t \n some text\n'), 451 'insignificant-whitespace30': ( 452 '\n\n {% templatetag openblock %}\t\n\n \t {{ spam }}\t \n\n \t {% templatetag openblock %}\t \n some text\n' 453 , {"spam" : "ham"}, '\n{%\t\nham\t \n{%\t \n some text\n', 454 '\n\n {%\t\n\n \t ham\t \n\n \t {%\t \n some text\n'), 455 ## Leading whitespace not stripped when followed by anything. See insignificant-whitespace24 456 'insignificant-whitespace31': ( 457 '\n {% templatetag openblock %}\t \t {{ spam }}\t \t {% templatetag openblock %}\t \n some text\n' 458 , {"spam" : "ham"}, '\n {%\t \t ham\t \t {%\t \n some text\n', 459 '\n {%\t \t ham\t \t {%\t \n some text\n'), 460 # {{ value }} {% tag %} {{ value }} this time 461 'insignificant-whitespace32': ( 462 '\n {{ spam }}\t\n \t {% templatetag openblock %}\t \n \t {{ spam }}\t \n some text\n' 463 , {"spam" : "ham"}, 'ham\t{%\t ham\t \n some text\n', 464 '\n ham\t\n \t {%\t \n \t ham\t \n some text\n'), 465 466 # Invalid stuff is still invalid 467 # Newlines inside begin-end tokens, even in {# comments #}, make it not a tag. 468 'insignificant-whitespace33': ( 469 '\n\n {# \n{% templatetag openblock #}\t \n some text\n' 470 , {}, '\n\n {# \n{% templatetag openblock #}\t \n some text\n', 471 '\n\n {# \n{% templatetag openblock #}\t \n some text\n'), 472 # Complete comment matching tags on one line are processed 473 'insignificant-whitespace34': ( 474 '\n\n {# \n{# templatetag openblock #}\t \n some text\n' 475 , {}, '\n\n {# \t \n some text\n', 476 '\n\n {# \n\t \n some text\n'), 477 'insignificant-whitespace35': ( 478 '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n' 479 , {}, '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n', 480 '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n'), 481 'insignificant-whitespace36': ( 482 '\n\n {# \n{{ some comment #}\t \n some text\n' 483 , {}, '\n\n {# \n{{ some comment #}\t \n some text\n', 484 '\n\n {# \n{{ some comment #}\t \n some text\n'), 485 'insignificant-whitespace37': ( 486 '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n' 487 , {}, '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n', 488 '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n'), 489 'insignificant-whitespace38': ( 490 "\n\n {# templatetag openblock #\n}\t \n some text\n" 491 , {}, "\n\n {# templatetag openblock #\n}\t \n some text\n", 492 "\n\n {# templatetag openblock #\n}\t \n some text\n" ), 493 'insignificant-whitespace39': ( 494 "\n\n {% templatetag openblock %\n}\t \n some text\n" 495 , {}, "\n\n {% templatetag openblock %\n}\t \n some text\n", 496 "\n\n {% templatetag openblock %\n}\t \n some text\n" ), 497 'insignificant-whitespace40': ( 498 "\n\n {{ templatetag openblock }\n}\t \n some text\n" 499 , {}, "\n\n {{ templatetag openblock }\n}\t \n some text\n", 500 "\n\n {{ templatetag openblock }\n}\t \n some text\n" ), 501 'insignificant-whitespace41': ( 502 "\n\n {\n# {# templatetag openblock #}\t \n some text\n" 503 , {}, "\n\n {\n# \t \n some text\n", 504 "\n\n {\n# \t \n some text\n"), 505 'insignificant-whitespace42': ( 506 "\n\n {\n {# templatetag openblock #}\t \n some text\n" 507 , {}, "\n\n {\t \n some text\n", 508 "\n\n {\n \t \n some text\n"), 509 'insignificant-whitespace43': ( 510 "\n{{# foo #};{# bar #}\n" 511 , {}, "\n{;\n", 512 "\n{;\n"), 513 } 514 tests = whitespace_tests.items() 515 tests.sort() 516 517 # Register our custom template loader. 518 def test_whitespace_loader(template_name, template_dirs=None): 519 "A custom template loader that loads the unit-test templates." 520 try: 521 return (whitespace_tests[template_name][0] , "test:%s" % template_name) 522 except KeyError: 523 raise template.TemplateDoesNotExist, template_name 524 525 old_template_loaders = loader.template_source_loaders 526 loader.template_source_loaders = [test_whitespace_loader] 527 528 failures = [] 529 530 old_strip_leading_whitespace = settings.TEMPLATE_STRIP_LEADING_WHITESPACE 531 532 for name, vals in tests: 533 for strip_leading_whitespace in (True, False): 534 settings.TEMPLATE_STRIP_LEADING_WHITESPACE = strip_leading_whitespace 535 test_template = loader.get_template(name) 536 result = vals[2] if strip_leading_whitespace else vals[3] 537 output = self.render(test_template, vals) 538 539 if output != result: 540 failures.append("Whitespace test: %s -- FAILED. Expected %r, got %r" % (name, result, output)) 541 542 loader.template_source_loaders = old_template_loaders 543 settings.TEMPLATE_STRIP_LEADING_WHITESPACE = old_strip_leading_whitespace 544 545 self.assertEqual(failures, [], "Tests failed:\n%s\n%s" % 546 ('-'*70, ("\n%s\n" % ('-'*70)).join(failures))) 547 343 548 def test_templates(self): 344 549 template_tests = self.get_template_tests() 345 550 filter_tests = filters.get_filter_tests() -
new file django-apps/Django-1.3-beta-1/whitespace.patch
diff --git a/django-apps/Django-1.3-beta-1/whitespace.patch b/django-apps/Django-1.3-beta-1/whitespace.patch new file mode 100644 index 0000000..dd3c838
- + 1 commit ffaecbd5cf0387868af908f89e0b6695de755174 2 Author: Stephen Kelly <steveire@gmail.com> 3 Date: Thu Jan 20 18:52:36 2011 +0100 4 5 Handle whitespace better in the template system. 6 7 diff --git a/AUTHORS b/AUTHORS 8 index ffcc34d..32dba07 100644 9 --- a/AUTHORS 10 +++ b/AUTHORS 11 @@ -262,6 +262,7 @@ answer newbie questions, and generally made Django that much better: 12 Ian G. Kelly <ian.g.kelly@gmail.com> 13 Niall Kelly <duke.sam.vimes@gmail.com> 14 Ryan Kelly <ryan@rfk.id.au> 15 + Stephen Kelly <steveire@gmail.com> 16 Thomas Kerpe <thomas@kerpe.net> 17 Wiley Kestner <wiley.kestner@gmail.com> 18 Ossama M. Khayat <okhayat@yahoo.com> 19 diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py 20 index 0017f46..e5c0dbf 100644 21 --- a/django/conf/global_settings.py 22 +++ b/django/conf/global_settings.py 23 @@ -11,6 +11,7 @@ gettext_noop = lambda s: s 24 25 DEBUG = False 26 TEMPLATE_DEBUG = False 27 +TEMPLATE_STRIP_LEADING_WHITESPACE = False 28 29 # Whether the framework should propagate raw exceptions rather than catching 30 # them. This is useful under some testing siutations and should never be used 31 diff --git a/django/template/base.py b/django/template/base.py 32 index 1440869..9211ebf 100644 33 --- a/django/template/base.py 34 +++ b/django/template/base.py 35 @@ -1,4 +1,3 @@ 36 -import imp 37 import re 38 from inspect import getargspec 39 40 @@ -6,7 +5,7 @@ from django.conf import settings 41 from django.template.context import Context, RequestContext, ContextPopException 42 from django.utils.importlib import import_module 43 from django.utils.itercompat import is_iterable 44 -from django.utils.functional import curry, Promise 45 +from django.utils.functional import curry 46 from django.utils.text import smart_split, unescape_string_literal, get_text_list 47 from django.utils.encoding import smart_unicode, force_unicode, smart_str 48 from django.utils.translation import ugettext as _ 49 @@ -41,10 +40,60 @@ ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01 50 # (e.g. strings) 51 UNKNOWN_SOURCE = '<unknown source>' 52 53 + 54 # match a variable or block tag and capture the entire tag, including start/end delimiters 55 -tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 56 - re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), 57 - 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))) 110 111 # global dictionary of libraries that have been loaded using get_library 112 libraries = {} 113 @@ -171,7 +220,8 @@ class Lexer(object): 114 "Return a list of tokens from a given template_string." 115 in_tag = False 116 result = [] 117 - for bit in tag_re.split(self.template_string): 118 + tag_splitter = strip_leading_whitespace_tag_re if settings.TEMPLATE_STRIP_LEADING_WHITESPACE else tag_re 119 + for bit in tag_splitter.split(self.template_string): 120 if bit: 121 result.append(self.create_token(bit, in_tag)) 122 in_tag = not in_tag 123 @@ -184,12 +234,18 @@ class Lexer(object): 124 otherwise it should be treated as a literal string. 125 """ 126 if in_tag: 127 - if token_string.startswith(VARIABLE_TAG_START): 128 - token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip()) 129 - elif token_string.startswith(BLOCK_TAG_START): 130 - token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) 131 - elif token_string.startswith(COMMENT_TAG_START): 132 + if token_string.lstrip().startswith(VARIABLE_TAG_START): 133 + token_struct = variable_command_re.search(token_string) 134 + token_string = token_struct.group('token_string') 135 + token = Token(TOKEN_VAR, token_string.strip()) 136 + elif token_string.lstrip().startswith(BLOCK_TAG_START): 137 + token_struct = block_command_re.search(token_string) 138 + token_string = token_struct.group('token_string') 139 + token = Token(TOKEN_BLOCK, token_string.strip()) 140 + elif token_string.lstrip().startswith(COMMENT_TAG_START): 141 content = '' 142 + token_struct = comment_command_re.search(token_string) 143 + token_string = token_struct.group('token_string') 144 if token_string.find(TRANSLATOR_COMMENT_MARK): 145 content = token_string[len(COMMENT_TAG_START):-len(COMMENT_TAG_END)].strip() 146 token = Token(TOKEN_COMMENT, content) 147 diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py 148 index 0662b5f..13d4759 100644 149 --- a/django/template/defaulttags.py 150 +++ b/django/template/defaulttags.py 151 @@ -11,6 +11,7 @@ from django.template.smartif import IfParser, Literal 152 from django.conf import settings 153 from django.utils.encoding import smart_str, smart_unicode 154 from django.utils.safestring import mark_safe 155 +from django.utils.text import smart_split 156 157 register = Library() 158 # Regex for token keyword arguments 159 @@ -47,7 +48,7 @@ def token_kwargs(bits, parser, support_legacy=False): 160 161 kwargs = {} 162 while bits: 163 - if kwarg_format: 164 + if kwarg_format: 165 match = kwarg_re.match(bits[0]) 166 if not match or not match.group(1): 167 return kwargs 168 diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt 169 index 87a71fe..4addda6 100644 170 --- a/docs/ref/settings.txt 171 +++ b/docs/ref/settings.txt 172 @@ -1755,6 +1755,61 @@ misspelled) variables. See :ref:`invalid-template-variables`.. 173 174 .. setting:: TEST_RUNNER 175 176 +TEMPLATE_STRIP_LEADING_WHITESPACE 177 +--------------------------------- 178 + 179 +.. versionadded:: 1.3 180 + 181 +Default: ``False`` 182 + 183 +Whether to strip leading whitespace on template lines containing only template 184 +syntax. 185 + 186 +This template code:: 187 + <h1>My list</h1> 188 + 189 + {# This is a comment #} 190 + {# It describes the loop below #} 191 + {# Each line appears in the output as an empty line #} 192 + <ul> 193 + {% for item in items %} 194 + {# Description of a list item #} 195 + <li>{{ item }}</li> 196 + {% endfor %} 197 + </ul> 198 + 199 +Normally evaluates to:: 200 + <h1>My list</h1> 201 + 202 + 203 + 204 + 205 + <ul> 206 + 207 + 208 + <li>item 1</li> 209 + 210 + <li>item 2</li> 211 + 212 + <li>item 3</li> 213 + 214 + </ul> 215 + 216 +However, if TEMPLATE_STRIP_LEADING_WHITESPACE is set to True, lines which 217 +contain only one template tag, variable or comment no not cause a newline 218 +to be inserted in the output:: 219 + 220 + <h1>My list</h1> 221 + 222 + <ul> 223 + <li>item 1</li> 224 + <li>item 2</li> 225 + <li>item 3</li> 226 + </ul> 227 + 228 +Trailing whitespace does not get stripped, and lines which contain more 229 +than one template tag will not have their leading whitespace trimmed. 230 + 231 TEST_RUNNER 232 ----------- 233 234 diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py 235 index 99776e6..fb176fe 100644 236 --- a/tests/regressiontests/templates/tests.py 237 +++ b/tests/regressiontests/templates/tests.py 238 @@ -340,6 +340,211 @@ class Templates(unittest.TestCase): 239 except TemplateSyntaxError, e: 240 self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'") 241 242 + def test_insignificant_whitespace(self): 243 + whitespace_tests = { 244 + # The test tuple contents is (template_content, context_args, stripped_output, unstripped_output) 245 + # Tags on their own line should collapse the newline before them 246 + # Trailing newline is not removed 247 + # Leading whitespace before single template tag 248 + 'insignificant-whitespace01': ('\n {% templatetag openblock %}\n', {}, '{%\n', 249 + '\n {%\n'), 250 + 'insignificant-whitespace02': ('\n{% templatetag openblock %}\n', {}, '{%\n', 251 + '\n{%\n'), 252 + 'insignificant-whitespace03': ('{% templatetag openblock %}\n', {}, '{%\n', 253 + '{%\n'), 254 + 'insignificant-whitespace04': ('\n\t \t {% templatetag openblock %}\n', {}, '{%\n', 255 + '\n\t \t {%\n'), 256 + # Leading whitespace with text before single template tag 257 + 'insignificant-whitespace05': ('\n some\ttext {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 258 + '\n some\ttext {%\n'), 259 + # Leading line with text before single template tag 260 + 'insignificant-whitespace06': ('\n some\ttext\n {% templatetag openblock %}\n', {}, '\n some\ttext{%\n', 261 + '\n some\ttext\n {%\n'), 262 + 'insignificant-whitespace07': ('\n some\ttext \n \t {% templatetag openblock %}\n', {}, '\n some\ttext {%\n', 263 + '\n some\ttext \n \t {%\n'), 264 + # whitespace leading /before/ the newline is not stripped. 265 + 'insignificant-whitespace08': ('\n some\ttext \t \n {% templatetag openblock %}\n', {}, '\n some\ttext \t {%\n', 266 + '\n some\ttext \t \n {%\n'), 267 + # Multiple text lines before tag 268 + 'insignificant-whitespace09': ('\n some\ntext \t \n {% templatetag openblock %}\n', {}, '\n some\ntext \t {%\n', 269 + '\n some\ntext \t \n {%\n'), 270 + 'insignificant-whitespace10': ('\n some \t \n \t text \t \n {% templatetag openblock %}\n', {}, '\n some \t \n \t text \t {%\n', 271 + '\n some \t \n \t text \t \n {%\n'), 272 + # Leading whitespace before tag, some text after 273 + 'insignificant-whitespace11': ('\n \t {% templatetag openblock %} some text\n', {}, '\n \t {% some text\n', 274 + '\n \t {% some text\n'), 275 + # Leading whitespace before tag, some text with trailing whitespace after 276 + 'insignificant-whitespace12': ('\n \t {% templatetag openblock %} some text \t \n', {}, '\n \t {% some text \t \n', 277 + '\n \t {% some text \t \n'), 278 + # Whitespace after tag is not removed 279 + 'insignificant-whitespace13': ('\n \t {% templatetag openblock %} \t \n \t some text \t \n', {}, '{% \t \n \t some text \t \n', 280 + '\n \t {% \t \n \t some text \t \n'), 281 + # Multiple lines of leading whitespace. Only one leading newline is removed 282 + 'insignificant-whitespace14': ('\n\n\n{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 283 + '\n\n\n{%\n some text\n'), 284 + # Trailing whitespace after tag 285 + 'insignificant-whitespace15': ('\n\n\n{% templatetag openblock %}\t \t \t\n some text\n', {}, '\n\n{%\t \t \t\n some text\n', 286 + '\n\n\n{%\t \t \t\n some text\n'), 287 + # Removable newline followed by leading whitespace 288 + 'insignificant-whitespace16': ('\n\n\n\t \t \t{% templatetag openblock %}\n some text\n', {}, '\n\n{%\n some text\n', 289 + '\n\n\n\t \t \t{%\n some text\n'), 290 + # Removable leading whitespace and trailing whitespace 291 + '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', 292 + '\n\n\n\t \t \t{%\t \t \t\n some text\n'), 293 + # Multiple lines of trailing whitespace. No trailing newline is removed. 294 + 'insignificant-whitespace18': ('\n{% templatetag openblock %}\n\n\n some text\n', {}, '{%\n\n\n some text\n', 295 + '\n{%\n\n\n some text\n'), 296 + 'insignificant-whitespace19': ('\n{% templatetag openblock %}\t \n\n\n some text\n', {}, '{%\t \n\n\n some text\n', 297 + '\n{%\t \n\n\n some text\n'), 298 + # Consecutive trimmed lines with tags strips one newline each 299 + 'insignificant-whitespace20': ( 300 + '\n{% templatetag openblock %}\n{% templatetag openblock %}\n{% templatetag openblock %}\n some text\n' 301 + , {}, '{%{%{%\n some text\n', 302 + '\n{%\n{%\n{%\n some text\n'), 303 + # Consecutive trimmed lines with tags strips one newline each. Intermediate newlines are preserved 304 + 'insignificant-whitespace21': ( 305 + '\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n{% templatetag openblock %}\n\n some text\n' 306 + , {}, '\n{%\n{%\n{%\n\n some text\n', 307 + '\n\n{%\n\n{%\n\n{%\n\n some text\n'), 308 + # Consecutive trimmed lines with tags strips one newline each. Leading whitespace is stripped but trailing is not 309 + 'insignificant-whitespace22': ( 310 + '\n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n\n\t {% templatetag openblock %}\t \n some text\n' 311 + , {}, '\n{%\t \n{%\t \n{%\t \n some text\n', 312 + '\n\n\t {%\t \n\n\t {%\t \n\n\t {%\t \n some text\n'), 313 + # Consecutive trimmed lines with tags strips one newline each. Intermediate whitespace is stripped 314 + 'insignificant-whitespace23': ( 315 + '\n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n\t {% templatetag openblock %}\t \n some text\n' 316 + , {}, '{%\t {%\t {%\t \n some text\n', 317 + '\n\t {%\t \n\t {%\t \n\t {%\t \n some text\n'), 318 + # Intermediate whitespace on one line is preserved 319 + # Consecutive tags on one line do not have intermediate whitespace or leading whitespace stripped 320 + 'insignificant-whitespace24': ( 321 + '\n\t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \t {% templatetag openblock %}\t \n some text\n' 322 + , {}, '\n\t {%\t \t {%\t \t {%\t \n some text\n', 323 + '\n\t {%\t \t {%\t \t {%\t \n some text\n'), 324 + # Still, only one leading newline is removed. 325 + 'insignificant-whitespace25': ( 326 + '\n\n {% templatetag openblock %}\n \t {% templatetag openblock %}\n \t {% templatetag openblock %}\n some text\n' 327 + , {}, '\n{%{%{%\n some text\n', 328 + '\n\n {%\n \t {%\n \t {%\n some text\n'), 329 + # Lines with {# comments #} have the same stripping behavior 330 + 'insignificant-whitespace26': ( 331 + '\n\n {% templatetag openblock %}\n \t {# some comment #}\n some text\n' 332 + , {}, '\n{%\n some text\n', 333 + '\n\n {%\n \t \n some text\n'), 334 + # Only {# comments #} 335 + 'insignificant-whitespace27': ( 336 + '\n\n {# a comment #}\n \t {# some comment #}\n some text\n' 337 + , {}, '\n\n some text\n', 338 + '\n\n \n \t \n some text\n'), 339 + # Consecutive newlines with tags and comments 340 + 'insignificant-whitespace28': ( 341 + '\n\t {% templatetag openblock %}\t \n\t {# some comment #}\t \n\t {% templatetag openblock %}\t \n some text\n' 342 + , {}, '{%\t \t {%\t \n some text\n', 343 + '\n\t {%\t \n\t \t \n\t {%\t \n some text\n'), 344 + 345 + # Lines with only {{ values }} have the same stripping behavior 346 + 'insignificant-whitespace29': ( 347 + '\n {% templatetag openblock %}\t\n \t {{ spam }}\t \n \t {% templatetag openblock %}\t \n some text\n' 348 + , {"spam" : "ham"}, '{%\tham\t {%\t \n some text\n', 349 + '\n {%\t\n \t ham\t \n \t {%\t \n some text\n'), 350 + 'insignificant-whitespace30': ( 351 + '\n\n {% templatetag openblock %}\t\n\n \t {{ spam }}\t \n\n \t {% templatetag openblock %}\t \n some text\n' 352 + , {"spam" : "ham"}, '\n{%\t\nham\t \n{%\t \n some text\n', 353 + '\n\n {%\t\n\n \t ham\t \n\n \t {%\t \n some text\n'), 354 + ## Leading whitespace not stripped when followed by anything. See insignificant-whitespace24 355 + 'insignificant-whitespace31': ( 356 + '\n {% templatetag openblock %}\t \t {{ spam }}\t \t {% templatetag openblock %}\t \n some text\n' 357 + , {"spam" : "ham"}, '\n {%\t \t ham\t \t {%\t \n some text\n', 358 + '\n {%\t \t ham\t \t {%\t \n some text\n'), 359 + # {{ value }} {% tag %} {{ value }} this time 360 + 'insignificant-whitespace32': ( 361 + '\n {{ spam }}\t\n \t {% templatetag openblock %}\t \n \t {{ spam }}\t \n some text\n' 362 + , {"spam" : "ham"}, 'ham\t{%\t ham\t \n some text\n', 363 + '\n ham\t\n \t {%\t \n \t ham\t \n some text\n'), 364 + 365 + # Invalid stuff is still invalid 366 + # Newlines inside begin-end tokens, even in {# comments #}, make it not a tag. 367 + 'insignificant-whitespace33': ( 368 + '\n\n {# \n{% templatetag openblock #}\t \n some text\n' 369 + , {}, '\n\n {# \n{% templatetag openblock #}\t \n some text\n', 370 + '\n\n {# \n{% templatetag openblock #}\t \n some text\n'), 371 + # Complete comment matching tags on one line are processed 372 + 'insignificant-whitespace34': ( 373 + '\n\n {# \n{# templatetag openblock #}\t \n some text\n' 374 + , {}, '\n\n {# \t \n some text\n', 375 + '\n\n {# \n\t \n some text\n'), 376 + 'insignificant-whitespace35': ( 377 + '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n' 378 + , {}, '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n', 379 + '\n\n {# \n{# templatetag openblock\n #}\t \n some text\n'), 380 + 'insignificant-whitespace36': ( 381 + '\n\n {# \n{{ some comment #}\t \n some text\n' 382 + , {}, '\n\n {# \n{{ some comment #}\t \n some text\n', 383 + '\n\n {# \n{{ some comment #}\t \n some text\n'), 384 + 'insignificant-whitespace37': ( 385 + '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n' 386 + , {}, '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n', 387 + '\n\n {# \n \t {% templatetag openblock #}\t \n some text\n'), 388 + 'insignificant-whitespace38': ( 389 + "\n\n {# templatetag openblock #\n}\t \n some text\n" 390 + , {}, "\n\n {# templatetag openblock #\n}\t \n some text\n", 391 + "\n\n {# templatetag openblock #\n}\t \n some text\n" ), 392 + 'insignificant-whitespace39': ( 393 + "\n\n {% templatetag openblock %\n}\t \n some text\n" 394 + , {}, "\n\n {% templatetag openblock %\n}\t \n some text\n", 395 + "\n\n {% templatetag openblock %\n}\t \n some text\n" ), 396 + 'insignificant-whitespace40': ( 397 + "\n\n {{ templatetag openblock }\n}\t \n some text\n" 398 + , {}, "\n\n {{ templatetag openblock }\n}\t \n some text\n", 399 + "\n\n {{ templatetag openblock }\n}\t \n some text\n" ), 400 + 'insignificant-whitespace41': ( 401 + "\n\n {\n# {# templatetag openblock #}\t \n some text\n" 402 + , {}, "\n\n {\n# \t \n some text\n", 403 + "\n\n {\n# \t \n some text\n"), 404 + 'insignificant-whitespace42': ( 405 + "\n\n {\n {# templatetag openblock #}\t \n some text\n" 406 + , {}, "\n\n {\t \n some text\n", 407 + "\n\n {\n \t \n some text\n"), 408 + 'insignificant-whitespace43': ( 409 + "\n{{# foo #};{# bar #}\n" 410 + , {}, "\n{;\n", 411 + "\n{;\n"), 412 + } 413 + tests = whitespace_tests.items() 414 + tests.sort() 415 + 416 + # Register our custom template loader. 417 + def test_whitespace_loader(template_name, template_dirs=None): 418 + "A custom template loader that loads the unit-test templates." 419 + try: 420 + return (whitespace_tests[template_name][0] , "test:%s" % template_name) 421 + except KeyError: 422 + raise template.TemplateDoesNotExist, template_name 423 + 424 + old_template_loaders = loader.template_source_loaders 425 + loader.template_source_loaders = [test_whitespace_loader] 426 + 427 + failures = [] 428 + 429 + old_strip_leading_whitespace = settings.TEMPLATE_STRIP_LEADING_WHITESPACE 430 + 431 + for name, vals in tests: 432 + for strip_leading_whitespace in (True, False): 433 + settings.TEMPLATE_STRIP_LEADING_WHITESPACE = strip_leading_whitespace 434 + test_template = loader.get_template(name) 435 + result = vals[2] if strip_leading_whitespace else vals[3] 436 + output = self.render(test_template, vals) 437 + 438 + if output != result: 439 + failures.append("Whitespace test: %s -- FAILED. Expected %r, got %r" % (name, result, output)) 440 + 441 + loader.template_source_loaders = old_template_loaders 442 + settings.TEMPLATE_STRIP_LEADING_WHITESPACE = old_strip_leading_whitespace 443 + 444 + self.assertEqual(failures, [], "Tests failed:\n%s\n%s" % 445 + ('-'*70, ("\n%s\n" % ('-'*70)).join(failures))) 446 + 447 def test_templates(self): 448 template_tests = self.get_template_tests() 449 filter_tests = filters.get_filter_tests()