Browse Source

Refs #23919 -- Removed usage of obsolete SafeBytes class

The class will be removed as part of #27753.
Thanks Tim Graham for the review.
Claude Paroz 8 years ago
parent
commit
52138b1fd0

+ 1 - 2
django/db/backends/postgresql/base.py

@@ -13,7 +13,7 @@ from django.db import DEFAULT_DB_ALIAS
 from django.db.backends.base.base import BaseDatabaseWrapper
 from django.db.utils import DatabaseError as WrappedDatabaseError
 from django.utils.functional import cached_property
-from django.utils.safestring import SafeBytes, SafeText
+from django.utils.safestring import SafeText
 
 try:
     import psycopg2 as Database
@@ -44,7 +44,6 @@ from .schema import DatabaseSchemaEditor                    # NOQA isort:skip
 from .utils import utc_tzinfo_factory                       # NOQA isort:skip
 from .version import get_version                            # NOQA isort:skip
 
-psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
 psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)
 psycopg2.extras.register_uuid()
 

+ 4 - 9
django/utils/encoding.py

@@ -68,10 +68,7 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
             else:
                 s = str(s)
         else:
-            # Note: We use .decode() here, instead of str(s, encoding,
-            # errors), so that if s is a SafeBytes, it ends up being a
-            # SafeText at the end.
-            s = s.decode(encoding, errors)
+            str(s, encoding, errors)
     except UnicodeDecodeError as e:
         if not isinstance(s, Exception):
             raise DjangoUnicodeDecodeError(s, *e.args)
@@ -209,7 +206,7 @@ def escape_uri_path(path):
     # and "?" according to section 3.3 of RFC 2396.
     # The reason for not subtracting and escaping "/" is that we are escaping
     # the entire path, not a path segment.
-    return quote(force_bytes(path), safe=b"/:@&+$,-_.!~*'()")
+    return quote(path, safe="/:@&+$,-_.!~*'()")
 
 
 def repercent_broken_unicode(path):
@@ -231,20 +228,18 @@ def filepath_to_uri(path):
     """Convert a file system path to a URI portion that is suitable for
     inclusion in a URL.
 
-    Assume the input is either UTF-8 bytes or a string.
-
     This method will encode certain chars that would normally be recognized as
     special chars for URIs.  Note that this method does not encode the '
     character, as it is a valid character within URIs.  See
     encodeURIComponent() JavaScript function for more details.
 
-    Returns an ASCII string containing the encoded result.
+    Return a string containing the result.
     """
     if path is None:
         return path
     # I know about `os.sep` and `os.altsep` but I want to leave
     # some flexibility for hardcoding separators.
-    return quote(force_bytes(path).replace(b"\\", b"/"), safe=b"/~!*()'")
+    return quote(path.replace("\\", "/"), safe="/~!*()'")
 
 
 def get_system_encoding():

+ 5 - 32
django/utils/safestring.py

@@ -5,7 +5,7 @@ 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.
 """
 
-from django.utils.functional import Promise, curry, wraps
+from django.utils.functional import Promise, wraps
 
 
 class SafeData:
@@ -22,6 +22,9 @@ class SafeBytes(bytes, SafeData):
     """
     A bytes subclass that has been specifically marked as "safe" (requires no
     further escaping) for HTML output purposes.
+
+    Kept in Django 2.0 for usage by apps supporting Python 2. Shouldn't be used
+    in Django anymore.
     """
     def __add__(self, rhs):
         """
@@ -35,20 +38,6 @@ class SafeBytes(bytes, SafeData):
             return SafeBytes(t)
         return t
 
-    def _proxy_method(self, *args, **kwargs):
-        """
-        Wrap a call to a normal bytes method up so that the result is safe.
-        The method that is being wrapped is passed in the 'method' argument.
-        """
-        method = kwargs.pop('method')
-        data = method(self, *args, **kwargs)
-        if isinstance(data, bytes):
-            return SafeBytes(data)
-        else:
-            return SafeText(data)
-
-    decode = curry(_proxy_method, method=bytes.decode)
-
 
 class SafeText(str, SafeData):
     """
@@ -65,20 +54,6 @@ class SafeText(str, SafeData):
             return SafeText(t)
         return t
 
-    def _proxy_method(self, *args, **kwargs):
-        """
-        Wrap a call to a normal str method up so that the result is safe.
-        The method that is being wrapped is passed in the 'method' argument.
-        """
-        method = kwargs.pop('method')
-        data = method(self, *args, **kwargs)
-        if isinstance(data, bytes):
-            return SafeBytes(data)
-        else:
-            return SafeText(data)
-
-    encode = curry(_proxy_method, method=str.encode)
-
 
 SafeString = SafeText
 
@@ -101,10 +76,8 @@ def mark_safe(s):
     """
     if hasattr(s, '__html__'):
         return s
-    if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
-        return SafeBytes(s)
     if isinstance(s, (str, Promise)):
         return SafeText(s)
     if callable(s):
         return _safety_decorator(mark_safe, s)
-    return SafeString(str(s))
+    return SafeText(str(s))

+ 6 - 4
docs/howto/custom-template-tags.txt

@@ -199,11 +199,13 @@ passed around inside the template code:
   They're commonly used for output that contains raw HTML that is intended
   to be interpreted as-is on the client side.
 
-  Internally, these strings are of type ``SafeBytes`` or ``SafeText``.
-  They share a common base class of ``SafeData``, so you can test
-  for them using code like::
+  Internally, these strings are of type
+  :class:`~django.utils.safestring.SafeText`. You can test for them
+  using code like::
 
-      if isinstance(value, SafeData):
+      from django.utils.safestring import SafeText
+
+      if isinstance(value, SafeText):
           # Do something with the "safe" string.
           ...
 

+ 1 - 9
docs/ref/utils.txt

@@ -763,20 +763,12 @@ 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
 appropriate entities.
 
-.. class:: SafeBytes
-
-    A ``bytes`` subclass that has been specifically marked as "safe"
-    (requires no further escaping) for HTML output purposes.
-
 .. class:: SafeString
 
     A ``str`` subclass that has been specifically marked as "safe"
     (requires no further escaping) for HTML output purposes. Alias of
     :class:`SafeText`.
 
-    Alias of :class:`SafeBytes` on Python 2 (in older versions of Django that
-    support it).
-
 .. class:: SafeText
 
     A ``str`` subclass that has been specifically marked as "safe" for HTML
@@ -799,7 +791,7 @@ appropriate entities.
         >>> mystr = '<b>Hello World</b>   '
         >>> mystr = mark_safe(mystr)
         >>> type(mystr)
-        <class 'django.utils.safestring.SafeBytes'>
+        <class 'django.utils.safestring.SafeText'>
 
         >>> mystr = mystr.strip()  # removing whitespace
         >>> type(mystr)

+ 10 - 0
docs/releases/2.0.txt

@@ -205,6 +205,16 @@ Validators
 Backwards incompatible changes in 2.0
 =====================================
 
+Removed support for bytestrings in some places
+----------------------------------------------
+
+To support native Python 2 strings, older Django versions had to accept both
+bytestrings and unicode strings. Now that Python 2 support is dropped,
+bytestrings should only be encountered around input/output boundaries (handling
+of binary fields or HTTP streams, for example). You might have to update your
+code to limit bytestring usage to a minimum, as Django no longer accepts
+bytestrings in certain code paths.
+
 Database backend API
 --------------------
 

+ 1 - 3
tests/i18n/tests.py

@@ -20,7 +20,7 @@ from django.utils.formats import (
     localize_input, reset_format_cache, sanitize_separators, time_format,
 )
 from django.utils.numberformat import format as nformat
-from django.utils.safestring import SafeBytes, SafeText
+from django.utils.safestring import SafeText
 from django.utils.translation import (
     LANGUAGE_SESSION_KEY, activate, check_for_language, deactivate,
     get_language, get_language_from_request, get_language_info, gettext_lazy,
@@ -1280,8 +1280,6 @@ class TestModels(TestCase):
         c = Company(cents_paid=12, products_delivered=1)
         c.name = SafeText('Iñtërnâtiônàlizætiøn1')
         c.save()
-        c.name = SafeBytes('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
-        c.save()
 
 
 class TestLanguageInfo(SimpleTestCase):

+ 0 - 4
tests/utils_tests/test_encoding.py

@@ -62,10 +62,6 @@ class TestRFC3987IEncodingUtils(unittest.TestCase):
 
     def test_filepath_to_uri(self):
         self.assertEqual(filepath_to_uri('upload\\чубака.mp4'), 'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4')
-        self.assertEqual(
-            filepath_to_uri('upload\\чубака.mp4'.encode('utf-8')),
-            'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4'
-        )
 
     def test_iri_to_uri(self):
         cases = [

+ 1 - 6
tests/utils_tests/test_safestring.py

@@ -1,12 +1,9 @@
 from django.template import Context, Template
 from django.test import SimpleTestCase
 from django.utils import html, text
-from django.utils.encoding import force_bytes
-from django.utils.functional import lazy, lazystr
+from django.utils.functional import lazystr
 from django.utils.safestring import SafeData, mark_safe
 
-lazybytes = lazy(force_bytes, bytes)
-
 
 class customescape(str):
     def __html__(self):
@@ -37,10 +34,8 @@ class SafeStringTest(SimpleTestCase):
 
     def test_mark_safe_lazy(self):
         s = lazystr('a&b')
-        b = lazybytes(b'a&b')
 
         self.assertIsInstance(mark_safe(s), SafeData)
-        self.assertIsInstance(mark_safe(b), SafeData)
         self.assertRenderEqual('{{ s }}', 'a&b', s=mark_safe(s))
 
     def test_mark_safe_object_implementing_dunder_str(self):