mirror of
https://github.com/django/django.git
synced 2024-12-01 15:42:04 +01:00
[py3] Ported django.utils.safestring.
Backwards compatibility aliases were created under Python 2.
This commit is contained in:
parent
e41c308014
commit
547b181046
@ -38,7 +38,7 @@ from django.db.backends.mysql.creation import DatabaseCreation
|
|||||||
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
||||||
from django.db.backends.mysql.validation import DatabaseValidation
|
from django.db.backends.mysql.validation import DatabaseValidation
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.safestring import SafeString, SafeUnicode
|
from django.utils.safestring import SafeBytes, SafeText
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ def adapt_datetime_with_timezone_support(value, conv):
|
|||||||
# MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
|
# MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
|
||||||
# timedelta in terms of actual behavior as they are signed and include days --
|
# timedelta in terms of actual behavior as they are signed and include days --
|
||||||
# and Django expects time, so we still need to override that. We also need to
|
# and Django expects time, so we still need to override that. We also need to
|
||||||
# add special handling for SafeUnicode and SafeString as MySQLdb's type
|
# add special handling for SafeText and SafeBytes as MySQLdb's type
|
||||||
# checking is too tight to catch those (see Django ticket #6052).
|
# checking is too tight to catch those (see Django ticket #6052).
|
||||||
# Finally, MySQLdb always returns naive datetime objects. However, when
|
# Finally, MySQLdb always returns naive datetime objects. However, when
|
||||||
# timezone support is active, Django expects timezone-aware datetime objects.
|
# timezone support is active, Django expects timezone-aware datetime objects.
|
||||||
@ -402,8 +402,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
kwargs['client_flag'] = CLIENT.FOUND_ROWS
|
kwargs['client_flag'] = CLIENT.FOUND_ROWS
|
||||||
kwargs.update(settings_dict['OPTIONS'])
|
kwargs.update(settings_dict['OPTIONS'])
|
||||||
self.connection = Database.connect(**kwargs)
|
self.connection = Database.connect(**kwargs)
|
||||||
self.connection.encoders[SafeUnicode] = self.connection.encoders[six.text_type]
|
self.connection.encoders[SafeText] = self.connection.encoders[six.text_type]
|
||||||
self.connection.encoders[SafeString] = self.connection.encoders[bytes]
|
self.connection.encoders[SafeBytes] = self.connection.encoders[bytes]
|
||||||
connection_created.send(sender=self.__class__, connection=self)
|
connection_created.send(sender=self.__class__, connection=self)
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
if new_connection:
|
if new_connection:
|
||||||
|
@ -14,7 +14,7 @@ from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
|
|||||||
from django.db.backends.postgresql_psycopg2.version import get_version
|
from django.db.backends.postgresql_psycopg2.version import get_version
|
||||||
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
from django.utils.safestring import SafeUnicode, SafeString
|
from django.utils.safestring import SafeText, SafeBytes
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
@ -29,8 +29,8 @@ DatabaseError = Database.DatabaseError
|
|||||||
IntegrityError = Database.IntegrityError
|
IntegrityError = Database.IntegrityError
|
||||||
|
|
||||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
|
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
|
||||||
psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
|
psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)
|
||||||
|
|
||||||
logger = getLogger('django.db.backends')
|
logger = getLogger('django.db.backends')
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ from django.db.backends.sqlite3.creation import DatabaseCreation
|
|||||||
from django.db.backends.sqlite3.introspection import DatabaseIntrospection
|
from django.db.backends.sqlite3.introspection import DatabaseIntrospection
|
||||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.safestring import SafeString
|
from django.utils.safestring import SafeBytes
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ if Database.version_info >= (2, 4, 1):
|
|||||||
# slow-down, this adapter is only registered for sqlite3 versions
|
# slow-down, this adapter is only registered for sqlite3 versions
|
||||||
# needing it (Python 2.6 and up).
|
# needing it (Python 2.6 and up).
|
||||||
Database.register_adapter(str, lambda s: s.decode('utf-8'))
|
Database.register_adapter(str, lambda s: s.decode('utf-8'))
|
||||||
Database.register_adapter(SafeString, lambda s: s.decode('utf-8'))
|
Database.register_adapter(SafeBytes, lambda s: s.decode('utf-8'))
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
# SQLite cannot handle us only partially reading from a cursor's result set
|
# SQLite cannot handle us only partially reading from a cursor's result set
|
||||||
|
@ -119,8 +119,8 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
|
|||||||
errors) for arg in s])
|
errors) for arg in s])
|
||||||
else:
|
else:
|
||||||
# Note: We use .decode() here, instead of six.text_type(s, encoding,
|
# Note: We use .decode() here, instead of six.text_type(s, encoding,
|
||||||
# errors), so that if s is a SafeString, it ends up being a
|
# errors), so that if s is a SafeBytes, it ends up being a
|
||||||
# SafeUnicode at the end.
|
# SafeText at the end.
|
||||||
s = s.decode(encoding, errors)
|
s = s.decode(encoding, errors)
|
||||||
except UnicodeDecodeError as e:
|
except UnicodeDecodeError as e:
|
||||||
if not isinstance(s, Exception):
|
if not isinstance(s, Exception):
|
||||||
|
@ -10,36 +10,43 @@ from django.utils import six
|
|||||||
class EscapeData(object):
|
class EscapeData(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class EscapeString(bytes, EscapeData):
|
class EscapeBytes(bytes, EscapeData):
|
||||||
"""
|
"""
|
||||||
A string that should be HTML-escaped when output.
|
A byte string that should be HTML-escaped when output.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class EscapeUnicode(six.text_type, EscapeData):
|
class EscapeText(six.text_type, EscapeData):
|
||||||
"""
|
"""
|
||||||
A unicode object that should be HTML-escaped when output.
|
A unicode string object that should be HTML-escaped when output.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if six.PY3:
|
||||||
|
EscapeString = EscapeText
|
||||||
|
else:
|
||||||
|
EscapeString = EscapeBytes
|
||||||
|
# backwards compatibility for Python 2
|
||||||
|
EscapeUnicode = EscapeText
|
||||||
|
|
||||||
class SafeData(object):
|
class SafeData(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class SafeString(bytes, SafeData):
|
class SafeBytes(bytes, SafeData):
|
||||||
"""
|
"""
|
||||||
A string 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.
|
||||||
"""
|
"""
|
||||||
def __add__(self, rhs):
|
def __add__(self, rhs):
|
||||||
"""
|
"""
|
||||||
Concatenating a safe string with another safe string or safe unicode
|
Concatenating a safe byte string with another safe byte string or safe
|
||||||
object is safe. Otherwise, the result is no longer safe.
|
unicode string is safe. Otherwise, the result is no longer safe.
|
||||||
"""
|
"""
|
||||||
t = super(SafeString, self).__add__(rhs)
|
t = super(SafeBytes, self).__add__(rhs)
|
||||||
if isinstance(rhs, SafeUnicode):
|
if isinstance(rhs, SafeText):
|
||||||
return SafeUnicode(t)
|
return SafeText(t)
|
||||||
elif isinstance(rhs, SafeString):
|
elif isinstance(rhs, SafeBytes):
|
||||||
return SafeString(t)
|
return SafeBytes(t)
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def _proxy_method(self, *args, **kwargs):
|
def _proxy_method(self, *args, **kwargs):
|
||||||
@ -51,25 +58,25 @@ class SafeString(bytes, SafeData):
|
|||||||
method = kwargs.pop('method')
|
method = kwargs.pop('method')
|
||||||
data = method(self, *args, **kwargs)
|
data = method(self, *args, **kwargs)
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
return SafeString(data)
|
return SafeBytes(data)
|
||||||
else:
|
else:
|
||||||
return SafeUnicode(data)
|
return SafeText(data)
|
||||||
|
|
||||||
decode = curry(_proxy_method, method=bytes.decode)
|
decode = curry(_proxy_method, method=bytes.decode)
|
||||||
|
|
||||||
class SafeUnicode(six.text_type, SafeData):
|
class SafeText(six.text_type, SafeData):
|
||||||
"""
|
"""
|
||||||
A unicode subclass that has been specifically marked as "safe" for HTML
|
A unicode (Python 2) / str (Python 3) subclass that has been specifically
|
||||||
output purposes.
|
marked as "safe" for HTML output purposes.
|
||||||
"""
|
"""
|
||||||
def __add__(self, rhs):
|
def __add__(self, rhs):
|
||||||
"""
|
"""
|
||||||
Concatenating a safe unicode object with another safe string or safe
|
Concatenating a safe unicode string with another safe byte string or
|
||||||
unicode object is safe. Otherwise, the result is no longer safe.
|
safe unicode string is safe. Otherwise, the result is no longer safe.
|
||||||
"""
|
"""
|
||||||
t = super(SafeUnicode, self).__add__(rhs)
|
t = super(SafeText, self).__add__(rhs)
|
||||||
if isinstance(rhs, SafeData):
|
if isinstance(rhs, SafeData):
|
||||||
return SafeUnicode(t)
|
return SafeText(t)
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def _proxy_method(self, *args, **kwargs):
|
def _proxy_method(self, *args, **kwargs):
|
||||||
@ -81,12 +88,19 @@ class SafeUnicode(six.text_type, SafeData):
|
|||||||
method = kwargs.pop('method')
|
method = kwargs.pop('method')
|
||||||
data = method(self, *args, **kwargs)
|
data = method(self, *args, **kwargs)
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
return SafeString(data)
|
return SafeBytes(data)
|
||||||
else:
|
else:
|
||||||
return SafeUnicode(data)
|
return SafeText(data)
|
||||||
|
|
||||||
encode = curry(_proxy_method, method=six.text_type.encode)
|
encode = curry(_proxy_method, method=six.text_type.encode)
|
||||||
|
|
||||||
|
if six.PY3:
|
||||||
|
SafeString = SafeText
|
||||||
|
else:
|
||||||
|
SafeString = SafeBytes
|
||||||
|
# backwards compatibility for Python 2
|
||||||
|
SafeUnicode = SafeText
|
||||||
|
|
||||||
def mark_safe(s):
|
def mark_safe(s):
|
||||||
"""
|
"""
|
||||||
Explicitly mark a string as safe for (HTML) output purposes. The returned
|
Explicitly mark a string as safe for (HTML) output purposes. The returned
|
||||||
@ -97,10 +111,10 @@ def mark_safe(s):
|
|||||||
if isinstance(s, SafeData):
|
if isinstance(s, SafeData):
|
||||||
return s
|
return s
|
||||||
if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
|
if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
|
||||||
return SafeString(s)
|
return SafeBytes(s)
|
||||||
if isinstance(s, (six.text_type, Promise)):
|
if isinstance(s, (six.text_type, Promise)):
|
||||||
return SafeUnicode(s)
|
return SafeText(s)
|
||||||
return SafeString(bytes(s))
|
return SafeString(str(s))
|
||||||
|
|
||||||
def mark_for_escaping(s):
|
def mark_for_escaping(s):
|
||||||
"""
|
"""
|
||||||
@ -113,8 +127,8 @@ def mark_for_escaping(s):
|
|||||||
if isinstance(s, (SafeData, EscapeData)):
|
if isinstance(s, (SafeData, EscapeData)):
|
||||||
return s
|
return s
|
||||||
if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
|
if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
|
||||||
return EscapeString(s)
|
return EscapeBytes(s)
|
||||||
if isinstance(s, (six.text_type, Promise)):
|
if isinstance(s, (six.text_type, Promise)):
|
||||||
return EscapeUnicode(s)
|
return EscapeText(s)
|
||||||
return EscapeString(bytes(s))
|
return EscapeBytes(bytes(s))
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ passed around inside the template code:
|
|||||||
They're commonly used for output that contains raw HTML that is intended
|
They're commonly used for output that contains raw HTML that is intended
|
||||||
to be interpreted as-is on the client side.
|
to be interpreted as-is on the client side.
|
||||||
|
|
||||||
Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
|
Internally, these strings are of type ``SafeBytes`` or ``SafeText``.
|
||||||
They share a common base class of ``SafeData``, so you can test
|
They share a common base class of ``SafeData``, so you can test
|
||||||
for them using code like:
|
for them using code like:
|
||||||
|
|
||||||
@ -204,8 +204,8 @@ passed around inside the template code:
|
|||||||
not. These strings are only escaped once, however, even if auto-escaping
|
not. These strings are only escaped once, however, even if auto-escaping
|
||||||
applies.
|
applies.
|
||||||
|
|
||||||
Internally, these strings are of type ``EscapeString`` or
|
Internally, these strings are of type ``EscapeBytes`` or
|
||||||
``EscapeUnicode``. Generally you don't have to worry about these; they
|
``EscapeText``. Generally you don't have to worry about these; they
|
||||||
exist for the implementation of the :tfilter:`escape` filter.
|
exist for the implementation of the :tfilter:`escape` filter.
|
||||||
|
|
||||||
Template filter code falls into one of two situations:
|
Template filter code falls into one of two situations:
|
||||||
|
@ -560,15 +560,29 @@ string" means that the producer of the string has already turned characters
|
|||||||
that should not be interpreted by the HTML engine (e.g. '<') into the
|
that should not be interpreted by the HTML engine (e.g. '<') into the
|
||||||
appropriate entities.
|
appropriate entities.
|
||||||
|
|
||||||
|
.. class:: SafeBytes
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
|
||||||
|
A :class:`bytes` subclass that has been specifically marked as "safe"
|
||||||
|
(requires no further escaping) for HTML output purposes.
|
||||||
|
|
||||||
.. class:: SafeString
|
.. class:: SafeString
|
||||||
|
|
||||||
A string subclass that has been specifically marked as "safe" (requires no
|
A :class:`str` subclass that has been specifically marked as "safe"
|
||||||
further escaping) for HTML output purposes.
|
(requires no further escaping) for HTML output purposes. This is
|
||||||
|
:class:`SafeBytes` on Python 2 and :class:`SafeText` on Python 3.
|
||||||
|
|
||||||
|
.. class:: SafeText
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
|
||||||
|
A :class:`str` (in Python 3) or :class:`unicode` (in Python 2) subclass
|
||||||
|
that has been specifically marked as "safe" for HTML output purposes.
|
||||||
|
|
||||||
.. class:: SafeUnicode
|
.. class:: SafeUnicode
|
||||||
|
|
||||||
A unicode subclass that has been specifically marked as "safe" for HTML
|
Historical name of :class:`SafeText`. Only available under Python 2.
|
||||||
output purposes.
|
|
||||||
|
|
||||||
.. function:: mark_safe(s)
|
.. function:: mark_safe(s)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ from django.utils.formats import (get_format, date_format, time_format,
|
|||||||
number_format)
|
number_format)
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.numberformat import format as nformat
|
from django.utils.numberformat import format as nformat
|
||||||
from django.utils.safestring import mark_safe, SafeString, SafeUnicode
|
from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.six import PY3
|
from django.utils.six import PY3
|
||||||
from django.utils.translation import (ugettext, ugettext_lazy, activate,
|
from django.utils.translation import (ugettext, ugettext_lazy, activate,
|
||||||
@ -235,9 +235,9 @@ class TranslationTests(TestCase):
|
|||||||
s = mark_safe(str('Password'))
|
s = mark_safe(str('Password'))
|
||||||
self.assertEqual(SafeString, type(s))
|
self.assertEqual(SafeString, type(s))
|
||||||
with translation.override('de', deactivate=True):
|
with translation.override('de', deactivate=True):
|
||||||
self.assertEqual(SafeUnicode, type(ugettext(s)))
|
self.assertEqual(SafeText, type(ugettext(s)))
|
||||||
self.assertEqual('aPassword', SafeString('a') + s)
|
self.assertEqual('aPassword', SafeText('a') + s)
|
||||||
self.assertEqual('Passworda', s + SafeString('a'))
|
self.assertEqual('Passworda', s + SafeText('a'))
|
||||||
self.assertEqual('Passworda', s + mark_safe('a'))
|
self.assertEqual('Passworda', s + mark_safe('a'))
|
||||||
self.assertEqual('aPassword', mark_safe('a') + s)
|
self.assertEqual('aPassword', mark_safe('a') + s)
|
||||||
self.assertEqual('as', mark_safe('a') + mark_safe('s'))
|
self.assertEqual('as', mark_safe('a') + mark_safe('s'))
|
||||||
@ -897,9 +897,9 @@ 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 = SafeUnicode('Iñtërnâtiônàlizætiøn1')
|
c.name = SafeText('Iñtërnâtiônàlizætiøn1')
|
||||||
c.save()
|
c.save()
|
||||||
c.name = SafeString('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
|
c.name = SafeBytes('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user