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 fahhem, 14 years ago)

Modifies DebugLexer too, not just Lexer

  • 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:  
    261261    Ian G. Kelly <ian.g.kelly@gmail.com>
    262262    Niall Kelly <duke.sam.vimes@gmail.com>
    263263    Ryan Kelly <ryan@rfk.id.au>
     264    Stephen Kelly <steveire@gmail.com>
    264265    Thomas Kerpe <thomas@kerpe.net>
    265266    Wiley Kestner <wiley.kestner@gmail.com>
    266267    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  
    1111
    1212DEBUG = False
    1313TEMPLATE_DEBUG = False
     14TEMPLATE_STRIP_LEADING_WHITESPACE = False
    1415
    1516# Whether the framework should propagate raw exceptions rather than catching
    1617# 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 imp
    21import re
    32from inspect import getargspec
    43
    from django.conf import settings  
    65from django.template.context import Context, RequestContext, ContextPopException
    76from django.utils.importlib import import_module
    87from django.utils.itercompat import is_iterable
    9 from django.utils.functional import curry, Promise
     8from django.utils.functional import curry
    109from django.utils.text import smart_split, unescape_string_literal, get_text_list
    1110from django.utils.encoding import smart_unicode, force_unicode, smart_str
    1211from django.utils.translation import ugettext as _
    ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01  
    4140# (e.g. strings)
    4241UNKNOWN_SOURCE = '<unknown source>'
    4342
     43
    4444# 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)))
     45tag_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
     60strip_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
     94block_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END)))
     95comment_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
     96variable_command_re = re.compile('%s(?P<token_string>.*?)%s' % (re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END)))
    4897
    4998# global dictionary of libraries that have been loaded using get_library
    5099libraries = {}
    class Lexer(object):  
    171220        "Return a list of tokens from a given template_string."
    172221        in_tag = False
    173222        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):
    175225            if bit:
    176226                result.append(self.create_token(bit, in_tag))
    177227            in_tag = not in_tag
    class Lexer(object):  
    184234        otherwise it should be treated as a literal string.
    185235        """
    186236        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):
    192246                content = ''
     247                token_struct = comment_command_re.search(token_string)
     248                token_string = token_struct.group('token_string')
    193249                if token_string.find(TRANSLATOR_COMMENT_MARK):
    194250                    content = token_string[len(COMMENT_TAG_START):-len(COMMENT_TAG_END)].strip()
    195251                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  
    11from django.conf import settings
    2 from django.template.base import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError
     2from django.template.base import Lexer, Parser, tag_re, strip_leading_whitespace_tag_re, NodeList, VariableNode, TemplateSyntaxError
    33from django.utils.encoding import force_unicode
    44from django.utils.html import escape
    55from django.utils.safestring import SafeData, EscapeData
    class DebugLexer(Lexer):  
    1212    def tokenize(self):
    1313        "Return a list of tokens from a given template_string"
    1414        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):
    1617            start, end = match.span()
    1718            if start > upto:
    1819                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  
    1111from django.conf import settings
    1212from django.utils.encoding import smart_str, smart_unicode
    1313from django.utils.safestring import mark_safe
     14from django.utils.text import smart_split
    1415
    1516register = Library()
    1617# Regex for token keyword arguments
    def token_kwargs(bits, parser, support_legacy=False):  
    4748
    4849    kwargs = {}
    4950    while bits:
    50         if kwarg_format: 
     51        if kwarg_format:
    5152            match = kwarg_re.match(bits[0])
    5253            if not match or not match.group(1):
    5354                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`..  
    17881788
    17891789.. setting:: TEST_RUNNER
    17901790
     1791TEMPLATE_STRIP_LEADING_WHITESPACE
     1792---------------------------------
     1793
     1794.. versionadded:: 1.3
     1795
     1796Default: ``False``
     1797
     1798Whether to strip leading whitespace on template lines containing only template
     1799syntax.
     1800
     1801This 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
     1814Normally 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
     1831However, if TEMPLATE_STRIP_LEADING_WHITESPACE is set to True, lines which
     1832contain only one template tag, variable or comment no not cause a newline
     1833to 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
     1843Trailing whitespace does not get stripped, and lines which contain more
     1844than one template tag will not have their leading whitespace trimmed.
     1845
    17911846TEST_RUNNER
    17921847-----------
    17931848
  • 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):  
    340340        except TemplateSyntaxError, e:
    341341            self.assertEquals(e.args[0], "Invalid block tag: 'endblock', expected 'else' or 'endif'")
    342342
     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
    343548    def test_templates(self):
    344549        template_tests = self.get_template_tests()
    345550        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
    - +  
     1commit ffaecbd5cf0387868af908f89e0b6695de755174
     2Author: Stephen Kelly <steveire@gmail.com>
     3Date:   Thu Jan 20 18:52:36 2011 +0100
     4
     5    Handle whitespace better in the template system.
     6
     7diff --git a/AUTHORS b/AUTHORS
     8index 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>
     19diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
     20index 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
     31diff --git a/django/template/base.py b/django/template/base.py
     32index 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)
     147diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
     148index 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
     168diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
     169index 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 
     234diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
     235index 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()
Back to Top