Fixed #20296 -- Allowed SafeData and EscapeData to be lazy

This commit is contained in:
Baptiste Mispelon 2013-04-20 13:38:14 +02:00 committed by Claude Paroz
parent be0bab1bb8
commit 2ee447fb5f
2 changed files with 60 additions and 3 deletions

View File

@ -4,7 +4,7 @@ without further escaping in HTML. Marking something as a "safe string" means
that the producer of the string has already turned characters that should not that the producer of the string has already turned characters that should not
be interpreted by the HTML engine (e.g. '<') into the appropriate entities. be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
""" """
from django.utils.functional import curry, Promise from django.utils.functional import curry, Promise, allow_lazy
from django.utils import six from django.utils import six
class EscapeData(object): class EscapeData(object):
@ -14,13 +14,13 @@ class EscapeBytes(bytes, EscapeData):
""" """
A byte string that should be HTML-escaped when output. A byte string that should be HTML-escaped when output.
""" """
pass __new__ = allow_lazy(bytes.__new__, bytes)
class EscapeText(six.text_type, EscapeData): class EscapeText(six.text_type, EscapeData):
""" """
A unicode string object that should be HTML-escaped when output. A unicode string object that should be HTML-escaped when output.
""" """
pass __new__ = allow_lazy(six.text_type.__new__, six.text_type)
if six.PY3: if six.PY3:
EscapeString = EscapeText EscapeString = EscapeText
@ -37,6 +37,8 @@ class SafeBytes(bytes, SafeData):
A bytes subclass that has been specifically marked as "safe" (requires no A bytes subclass that has been specifically marked as "safe" (requires no
further escaping) for HTML output purposes. further escaping) for HTML output purposes.
""" """
__new__ = allow_lazy(bytes.__new__, bytes)
def __add__(self, rhs): def __add__(self, rhs):
""" """
Concatenating a safe byte string with another safe byte string or safe Concatenating a safe byte string with another safe byte string or safe
@ -69,6 +71,8 @@ class SafeText(six.text_type, SafeData):
A unicode (Python 2) / str (Python 3) subclass that has been specifically A unicode (Python 2) / str (Python 3) subclass that has been specifically
marked as "safe" for HTML output purposes. marked as "safe" for HTML output purposes.
""" """
__new__ = allow_lazy(six.text_type.__new__, six.text_type)
def __add__(self, rhs): def __add__(self, rhs):
""" """
Concatenating a safe unicode string with another safe byte string or Concatenating a safe unicode string with another safe byte string or

View File

@ -0,0 +1,53 @@
from __future__ import absolute_import, unicode_literals
from django.template import Template, Context
from django.test import TestCase
from django.utils.encoding import force_text, force_bytes
from django.utils.functional import lazy, Promise
from django.utils.html import escape, conditional_escape
from django.utils.safestring import mark_safe, mark_for_escaping
from django.utils import six
from django.utils import translation
lazystr = lazy(force_text, six.text_type)
lazybytes = lazy(force_bytes, bytes)
class SafeStringTest(TestCase):
def assertRenderEqual(self, tpl, expected, **context):
context = Context(context)
tpl = Template(tpl)
self.assertEqual(tpl.render(context), expected)
def test_mark_safe(self):
s = mark_safe('a&b')
self.assertRenderEqual('{{ s }}', 'a&b', s=s)
self.assertRenderEqual('{{ s|force_escape }}', 'a&amp;b', s=s)
def test_mark_safe_lazy(self):
s = lazystr('a&b')
b = lazybytes(b'a&b')
self.assertIsInstance(mark_safe(s), Promise)
self.assertIsInstance(mark_safe(b), Promise)
self.assertRenderEqual('{{ s }}', 'a&b', s=mark_safe(s))
def test_mark_for_escaping(self):
s = mark_for_escaping('a&b')
self.assertRenderEqual('{{ s }}', 'a&amp;b', s=s)
self.assertRenderEqual('{{ s }}', 'a&amp;b', s=mark_for_escaping(s))
def test_mark_for_escaping_lazy(self):
s = lazystr('a&b')
b = lazybytes(b'a&b')
self.assertIsInstance(mark_for_escaping(s), Promise)
self.assertIsInstance(mark_for_escaping(b), Promise)
self.assertRenderEqual('{% autoescape off %}{{ s }}{% endautoescape %}', 'a&amp;b', s=mark_for_escaping(s))
def test_regression_20296(self):
s = mark_safe(translation.ugettext_lazy("username"))
with translation.override('fr'):
self.assertRenderEqual('{{ s }}', "nom d'utilisateur", s=s)