Loading AUTHORS +1 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,7 @@ answer newbie questions, and generally made Django that much better: polpak@yahoo.com pradeep.gowda@gmail.com Preston Holmes <preston@ptone.com> Preston Timmons <prestontimmons@gmail.com> Rachel Willmer <http://www.willmer.com/kb/> Radek Švarz <http://www.svarz.cz/translate/> Rajesh Dhawan <rajesh.dhawan@gmail.com> Loading tests/template_tests/filters.py +1 −13 Original line number Diff line number Diff line Loading @@ -11,24 +11,12 @@ from __future__ import unicode_literals from datetime import date, datetime, time, timedelta from django.test.utils import str_prefix, TZ_SUPPORT from django.utils.encoding import python_2_unicode_compatible from django.utils.safestring import mark_safe from django.utils import timezone # These two classes are used to test auto-escaping of __unicode__ output. from .syntax_tests.utils import SafeClass, UnsafeClass @python_2_unicode_compatible class UnsafeClass: def __str__(self): return 'you & me' @python_2_unicode_compatible class SafeClass: def __str__(self): return mark_safe('you > me') # RESULT SYNTAX -- # 'template_name': ('template contents', 'context dict', # 'expected string output' or Exception class) Loading tests/template_tests/syntax_tests/__init__.py 0 → 100644 +0 −0 Empty file added. tests/template_tests/syntax_tests/test_autoescape.py 0 → 100644 +121 −0 Original line number Diff line number Diff line from django.template.base import TemplateSyntaxError from django.test import TestCase from django.utils.safestring import mark_safe from .utils import render, setup, SafeClass, UnsafeClass class AutoescapeTagTests(TestCase): @setup({'autoescape-tag01': '{% autoescape off %}hello{% endautoescape %}'}) def test_autoescape_tag01(self): output = render('autoescape-tag01') self.assertEqual(output, 'hello') @setup({'autoescape-tag02': '{% autoescape off %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag02(self): output = render('autoescape-tag02', {'first': '<b>hello</b>'}) self.assertEqual(output, '<b>hello</b>') @setup({'autoescape-tag03': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag03(self): output = render('autoescape-tag03', {'first': '<b>hello</b>'}) self.assertEqual(output, '<b>hello</b>') # Autoescape disabling and enabling nest in a predictable way. @setup({'autoescape-tag04': '{% autoescape off %}' '{{ first }} {% autoescape on %}{{ first }}{% endautoescape %}{% endautoescape %}'}) def test_autoescape_tag04(self): output = render('autoescape-tag04', {'first': '<a>'}) self.assertEqual(output, '<a> <a>') @setup({'autoescape-tag05': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag05(self): output = render('autoescape-tag05', {'first': '<b>first</b>'}) self.assertEqual(output, '<b>first</b>') # Strings (ASCII or unicode) already marked as "safe" are not # auto-escaped @setup({'autoescape-tag06': '{{ first }}'}) def test_autoescape_tag06(self): output = render('autoescape-tag06', {'first': mark_safe('<b>first</b>')}) self.assertEqual(output, '<b>first</b>') @setup({'autoescape-tag07': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag07(self): output = render('autoescape-tag07', {'first': mark_safe('<b>Apple</b>')}) self.assertEqual(output, '<b>Apple</b>') @setup({'autoescape-tag08': r'{% autoescape on %}' r'{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}'}) def test_autoescape_tag08(self): """ Literal string arguments to filters, if used in the result, are safe. """ output = render('autoescape-tag08', {"var": None}) self.assertEqual(output, ' endquote" hah') # Objects which return safe strings as their __str__ method # won't get double-escaped. @setup({'autoescape-tag09': r'{{ unsafe }}'}) def test_autoescape_tag09(self): output = render('autoescape-tag09', {'unsafe': UnsafeClass()}) self.assertEqual(output, 'you & me') @setup({'autoescape-tag10': r'{{ safe }}'}) def test_autoescape_tag10(self): output = render('autoescape-tag10', {'safe': SafeClass()}) self.assertEqual(output, 'you > me') @setup({'autoescape-filtertag01': '{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}'}) def test_autoescape_filtertag01(self): """ The "safe" and "escape" filters cannot work due to internal implementation details (fortunately, the (no)autoescape block tags can be used in those cases) """ with self.assertRaises(TemplateSyntaxError): render('autoescape-filtertag01', {'first': '<a>'}) @setup({'autoescape-ifequal01': '{% ifequal var "this & that" %}yes{% endifequal %}'}) def test_autoescape_ifequal01(self): """ ifequal compares unescaped vales. """ output = render('autoescape-ifequal01', {'var': 'this & that'}) self.assertEqual(output, 'yes') # Arguments to filters are 'safe' and manipulate their input unescaped. @setup({'autoescape-filters01': '{{ var|cut:"&" }}'}) def test_autoescape_filters01(self): output = render('autoescape-filters01', {'var': 'this & that'}) self.assertEqual(output, 'this that') @setup({'autoescape-filters02': '{{ var|join:" & " }}'}) def test_autoescape_filters02(self): output = render('autoescape-filters02', {'var': ('Tom', 'Dick', 'Harry')}) self.assertEqual(output, 'Tom & Dick & Harry') @setup({'autoescape-literals01': '{{ "this & that" }}'}) def test_autoescape_literals01(self): """ Literal strings are safe. """ output = render('autoescape-literals01') self.assertEqual(output, 'this & that') @setup({'autoescape-stringiterations01': '{% for l in var %}{{ l }},{% endfor %}'}) def test_autoescape_stringiterations01(self): """ Iterating over strings outputs safe characters. """ output = render('autoescape-stringiterations01', {'var': 'K&R'}) self.assertEqual(output, 'K,&,R,') @setup({'autoescape-lookup01': '{{ var.key }}'}) def test_autoescape_lookup01(self): """ Escape requirement survives lookup. """ output = render('autoescape-lookup01', {'var': {'key': 'this & that'}}) self.assertEqual(output, 'this & that') tests/template_tests/syntax_tests/test_basic.py 0 → 100644 +316 −0 Original line number Diff line number Diff line from django.conf import settings from django.template.base import Context, TemplateSyntaxError from django.template.loader import get_template from django.test import TestCase from .utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass basic_templates = { 'basic-syntax01': 'something cool', 'basic-syntax02': '{{ headline }}', 'basic-syntax03': '{{ first }} --- {{ second }}', } class BasicSyntaxTests(TestCase): @setup(basic_templates) def test_basic_syntax01(self): """ Plain text should go through the template parser untouched. """ output = render('basic-syntax01') self.assertEqual(output, "something cool") @setup(basic_templates) def test_basic_syntax02(self): """ Variables should be replaced with their value in the current context """ output = render('basic-syntax02', {'headline': 'Success'}) self.assertEqual(output, 'Success') @setup(basic_templates) def test_basic_syntax03(self): """ More than one replacement variable is allowed in a template """ output = render('basic-syntax03', {"first": 1, "second": 2}) self.assertEqual(output, '1 --- 2') @setup({'basic-syntax04': 'as{{ missing }}df'}) def test_basic_syntax04(self): """ Fail silently when a variable is not found in the current context """ output = render('basic-syntax04') if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'asINVALIDdf') else: self.assertEqual(output, 'asdf') @setup({'basic-syntax06': '{{ multi word variable }}'}) def test_basic_syntax06(self): """ A variable may not contain more than one word """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax06') @setup({'basic-syntax07': '{{ }}'}) def test_basic_syntax07(self): """ Raise TemplateSyntaxError for empty variable tags. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax07') @setup({'basic-syntax08': '{{ }}'}) def test_basic_syntax08(self): """ Raise TemplateSyntaxError for empty variable tags. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax08') @setup({'basic-syntax09': '{{ var.method }}'}) def test_basic_syntax09(self): """ Attribute syntax allows a template to call an object's attribute """ output = render('basic-syntax09', {'var': SomeClass()}) self.assertEqual(output, 'SomeClass.method') @setup({'basic-syntax10': '{{ var.otherclass.method }}'}) def test_basic_syntax10(self): """ Multiple levels of attribute access are allowed. """ output = render('basic-syntax10', {'var': SomeClass()}) self.assertEqual(output, 'OtherClass.method') @setup({'basic-syntax11': '{{ var.blech }}'}) def test_basic_syntax11(self): """ Fail silently when a variable's attribute isn't found. """ output = render('basic-syntax11', {'var': SomeClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax12': '{{ var.__dict__ }}'}) def test_basic_syntax12(self): """ Raise TemplateSyntaxError when trying to access a variable beginning with an underscore. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax12') # Raise TemplateSyntaxError when trying to access a variable # containing an illegal character. @setup({'basic-syntax13': "{{ va>r }}"}) def test_basic_syntax13(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax13') @setup({'basic-syntax14': "{{ (var.r) }}"}) def test_basic_syntax14(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax14') @setup({'basic-syntax15': "{{ sp%am }}"}) def test_basic_syntax15(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax15') @setup({'basic-syntax16': "{{ eggs! }}"}) def test_basic_syntax16(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax16') @setup({'basic-syntax17': "{{ moo? }}"}) def test_basic_syntax17(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax17') @setup({'basic-syntax18': "{{ foo.bar }}"}) def test_basic_syntax18(self): """ Attribute syntax allows a template to call a dictionary key's value. """ output = render('basic-syntax18', {"foo": {"bar": "baz"}}) self.assertEqual(output, "baz") @setup({'basic-syntax19': "{{ foo.spam }}"}) def test_basic_syntax19(self): """ Fail silently when a variable's dictionary key isn't found. """ output = render('basic-syntax19', {"foo": {"bar": "baz"}}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax20': "{{ var.method2 }}"}) def test_basic_syntax20(self): """ Fail silently when accessing a non-simple method """ output = render('basic-syntax20', {'var': SomeClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax20b': "{{ var.method5 }}"}) def test_basic_syntax20b(self): """ Don't silence a TypeError if it was raised inside a callable. """ template = get_template('basic-syntax20b') with self.assertRaises(TypeError): template.render(Context({'var': SomeClass()})) # Don't get confused when parsing something that is almost, but not # quite, a template tag. @setup({'basic-syntax21': "a {{ moo %} b"}) def test_basic_syntax21(self): output = render('basic-syntax21') self.assertEqual(output, "a {{ moo %} b") @setup({'basic-syntax22': "{{ moo #}"}) def test_basic_syntax22(self): output = render('basic-syntax22') self.assertEqual(output, "{{ moo #}") @setup({'basic-syntax23': "{{ moo #} {{ cow }}"}) def test_basic_syntax23(self): """ Treat "moo #} {{ cow" as the variable. Not ideal, but costly to work around, so this triggers an error. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax23') @setup({'basic-syntax24': "{{ moo\n }}"}) def test_basic_syntax24(self): """ Embedded newlines make it not-a-tag. """ output = render('basic-syntax24') self.assertEqual(output, "{{ moo\n }}") # Literal strings are permitted inside variables, mostly for i18n # purposes. @setup({'basic-syntax25': '{{ "fred" }}'}) def test_basic_syntax25(self): output = render('basic-syntax25') self.assertEqual(output, "fred") @setup({'basic-syntax26': r'{{ "\"fred\"" }}'}) def test_basic_syntax26(self): output = render('basic-syntax26') self.assertEqual(output, "\"fred\"") @setup({'basic-syntax27': r'{{ _("\"fred\"") }}'}) def test_basic_syntax27(self): output = render('basic-syntax27') self.assertEqual(output, "\"fred\"") # #12554 -- Make sure a silent_variable_failure Exception is # suppressed on dictionary and attribute lookup. @setup({'basic-syntax28': "{{ a.b }}"}) def test_basic_syntax28(self): output = render('basic-syntax28', {'a': SilentGetItemClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax29': "{{ a.b }}"}) def test_basic_syntax29(self): output = render('basic-syntax29', {'a': SilentAttrClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') # Something that starts like a number but has an extra lookup works # as a lookup. @setup({'basic-syntax30': "{{ 1.2.3 }}"}) def test_basic_syntax30(self): output = render( 'basic-syntax30', {"1": {"2": {"3": "d"}}} ) self.assertEqual(output, 'd') @setup({'basic-syntax31': "{{ 1.2.3 }}"}) def test_basic_syntax31(self): output = render( 'basic-syntax31', {"1": {"2": ("a", "b", "c", "d")}}, ) self.assertEqual(output, 'd') @setup({'basic-syntax32': "{{ 1.2.3 }}"}) def test_basic_syntax32(self): output = render( 'basic-syntax32', {"1": (("x", "x", "x", "x"), ("y", "y", "y", "y"), ("a", "b", "c", "d"))}, ) self.assertEqual(output, 'd') @setup({'basic-syntax33': "{{ 1.2.3 }}"}) def test_basic_syntax33(self): output = render( 'basic-syntax33', {"1": ("xxxx", "yyyy", "abcd")}, ) self.assertEqual(output, 'd') @setup({'basic-syntax34': "{{ 1.2.3 }}"}) def test_basic_syntax34(self): output = render( 'basic-syntax34', {"1": ({"x": "x"}, {"y": "y"}, {"z": "z", "3": "d"})} ) self.assertEqual(output, 'd') # Numbers are numbers even if their digits are in the context. @setup({'basic-syntax35': "{{ 1 }}"}) def test_basic_syntax35(self): output = render('basic-syntax35', {"1": "abc"}) self.assertEqual(output, '1') @setup({'basic-syntax36': "{{ 1.2 }}"}) def test_basic_syntax36(self): output = render('basic-syntax36', {"1": "abc"}) self.assertEqual(output, '1.2') @setup({'basic-syntax37': '{{ callable }}'}) def test_basic_syntax37(self): """ Call methods in the top level of the context. """ output = render('basic-syntax37', {"callable": lambda: "foo bar"}) self.assertEqual(output, 'foo bar') @setup({'basic-syntax38': '{{ var.callable }}'}) def test_basic_syntax38(self): """ Call methods returned from dictionary lookups. """ output = render('basic-syntax38', {"var": {"callable": lambda: "foo bar"}}) self.assertEqual(output, 'foo bar') Loading
AUTHORS +1 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,7 @@ answer newbie questions, and generally made Django that much better: polpak@yahoo.com pradeep.gowda@gmail.com Preston Holmes <preston@ptone.com> Preston Timmons <prestontimmons@gmail.com> Rachel Willmer <http://www.willmer.com/kb/> Radek Švarz <http://www.svarz.cz/translate/> Rajesh Dhawan <rajesh.dhawan@gmail.com> Loading
tests/template_tests/filters.py +1 −13 Original line number Diff line number Diff line Loading @@ -11,24 +11,12 @@ from __future__ import unicode_literals from datetime import date, datetime, time, timedelta from django.test.utils import str_prefix, TZ_SUPPORT from django.utils.encoding import python_2_unicode_compatible from django.utils.safestring import mark_safe from django.utils import timezone # These two classes are used to test auto-escaping of __unicode__ output. from .syntax_tests.utils import SafeClass, UnsafeClass @python_2_unicode_compatible class UnsafeClass: def __str__(self): return 'you & me' @python_2_unicode_compatible class SafeClass: def __str__(self): return mark_safe('you > me') # RESULT SYNTAX -- # 'template_name': ('template contents', 'context dict', # 'expected string output' or Exception class) Loading
tests/template_tests/syntax_tests/test_autoescape.py 0 → 100644 +121 −0 Original line number Diff line number Diff line from django.template.base import TemplateSyntaxError from django.test import TestCase from django.utils.safestring import mark_safe from .utils import render, setup, SafeClass, UnsafeClass class AutoescapeTagTests(TestCase): @setup({'autoescape-tag01': '{% autoescape off %}hello{% endautoescape %}'}) def test_autoescape_tag01(self): output = render('autoescape-tag01') self.assertEqual(output, 'hello') @setup({'autoescape-tag02': '{% autoescape off %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag02(self): output = render('autoescape-tag02', {'first': '<b>hello</b>'}) self.assertEqual(output, '<b>hello</b>') @setup({'autoescape-tag03': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag03(self): output = render('autoescape-tag03', {'first': '<b>hello</b>'}) self.assertEqual(output, '<b>hello</b>') # Autoescape disabling and enabling nest in a predictable way. @setup({'autoescape-tag04': '{% autoescape off %}' '{{ first }} {% autoescape on %}{{ first }}{% endautoescape %}{% endautoescape %}'}) def test_autoescape_tag04(self): output = render('autoescape-tag04', {'first': '<a>'}) self.assertEqual(output, '<a> <a>') @setup({'autoescape-tag05': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag05(self): output = render('autoescape-tag05', {'first': '<b>first</b>'}) self.assertEqual(output, '<b>first</b>') # Strings (ASCII or unicode) already marked as "safe" are not # auto-escaped @setup({'autoescape-tag06': '{{ first }}'}) def test_autoescape_tag06(self): output = render('autoescape-tag06', {'first': mark_safe('<b>first</b>')}) self.assertEqual(output, '<b>first</b>') @setup({'autoescape-tag07': '{% autoescape on %}{{ first }}{% endautoescape %}'}) def test_autoescape_tag07(self): output = render('autoescape-tag07', {'first': mark_safe('<b>Apple</b>')}) self.assertEqual(output, '<b>Apple</b>') @setup({'autoescape-tag08': r'{% autoescape on %}' r'{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}'}) def test_autoescape_tag08(self): """ Literal string arguments to filters, if used in the result, are safe. """ output = render('autoescape-tag08', {"var": None}) self.assertEqual(output, ' endquote" hah') # Objects which return safe strings as their __str__ method # won't get double-escaped. @setup({'autoescape-tag09': r'{{ unsafe }}'}) def test_autoescape_tag09(self): output = render('autoescape-tag09', {'unsafe': UnsafeClass()}) self.assertEqual(output, 'you & me') @setup({'autoescape-tag10': r'{{ safe }}'}) def test_autoescape_tag10(self): output = render('autoescape-tag10', {'safe': SafeClass()}) self.assertEqual(output, 'you > me') @setup({'autoescape-filtertag01': '{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}'}) def test_autoescape_filtertag01(self): """ The "safe" and "escape" filters cannot work due to internal implementation details (fortunately, the (no)autoescape block tags can be used in those cases) """ with self.assertRaises(TemplateSyntaxError): render('autoescape-filtertag01', {'first': '<a>'}) @setup({'autoescape-ifequal01': '{% ifequal var "this & that" %}yes{% endifequal %}'}) def test_autoescape_ifequal01(self): """ ifequal compares unescaped vales. """ output = render('autoescape-ifequal01', {'var': 'this & that'}) self.assertEqual(output, 'yes') # Arguments to filters are 'safe' and manipulate their input unescaped. @setup({'autoescape-filters01': '{{ var|cut:"&" }}'}) def test_autoescape_filters01(self): output = render('autoescape-filters01', {'var': 'this & that'}) self.assertEqual(output, 'this that') @setup({'autoescape-filters02': '{{ var|join:" & " }}'}) def test_autoescape_filters02(self): output = render('autoescape-filters02', {'var': ('Tom', 'Dick', 'Harry')}) self.assertEqual(output, 'Tom & Dick & Harry') @setup({'autoescape-literals01': '{{ "this & that" }}'}) def test_autoescape_literals01(self): """ Literal strings are safe. """ output = render('autoescape-literals01') self.assertEqual(output, 'this & that') @setup({'autoescape-stringiterations01': '{% for l in var %}{{ l }},{% endfor %}'}) def test_autoescape_stringiterations01(self): """ Iterating over strings outputs safe characters. """ output = render('autoescape-stringiterations01', {'var': 'K&R'}) self.assertEqual(output, 'K,&,R,') @setup({'autoescape-lookup01': '{{ var.key }}'}) def test_autoescape_lookup01(self): """ Escape requirement survives lookup. """ output = render('autoescape-lookup01', {'var': {'key': 'this & that'}}) self.assertEqual(output, 'this & that')
tests/template_tests/syntax_tests/test_basic.py 0 → 100644 +316 −0 Original line number Diff line number Diff line from django.conf import settings from django.template.base import Context, TemplateSyntaxError from django.template.loader import get_template from django.test import TestCase from .utils import render, setup, SilentGetItemClass, SilentAttrClass, SomeClass basic_templates = { 'basic-syntax01': 'something cool', 'basic-syntax02': '{{ headline }}', 'basic-syntax03': '{{ first }} --- {{ second }}', } class BasicSyntaxTests(TestCase): @setup(basic_templates) def test_basic_syntax01(self): """ Plain text should go through the template parser untouched. """ output = render('basic-syntax01') self.assertEqual(output, "something cool") @setup(basic_templates) def test_basic_syntax02(self): """ Variables should be replaced with their value in the current context """ output = render('basic-syntax02', {'headline': 'Success'}) self.assertEqual(output, 'Success') @setup(basic_templates) def test_basic_syntax03(self): """ More than one replacement variable is allowed in a template """ output = render('basic-syntax03', {"first": 1, "second": 2}) self.assertEqual(output, '1 --- 2') @setup({'basic-syntax04': 'as{{ missing }}df'}) def test_basic_syntax04(self): """ Fail silently when a variable is not found in the current context """ output = render('basic-syntax04') if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'asINVALIDdf') else: self.assertEqual(output, 'asdf') @setup({'basic-syntax06': '{{ multi word variable }}'}) def test_basic_syntax06(self): """ A variable may not contain more than one word """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax06') @setup({'basic-syntax07': '{{ }}'}) def test_basic_syntax07(self): """ Raise TemplateSyntaxError for empty variable tags. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax07') @setup({'basic-syntax08': '{{ }}'}) def test_basic_syntax08(self): """ Raise TemplateSyntaxError for empty variable tags. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax08') @setup({'basic-syntax09': '{{ var.method }}'}) def test_basic_syntax09(self): """ Attribute syntax allows a template to call an object's attribute """ output = render('basic-syntax09', {'var': SomeClass()}) self.assertEqual(output, 'SomeClass.method') @setup({'basic-syntax10': '{{ var.otherclass.method }}'}) def test_basic_syntax10(self): """ Multiple levels of attribute access are allowed. """ output = render('basic-syntax10', {'var': SomeClass()}) self.assertEqual(output, 'OtherClass.method') @setup({'basic-syntax11': '{{ var.blech }}'}) def test_basic_syntax11(self): """ Fail silently when a variable's attribute isn't found. """ output = render('basic-syntax11', {'var': SomeClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax12': '{{ var.__dict__ }}'}) def test_basic_syntax12(self): """ Raise TemplateSyntaxError when trying to access a variable beginning with an underscore. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax12') # Raise TemplateSyntaxError when trying to access a variable # containing an illegal character. @setup({'basic-syntax13': "{{ va>r }}"}) def test_basic_syntax13(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax13') @setup({'basic-syntax14': "{{ (var.r) }}"}) def test_basic_syntax14(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax14') @setup({'basic-syntax15': "{{ sp%am }}"}) def test_basic_syntax15(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax15') @setup({'basic-syntax16': "{{ eggs! }}"}) def test_basic_syntax16(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax16') @setup({'basic-syntax17': "{{ moo? }}"}) def test_basic_syntax17(self): with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax17') @setup({'basic-syntax18': "{{ foo.bar }}"}) def test_basic_syntax18(self): """ Attribute syntax allows a template to call a dictionary key's value. """ output = render('basic-syntax18', {"foo": {"bar": "baz"}}) self.assertEqual(output, "baz") @setup({'basic-syntax19': "{{ foo.spam }}"}) def test_basic_syntax19(self): """ Fail silently when a variable's dictionary key isn't found. """ output = render('basic-syntax19', {"foo": {"bar": "baz"}}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax20': "{{ var.method2 }}"}) def test_basic_syntax20(self): """ Fail silently when accessing a non-simple method """ output = render('basic-syntax20', {'var': SomeClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax20b': "{{ var.method5 }}"}) def test_basic_syntax20b(self): """ Don't silence a TypeError if it was raised inside a callable. """ template = get_template('basic-syntax20b') with self.assertRaises(TypeError): template.render(Context({'var': SomeClass()})) # Don't get confused when parsing something that is almost, but not # quite, a template tag. @setup({'basic-syntax21': "a {{ moo %} b"}) def test_basic_syntax21(self): output = render('basic-syntax21') self.assertEqual(output, "a {{ moo %} b") @setup({'basic-syntax22': "{{ moo #}"}) def test_basic_syntax22(self): output = render('basic-syntax22') self.assertEqual(output, "{{ moo #}") @setup({'basic-syntax23': "{{ moo #} {{ cow }}"}) def test_basic_syntax23(self): """ Treat "moo #} {{ cow" as the variable. Not ideal, but costly to work around, so this triggers an error. """ with self.assertRaises(TemplateSyntaxError): get_template('basic-syntax23') @setup({'basic-syntax24': "{{ moo\n }}"}) def test_basic_syntax24(self): """ Embedded newlines make it not-a-tag. """ output = render('basic-syntax24') self.assertEqual(output, "{{ moo\n }}") # Literal strings are permitted inside variables, mostly for i18n # purposes. @setup({'basic-syntax25': '{{ "fred" }}'}) def test_basic_syntax25(self): output = render('basic-syntax25') self.assertEqual(output, "fred") @setup({'basic-syntax26': r'{{ "\"fred\"" }}'}) def test_basic_syntax26(self): output = render('basic-syntax26') self.assertEqual(output, "\"fred\"") @setup({'basic-syntax27': r'{{ _("\"fred\"") }}'}) def test_basic_syntax27(self): output = render('basic-syntax27') self.assertEqual(output, "\"fred\"") # #12554 -- Make sure a silent_variable_failure Exception is # suppressed on dictionary and attribute lookup. @setup({'basic-syntax28': "{{ a.b }}"}) def test_basic_syntax28(self): output = render('basic-syntax28', {'a': SilentGetItemClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') @setup({'basic-syntax29': "{{ a.b }}"}) def test_basic_syntax29(self): output = render('basic-syntax29', {'a': SilentAttrClass()}) if settings.TEMPLATE_STRING_IF_INVALID: self.assertEqual(output, 'INVALID') else: self.assertEqual(output, '') # Something that starts like a number but has an extra lookup works # as a lookup. @setup({'basic-syntax30': "{{ 1.2.3 }}"}) def test_basic_syntax30(self): output = render( 'basic-syntax30', {"1": {"2": {"3": "d"}}} ) self.assertEqual(output, 'd') @setup({'basic-syntax31': "{{ 1.2.3 }}"}) def test_basic_syntax31(self): output = render( 'basic-syntax31', {"1": {"2": ("a", "b", "c", "d")}}, ) self.assertEqual(output, 'd') @setup({'basic-syntax32': "{{ 1.2.3 }}"}) def test_basic_syntax32(self): output = render( 'basic-syntax32', {"1": (("x", "x", "x", "x"), ("y", "y", "y", "y"), ("a", "b", "c", "d"))}, ) self.assertEqual(output, 'd') @setup({'basic-syntax33': "{{ 1.2.3 }}"}) def test_basic_syntax33(self): output = render( 'basic-syntax33', {"1": ("xxxx", "yyyy", "abcd")}, ) self.assertEqual(output, 'd') @setup({'basic-syntax34': "{{ 1.2.3 }}"}) def test_basic_syntax34(self): output = render( 'basic-syntax34', {"1": ({"x": "x"}, {"y": "y"}, {"z": "z", "3": "d"})} ) self.assertEqual(output, 'd') # Numbers are numbers even if their digits are in the context. @setup({'basic-syntax35': "{{ 1 }}"}) def test_basic_syntax35(self): output = render('basic-syntax35', {"1": "abc"}) self.assertEqual(output, '1') @setup({'basic-syntax36': "{{ 1.2 }}"}) def test_basic_syntax36(self): output = render('basic-syntax36', {"1": "abc"}) self.assertEqual(output, '1.2') @setup({'basic-syntax37': '{{ callable }}'}) def test_basic_syntax37(self): """ Call methods in the top level of the context. """ output = render('basic-syntax37', {"callable": lambda: "foo bar"}) self.assertEqual(output, 'foo bar') @setup({'basic-syntax38': '{{ var.callable }}'}) def test_basic_syntax38(self): """ Call methods returned from dictionary lookups. """ output = render('basic-syntax38', {"var": {"callable": lambda: "foo bar"}}) self.assertEqual(output, 'foo bar')