Refs #27753 -- Favored SafeString over SafeText.

This commit is contained in:
Tim Graham 2019-02-05 09:38:29 -05:00
parent d55e882927
commit 77d25dbd0f
8 changed files with 25 additions and 31 deletions

View File

@ -13,7 +13,7 @@ from django.db import connections
from django.db.backends.base.base import BaseDatabaseWrapper from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.utils import DatabaseError as WrappedDatabaseError from django.db.utils import DatabaseError as WrappedDatabaseError
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.safestring import SafeText from django.utils.safestring import SafeString
from django.utils.version import get_version_tuple from django.utils.version import get_version_tuple
try: try:
@ -44,7 +44,7 @@ from .operations import DatabaseOperations # NOQA isort:skip
from .schema import DatabaseSchemaEditor # NOQA isort:skip from .schema import DatabaseSchemaEditor # NOQA isort:skip
from .utils import utc_tzinfo_factory # NOQA isort:skip from .utils import utc_tzinfo_factory # NOQA isort:skip
psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString) psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
psycopg2.extras.register_uuid() psycopg2.extras.register_uuid()
# Register support for inet[] manually so we don't have to handle the Inet() # Register support for inet[] manually so we don't have to handle the Inet()

View File

@ -1,7 +1,7 @@
from django.middleware.csrf import get_token from django.middleware.csrf import get_token
from django.utils.functional import lazy from django.utils.functional import lazy
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import SafeText from django.utils.safestring import SafeString
def csrf_input(request): def csrf_input(request):
@ -10,5 +10,5 @@ def csrf_input(request):
get_token(request)) get_token(request))
csrf_input_lazy = lazy(csrf_input, SafeText, str) csrf_input_lazy = lazy(csrf_input, SafeString, str)
csrf_token_lazy = lazy(get_token, str) csrf_token_lazy = lazy(get_token, str)

View File

@ -9,7 +9,7 @@ from urllib.parse import (
from django.utils.functional import Promise, keep_lazy, keep_lazy_text from django.utils.functional import Promise, keep_lazy, keep_lazy_text
from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
from django.utils.safestring import SafeData, SafeText, mark_safe from django.utils.safestring import SafeData, SafeString, mark_safe
from django.utils.text import normalize_newlines from django.utils.text import normalize_newlines
# Configuration for urlize() function. # Configuration for urlize() function.
@ -33,7 +33,7 @@ _html_escapes = {
} }
@keep_lazy(str, SafeText) @keep_lazy(str, SafeString)
def escape(text): def escape(text):
""" """
Return the given text with ampersands, quotes and angle brackets encoded Return the given text with ampersands, quotes and angle brackets encoded
@ -65,7 +65,7 @@ _js_escapes = {
_js_escapes.update((ord('%c' % z), '\\u%04X' % z) for z in range(32)) _js_escapes.update((ord('%c' % z), '\\u%04X' % z) for z in range(32))
@keep_lazy(str, SafeText) @keep_lazy(str, SafeString)
def escapejs(value): def escapejs(value):
"""Hex encode characters for use in JavaScript strings.""" """Hex encode characters for use in JavaScript strings."""
return mark_safe(str(value).translate(_js_escapes)) return mark_safe(str(value).translate(_js_escapes))
@ -372,7 +372,7 @@ def avoid_wrapping(value):
def html_safe(klass): def html_safe(klass):
""" """
A decorator that defines the __html__ method. This helps non-Django A decorator that defines the __html__ method. This helps non-Django
templates to detect classes whose __str__ methods return SafeText. templates to detect classes whose __str__ methods return SafeString.
""" """
if '__html__' in klass.__dict__: if '__html__' in klass.__dict__:
raise ValueError( raise ValueError(

View File

@ -18,7 +18,7 @@ class SafeData:
return self return self
class SafeText(str, SafeData): class SafeString(str, SafeData):
""" """
A str subclass that has been specifically marked as "safe" for HTML output A str subclass that has been specifically marked as "safe" for HTML output
purposes. purposes.
@ -30,14 +30,14 @@ class SafeText(str, SafeData):
""" """
t = super().__add__(rhs) t = super().__add__(rhs)
if isinstance(rhs, SafeData): if isinstance(rhs, SafeData):
return SafeText(t) return SafeString(t)
return t return t
def __str__(self): def __str__(self):
return self return self
SafeString = SafeText SafeText = SafeString # For backwards compatibility since Django 2.0.
def _safety_decorator(safety_marker, func): def _safety_decorator(safety_marker, func):
@ -60,4 +60,4 @@ def mark_safe(s):
return s return s
if callable(s): if callable(s):
return _safety_decorator(mark_safe, s) return _safety_decorator(mark_safe, s)
return SafeText(s) return SafeString(s)

View File

@ -200,12 +200,12 @@ passed around inside the template code:
to be interpreted as-is on the client side. to be interpreted as-is on the client side.
Internally, these strings are of type Internally, these strings are of type
:class:`~django.utils.safestring.SafeText`. You can test for them :class:`~django.utils.safestring.SafeString`. You can test for them
using code like:: using code like::
from django.utils.safestring import SafeText from django.utils.safestring import SafeString
if isinstance(value, SafeText): if isinstance(value, SafeString):
# Do something with the "safe" string. # Do something with the "safe" string.
... ...

View File

@ -748,14 +748,8 @@ appropriate entities.
.. class:: SafeString .. class:: SafeString
A ``str`` subclass that has been specifically marked as "safe" A ``str`` subclass that has been specifically marked as "safe" (requires no
(requires no further escaping) for HTML output purposes. Alias of further escaping) for HTML output purposes.
:class:`SafeText`.
.. class:: SafeText
A ``str`` subclass that has been specifically marked as "safe" for HTML
output purposes.
.. function:: mark_safe(s) .. function:: mark_safe(s)
@ -774,7 +768,7 @@ appropriate entities.
>>> mystr = '<b>Hello World</b> ' >>> mystr = '<b>Hello World</b> '
>>> mystr = mark_safe(mystr) >>> mystr = mark_safe(mystr)
>>> type(mystr) >>> type(mystr)
<class 'django.utils.safestring.SafeText'> <class 'django.utils.safestring.SafeString'>
>>> mystr = mystr.strip() # removing whitespace >>> mystr = mystr.strip() # removing whitespace
>>> type(mystr) >>> type(mystr)

View File

@ -28,7 +28,7 @@ from django.utils.formats import (
localize_input, reset_format_cache, sanitize_separators, time_format, localize_input, reset_format_cache, sanitize_separators, time_format,
) )
from django.utils.numberformat import format as nformat from django.utils.numberformat import format as nformat
from django.utils.safestring import SafeText, mark_safe from django.utils.safestring import SafeString, mark_safe
from django.utils.translation import ( from django.utils.translation import (
LANGUAGE_SESSION_KEY, activate, check_for_language, deactivate, LANGUAGE_SESSION_KEY, activate, check_for_language, deactivate,
get_language, get_language_bidi, get_language_from_request, get_language, get_language_bidi, get_language_from_request,
@ -287,10 +287,10 @@ class TranslationTests(SimpleTestCase):
s1 = mark_safe('Password') s1 = mark_safe('Password')
s2 = mark_safe('May') s2 = mark_safe('May')
with translation.override('de', deactivate=True): with translation.override('de', deactivate=True):
self.assertIs(type(gettext(s1)), SafeText) self.assertIs(type(gettext(s1)), SafeString)
self.assertIs(type(pgettext('month name', s2)), SafeText) self.assertIs(type(pgettext('month name', s2)), SafeString)
self.assertEqual('aPassword', SafeText('a') + s1) self.assertEqual('aPassword', SafeString('a') + s1)
self.assertEqual('Passworda', s1 + SafeText('a')) self.assertEqual('Passworda', s1 + SafeString('a'))
self.assertEqual('Passworda', s1 + mark_safe('a')) self.assertEqual('Passworda', s1 + mark_safe('a'))
self.assertEqual('aPassword', mark_safe('a') + s1) self.assertEqual('aPassword', mark_safe('a') + s1)
self.assertEqual('as', mark_safe('a') + mark_safe('s')) self.assertEqual('as', mark_safe('a') + mark_safe('s'))
@ -1532,7 +1532,7 @@ class TestModels(TestCase):
def test_safestr(self): def test_safestr(self):
c = Company(cents_paid=12, products_delivered=1) c = Company(cents_paid=12, products_delivered=1)
c.name = SafeText('Iñtërnâtiônàlizætiøn1') c.name = SafeString('Iñtërnâtiônàlizætiøn1')
c.save() c.save()

View File

@ -26,7 +26,7 @@ class SafeStringTest(SimpleTestCase):
def test_mark_safe_str(self): def test_mark_safe_str(self):
""" """
Calling str() on a SafeText instance doesn't lose the safe status. Calling str() on a SafeString instance doesn't lose the safe status.
""" """
s = mark_safe('a&b') s = mark_safe('a&b')
self.assertIsInstance(str(s), type(s)) self.assertIsInstance(str(s), type(s))