Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[py3] Ported django.utils.safestring.

Backwards compatibility aliases were created under Python 2.
  • Loading branch information...
commit 547b181046539f548839e42544521503fbe4d821 1 parent e41c308
Aymeric Augustin authored August 18, 2012
8  django/db/backends/mysql/base.py
@@ -38,7 +38,7 @@
38 38
 from django.db.backends.mysql.introspection import DatabaseIntrospection
39 39
 from django.db.backends.mysql.validation import DatabaseValidation
40 40
 from django.utils.functional import cached_property
41  
-from django.utils.safestring import SafeString, SafeUnicode
  41
+from django.utils.safestring import SafeBytes, SafeText
42 42
 from django.utils import six
43 43
 from django.utils import timezone
44 44
 
@@ -75,7 +75,7 @@ def adapt_datetime_with_timezone_support(value, conv):
75 75
 # MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
76 76
 # timedelta in terms of actual behavior as they are signed and include days --
77 77
 # and Django expects time, so we still need to override that. We also need to
78  
-# add special handling for SafeUnicode and SafeString as MySQLdb's type
  78
+# add special handling for SafeText and SafeBytes as MySQLdb's type
79 79
 # checking is too tight to catch those (see Django ticket #6052).
80 80
 # Finally, MySQLdb always returns naive datetime objects. However, when
81 81
 # timezone support is active, Django expects timezone-aware datetime objects.
@@ -402,8 +402,8 @@ def _cursor(self):
402 402
             kwargs['client_flag'] = CLIENT.FOUND_ROWS
403 403
             kwargs.update(settings_dict['OPTIONS'])
404 404
             self.connection = Database.connect(**kwargs)
405  
-            self.connection.encoders[SafeUnicode] = self.connection.encoders[six.text_type]
406  
-            self.connection.encoders[SafeString] = self.connection.encoders[bytes]
  405
+            self.connection.encoders[SafeText] = self.connection.encoders[six.text_type]
  406
+            self.connection.encoders[SafeBytes] = self.connection.encoders[bytes]
407 407
             connection_created.send(sender=self.__class__, connection=self)
408 408
         cursor = self.connection.cursor()
409 409
         if new_connection:
6  django/db/backends/postgresql_psycopg2/base.py
@@ -14,7 +14,7 @@
14 14
 from django.db.backends.postgresql_psycopg2.version import get_version
15 15
 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
16 16
 from django.utils.log import getLogger
17  
-from django.utils.safestring import SafeUnicode, SafeString
  17
+from django.utils.safestring import SafeText, SafeBytes
18 18
 from django.utils import six
19 19
 from django.utils.timezone import utc
20 20
 
@@ -29,8 +29,8 @@
29 29
 IntegrityError = Database.IntegrityError
30 30
 
31 31
 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
32  
-psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
33  
-psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
  32
+psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
  33
+psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)
34 34
 
35 35
 logger = getLogger('django.db.backends')
36 36
 
4  django/db/backends/sqlite3/base.py
@@ -20,7 +20,7 @@
20 20
 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
21 21
 from django.utils.dateparse import parse_date, parse_datetime, parse_time
22 22
 from django.utils.functional import cached_property
23  
-from django.utils.safestring import SafeString
  23
+from django.utils.safestring import SafeBytes
24 24
 from django.utils import six
25 25
 from django.utils import timezone
26 26
 
@@ -80,7 +80,7 @@ def decoder(conv_func):
80 80
     # slow-down, this adapter is only registered for sqlite3 versions
81 81
     # needing it (Python 2.6 and up).
82 82
     Database.register_adapter(str, lambda s: s.decode('utf-8'))
83  
-    Database.register_adapter(SafeString, lambda s: s.decode('utf-8'))
  83
+    Database.register_adapter(SafeBytes, lambda s: s.decode('utf-8'))
84 84
 
85 85
 class DatabaseFeatures(BaseDatabaseFeatures):
86 86
     # SQLite cannot handle us only partially reading from a cursor's result set
4  django/utils/encoding.py
@@ -119,8 +119,8 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
119 119
                             errors) for arg in s])
120 120
         else:
121 121
             # Note: We use .decode() here, instead of six.text_type(s, encoding,
122  
-            # errors), so that if s is a SafeString, it ends up being a
123  
-            # SafeUnicode at the end.
  122
+            # errors), so that if s is a SafeBytes, it ends up being a
  123
+            # SafeText at the end.
124 124
             s = s.decode(encoding, errors)
125 125
     except UnicodeDecodeError as e:
126 126
         if not isinstance(s, Exception):
74  django/utils/safestring.py
@@ -10,36 +10,43 @@
10 10
 class EscapeData(object):
11 11
     pass
12 12
 
13  
-class EscapeString(bytes, EscapeData):
  13
+class EscapeBytes(bytes, EscapeData):
14 14
     """
15  
-    A string that should be HTML-escaped when output.
  15
+    A byte string that should be HTML-escaped when output.
16 16
     """
17 17
     pass
18 18
 
19  
-class EscapeUnicode(six.text_type, EscapeData):
  19
+class EscapeText(six.text_type, EscapeData):
20 20
     """
21  
-    A unicode object that should be HTML-escaped when output.
  21
+    A unicode string object that should be HTML-escaped when output.
22 22
     """
23 23
     pass
24 24
 
  25
+if six.PY3:
  26
+    EscapeString = EscapeText
  27
+else:
  28
+    EscapeString = EscapeBytes
  29
+    # backwards compatibility for Python 2
  30
+    EscapeUnicode = EscapeText
  31
+
25 32
 class SafeData(object):
26 33
     pass
27 34
 
28  
-class SafeString(bytes, SafeData):
  35
+class SafeBytes(bytes, SafeData):
29 36
     """
30  
-    A string subclass that has been specifically marked as "safe" (requires no
  37
+    A bytes subclass that has been specifically marked as "safe" (requires no
31 38
     further escaping) for HTML output purposes.
32 39
     """
33 40
     def __add__(self, rhs):
34 41
         """
35  
-        Concatenating a safe string with another safe string or safe unicode
36  
-        object is safe. Otherwise, the result is no longer safe.
  42
+        Concatenating a safe byte string with another safe byte string or safe
  43
+        unicode string is safe. Otherwise, the result is no longer safe.
37 44
         """
38  
-        t = super(SafeString, self).__add__(rhs)
39  
-        if isinstance(rhs, SafeUnicode):
40  
-            return SafeUnicode(t)
41  
-        elif isinstance(rhs, SafeString):
42  
-            return SafeString(t)
  45
+        t = super(SafeBytes, self).__add__(rhs)
  46
+        if isinstance(rhs, SafeText):
  47
+            return SafeText(t)
  48
+        elif isinstance(rhs, SafeBytes):
  49
+            return SafeBytes(t)
43 50
         return t
44 51
 
45 52
     def _proxy_method(self, *args, **kwargs):
@@ -51,25 +58,25 @@ def _proxy_method(self, *args, **kwargs):
51 58
         method = kwargs.pop('method')
52 59
         data = method(self, *args, **kwargs)
53 60
         if isinstance(data, bytes):
54  
-            return SafeString(data)
  61
+            return SafeBytes(data)
55 62
         else:
56  
-            return SafeUnicode(data)
  63
+            return SafeText(data)
57 64
 
58 65
     decode = curry(_proxy_method, method=bytes.decode)
59 66
 
60  
-class SafeUnicode(six.text_type, SafeData):
  67
+class SafeText(six.text_type, SafeData):
61 68
     """
62  
-    A unicode subclass that has been specifically marked as "safe" for HTML
63  
-    output purposes.
  69
+    A unicode (Python 2) / str (Python 3) subclass that has been specifically
  70
+    marked as "safe" for HTML output purposes.
64 71
     """
65 72
     def __add__(self, rhs):
66 73
         """
67  
-        Concatenating a safe unicode object with another safe string or safe
68  
-        unicode object is safe. Otherwise, the result is no longer safe.
  74
+        Concatenating a safe unicode string with another safe byte string or
  75
+        safe unicode string is safe. Otherwise, the result is no longer safe.
69 76
         """
70  
-        t = super(SafeUnicode, self).__add__(rhs)
  77
+        t = super(SafeText, self).__add__(rhs)
71 78
         if isinstance(rhs, SafeData):
72  
-            return SafeUnicode(t)
  79
+            return SafeText(t)
73 80
         return t
74 81
 
75 82
     def _proxy_method(self, *args, **kwargs):
@@ -81,12 +88,19 @@ def _proxy_method(self, *args, **kwargs):
81 88
         method = kwargs.pop('method')
82 89
         data = method(self, *args, **kwargs)
83 90
         if isinstance(data, bytes):
84  
-            return SafeString(data)
  91
+            return SafeBytes(data)
85 92
         else:
86  
-            return SafeUnicode(data)
  93
+            return SafeText(data)
87 94
 
88 95
     encode = curry(_proxy_method, method=six.text_type.encode)
89 96
 
  97
+if six.PY3:
  98
+    SafeString = SafeText
  99
+else:
  100
+    SafeString = SafeBytes
  101
+    # backwards compatibility for Python 2
  102
+    SafeUnicode = SafeText
  103
+
90 104
 def mark_safe(s):
91 105
     """
92 106
     Explicitly mark a string as safe for (HTML) output purposes. The returned
@@ -97,10 +111,10 @@ def mark_safe(s):
97 111
     if isinstance(s, SafeData):
98 112
         return s
99 113
     if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
100  
-        return SafeString(s)
  114
+        return SafeBytes(s)
101 115
     if isinstance(s, (six.text_type, Promise)):
102  
-        return SafeUnicode(s)
103  
-    return SafeString(bytes(s))
  116
+        return SafeText(s)
  117
+    return SafeString(str(s))
104 118
 
105 119
 def mark_for_escaping(s):
106 120
     """
@@ -113,8 +127,8 @@ def mark_for_escaping(s):
113 127
     if isinstance(s, (SafeData, EscapeData)):
114 128
         return s
115 129
     if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_bytes):
116  
-        return EscapeString(s)
  130
+        return EscapeBytes(s)
117 131
     if isinstance(s, (six.text_type, Promise)):
118  
-        return EscapeUnicode(s)
119  
-    return EscapeString(bytes(s))
  132
+        return EscapeText(s)
  133
+    return EscapeBytes(bytes(s))
120 134
 
6  docs/howto/custom-template-tags.txt
@@ -189,7 +189,7 @@ passed around inside the template code:
189 189
   They're commonly used for output that contains raw HTML that is intended
190 190
   to be interpreted as-is on the client side.
191 191
 
192  
-  Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
  192
+  Internally, these strings are of type ``SafeBytes`` or ``SafeText``.
193 193
   They share a common base class of ``SafeData``, so you can test
194 194
   for them using code like:
195 195
 
@@ -204,8 +204,8 @@ passed around inside the template code:
204 204
   not. These strings are only escaped once, however, even if auto-escaping
205 205
   applies.
206 206
 
207  
-  Internally, these strings are of type ``EscapeString`` or
208  
-  ``EscapeUnicode``. Generally you don't have to worry about these; they
  207
+  Internally, these strings are of type ``EscapeBytes`` or
  208
+  ``EscapeText``. Generally you don't have to worry about these; they
209 209
   exist for the implementation of the :tfilter:`escape` filter.
210 210
 
211 211
 Template filter code falls into one of two situations:
22  docs/ref/utils.txt
@@ -560,15 +560,29 @@ string" means that the producer of the string has already turned characters
560 560
 that should not be interpreted by the HTML engine (e.g. '<') into the
561 561
 appropriate entities.
562 562
 
  563
+.. class:: SafeBytes
  564
+
  565
+    .. versionadded:: 1.5
  566
+
  567
+    A :class:`bytes` subclass that has been specifically marked as "safe"
  568
+    (requires no further escaping) for HTML output purposes.
  569
+
563 570
 .. class:: SafeString
564 571
 
565  
-    A string subclass that has been specifically marked as "safe" (requires no
566  
-    further escaping) for HTML output purposes.
  572
+    A :class:`str` subclass that has been specifically marked as "safe"
  573
+    (requires no further escaping) for HTML output purposes. This is
  574
+    :class:`SafeBytes` on Python 2 and :class:`SafeText` on Python 3.
  575
+
  576
+.. class:: SafeText
  577
+
  578
+    .. versionadded:: 1.5
  579
+
  580
+    A :class:`str` (in Python 3) or :class:`unicode` (in Python 2) subclass
  581
+    that has been specifically marked as "safe" for HTML output purposes.
567 582
 
568 583
 .. class:: SafeUnicode
569 584
 
570  
-    A unicode subclass that has been specifically marked as "safe" for HTML
571  
-    output purposes.
  585
+    Historical name of :class:`SafeText`. Only available under Python 2.
572 586
 
573 587
 .. function:: mark_safe(s)
574 588
 
12  tests/regressiontests/i18n/tests.py
@@ -18,7 +18,7 @@
18 18
     number_format)
19 19
 from django.utils.importlib import import_module
20 20
 from django.utils.numberformat import format as nformat
21  
-from django.utils.safestring import mark_safe, SafeString, SafeUnicode
  21
+from django.utils.safestring import mark_safe, SafeBytes, SafeString, SafeText
22 22
 from django.utils import six
23 23
 from django.utils.six import PY3
24 24
 from django.utils.translation import (ugettext, ugettext_lazy, activate,
@@ -235,9 +235,9 @@ def test_safe_status(self):
235 235
         s = mark_safe(str('Password'))
236 236
         self.assertEqual(SafeString, type(s))
237 237
         with translation.override('de', deactivate=True):
238  
-            self.assertEqual(SafeUnicode, type(ugettext(s)))
239  
-        self.assertEqual('aPassword', SafeString('a') + s)
240  
-        self.assertEqual('Passworda', s + SafeString('a'))
  238
+            self.assertEqual(SafeText, type(ugettext(s)))
  239
+        self.assertEqual('aPassword', SafeText('a') + s)
  240
+        self.assertEqual('Passworda', s + SafeText('a'))
241 241
         self.assertEqual('Passworda', s + mark_safe('a'))
242 242
         self.assertEqual('aPassword', mark_safe('a') + s)
243 243
         self.assertEqual('as', mark_safe('a') + mark_safe('s'))
@@ -897,9 +897,9 @@ def test_lazy(self):
897 897
 
898 898
     def test_safestr(self):
899 899
         c = Company(cents_paid=12, products_delivered=1)
900  
-        c.name = SafeUnicode('Iñtërnâtiônàlizætiøn1')
  900
+        c.name = SafeText('Iñtërnâtiônàlizætiøn1')
901 901
         c.save()
902  
-        c.name = SafeString('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
  902
+        c.name = SafeBytes('Iñtërnâtiônàlizætiøn1'.encode('utf-8'))
903 903
         c.save()
904 904
 
905 905
 

0 notes on commit 547b181

Please sign in to comment.
Something went wrong with that request. Please try again.