Loading django/db/backends/mysql/base.py +4 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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: Loading django/db/backends/postgresql_psycopg2/base.py +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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') Loading django/db/backends/sqlite3/base.py +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading django/utils/encoding.py +2 −2 Original line number Diff line number Diff line Loading @@ -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): Loading django/utils/safestring.py +44 −30 Original line number Diff line number Diff line Loading @@ -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): Loading @@ -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): Loading @@ -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 Loading @@ -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): """ Loading @@ -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
django/db/backends/mysql/base.py +4 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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: Loading
django/db/backends/postgresql_psycopg2/base.py +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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') Loading
django/db/backends/sqlite3/base.py +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
django/utils/encoding.py +2 −2 Original line number Diff line number Diff line Loading @@ -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): Loading
django/utils/safestring.py +44 −30 Original line number Diff line number Diff line Loading @@ -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): Loading @@ -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): Loading @@ -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 Loading @@ -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): """ Loading @@ -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))