Skip to content

Commit

Permalink
Fixed #20296 -- Allowed SafeData and EscapeData to be lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
bmispelon authored and claudep committed May 25, 2013
1 parent be0bab1 commit 2ee447f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
10 changes: 7 additions & 3 deletions django/utils/safestring.py
Expand Up @@ -4,7 +4,7 @@
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):
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions tests/utils_tests/test_safestring.py
@@ -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)

0 comments on commit 2ee447f

Please sign in to comment.