Commit 547b1810 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

[py3] Ported django.utils.safestring.

Backwards compatibility aliases were created under Python 2.
parent e41c3080
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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.validation import DatabaseValidation
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 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
# 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
# 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).
# Finally, MySQLdb always returns naive datetime objects. However, when
# timezone support is active, Django expects timezone-aware datetime objects.
@@ -402,8 +402,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
            kwargs['client_flag'] = CLIENT.FOUND_ROWS
            kwargs.update(settings_dict['OPTIONS'])
            self.connection = Database.connect(**kwargs)
            self.connection.encoders[SafeUnicode] = self.connection.encoders[six.text_type]
            self.connection.encoders[SafeString] = self.connection.encoders[bytes]
            self.connection.encoders[SafeText] = self.connection.encoders[six.text_type]
            self.connection.encoders[SafeBytes] = self.connection.encoders[bytes]
            connection_created.send(sender=self.__class__, connection=self)
        cursor = self.connection.cursor()
        if new_connection:
+3 −3
Original line number Diff line number Diff line
@@ -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.introspection import DatabaseIntrospection
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.timezone import utc

@@ -29,8 +29,8 @@ DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)

logger = getLogger('django.db.backends')

+2 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ from django.db.backends.sqlite3.creation import DatabaseCreation
from django.db.backends.sqlite3.introspection import DatabaseIntrospection
from django.utils.dateparse import parse_date, parse_datetime, parse_time
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 timezone

@@ -80,7 +80,7 @@ if Database.version_info >= (2, 4, 1):
    # slow-down, this adapter is only registered for sqlite3 versions
    # needing it (Python 2.6 and up).
    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):
    # SQLite cannot handle us only partially reading from a cursor's result set
+2 −2
Original line number Diff line number Diff line
@@ -119,8 +119,8 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
                            errors) for arg in s])
        else:
            # 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
            # SafeUnicode at the end.
            # errors), so that if s is a SafeBytes, it ends up being a
            # SafeText at the end.
            s = s.decode(encoding, errors)
    except UnicodeDecodeError as e:
        if not isinstance(s, Exception):
+44 −30
Original line number Diff line number Diff line
@@ -10,36 +10,43 @@ from django.utils import six
class EscapeData(object):
    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

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

if six.PY3:
    EscapeString = EscapeText
else:
    EscapeString = EscapeBytes
    # backwards compatibility for Python 2
    EscapeUnicode = EscapeText

class SafeData(object):
    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.
    """
    def __add__(self, rhs):
        """
        Concatenating a safe string with another safe string or safe unicode
        object is safe. Otherwise, the result is no longer safe.
        Concatenating a safe byte string with another safe byte string or safe
        unicode string is safe. Otherwise, the result is no longer safe.
        """
        t = super(SafeString, self).__add__(rhs)
        if isinstance(rhs, SafeUnicode):
            return SafeUnicode(t)
        elif isinstance(rhs, SafeString):
            return SafeString(t)
        t = super(SafeBytes, self).__add__(rhs)
        if isinstance(rhs, SafeText):
            return SafeText(t)
        elif isinstance(rhs, SafeBytes):
            return SafeBytes(t)
        return t

    def _proxy_method(self, *args, **kwargs):
@@ -51,25 +58,25 @@ class SafeString(bytes, SafeData):
        method = kwargs.pop('method')
        data = method(self, *args, **kwargs)
        if isinstance(data, bytes):
            return SafeString(data)
            return SafeBytes(data)
        else:
            return SafeUnicode(data)
            return SafeText(data)

    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
    output purposes.
    A unicode (Python 2) / str (Python 3) subclass that has been specifically
    marked as "safe" for HTML output purposes.
    """
    def __add__(self, rhs):
        """
        Concatenating a safe unicode object with another safe string or safe
        unicode object is safe. Otherwise, the result is no longer safe.
        Concatenating a safe unicode string with another safe byte string or
        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):
            return SafeUnicode(t)
            return SafeText(t)
        return t

    def _proxy_method(self, *args, **kwargs):
@@ -81,12 +88,19 @@ class SafeUnicode(six.text_type, SafeData):
        method = kwargs.pop('method')
        data = method(self, *args, **kwargs)
        if isinstance(data, bytes):
            return SafeString(data)
            return SafeBytes(data)
        else:
            return SafeUnicode(data)
            return SafeText(data)

    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):
    """
    Explicitly mark a string as safe for (HTML) output purposes. The returned
@@ -97,10 +111,10 @@ def mark_safe(s):
    if isinstance(s, SafeData):
        return s
    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)):
        return SafeUnicode(s)
    return SafeString(bytes(s))
        return SafeText(s)
    return SafeString(str(s))

def mark_for_escaping(s):
    """
@@ -113,8 +127,8 @@ def mark_for_escaping(s):
    if isinstance(s, (SafeData, EscapeData)):
        return s
    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)):
        return EscapeUnicode(s)
    return EscapeString(bytes(s))
        return EscapeText(s)
    return EscapeBytes(bytes(s))
Loading