summaryrefslogtreecommitdiff
path: root/django/utils/encoding.py
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
committerAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
commitb546e7eb633022ee1962570387f22fb2bcea46ed (patch)
treef87f4a2d68fb66afae39148fa35489930710b623 /django/utils/encoding.py
parentcd583d6dbd222ae61331a6965b0e1fc86c974c50 (diff)
parentcff911f4ba3b3e6393c58da5131ce8b188a68f0c (diff)
Merge branch 'master' into schema-alteration
Diffstat (limited to 'django/utils/encoding.py')
-rw-r--r--django/utils/encoding.py49
1 files changed, 44 insertions, 5 deletions
diff --git a/django/utils/encoding.py b/django/utils/encoding.py
index eb60cfde8b..3b284f3ed0 100644
--- a/django/utils/encoding.py
+++ b/django/utils/encoding.py
@@ -8,6 +8,7 @@ try:
from urllib.parse import quote
except ImportError: # Python 2
from urllib import quote
+import warnings
from django.utils.functional import Promise
from django.utils import six
@@ -32,6 +33,12 @@ class StrAndUnicode(object):
Useful as a mix-in. If you support Python 2 and 3 with a single code base,
you can inherit this mix-in and just define __unicode__.
"""
+ def __init__(self, *args, **kwargs):
+ warnings.warn("StrAndUnicode is deprecated. Define a __str__ method "
+ "and apply the @python_2_unicode_compatible decorator "
+ "instead.", PendingDeprecationWarning, stacklevel=2)
+ super(StrAndUnicode, self).__init__(*args, **kwargs)
+
if six.PY3:
def __str__(self):
return self.__unicode__()
@@ -39,6 +46,19 @@ class StrAndUnicode(object):
def __str__(self):
return self.__unicode__().encode('utf-8')
+def python_2_unicode_compatible(klass):
+ """
+ A decorator that defines __unicode__ and __str__ methods under Python 2.
+ Under Python 3 it does nothing.
+
+ To support Python 2 and 3 with a single code base, define a __str__ method
+ returning text and apply this decorator to the class.
+ """
+ if not six.PY3:
+ klass.__unicode__ = klass.__str__
+ klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+ return klass
+
def smart_text(s, encoding='utf-8', strings_only=False, errors='strict'):
"""
Returns a text object representing 's' -- unicode on Python 2 and str on
@@ -99,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):
@@ -121,6 +141,19 @@ def smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
If strings_only is True, don't convert (some) non-string-like objects.
"""
+ if isinstance(s, Promise):
+ # The input is the result of a gettext_lazy() call.
+ return s
+ return force_bytes(s, encoding, strings_only, errors)
+
+
+def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
+ """
+ Similar to smart_bytes, except that lazy instances are resolved to
+ strings, rather than kept as lazy objects.
+
+ If strings_only is True, don't convert (some) non-string-like objects.
+ """
if isinstance(s, bytes):
if encoding == 'utf-8':
return s
@@ -141,7 +174,7 @@ def smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
# An Exception subclass containing non-ASCII data that doesn't
# know how to print itself properly. We shouldn't raise a
# further exception.
- return ' '.join([smart_bytes(arg, encoding, strings_only,
+ return b' '.join([force_bytes(arg, encoding, strings_only,
errors) for arg in s])
return six.text_type(s).encode(encoding, errors)
else:
@@ -149,8 +182,10 @@ def smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
if six.PY3:
smart_str = smart_text
+ force_str = force_text
else:
smart_str = smart_bytes
+ force_str = force_bytes
# backwards compatibility for Python 2
smart_unicode = smart_text
force_unicode = force_text
@@ -161,6 +196,10 @@ Apply smart_text in Python 3 and smart_bytes in Python 2.
This is suitable for writing to sys.stdout (for instance).
"""
+force_str.__doc__ = """\
+Apply force_text in Python 3 and force_bytes in Python 2.
+"""
+
def iri_to_uri(iri):
"""
Convert an Internationalized Resource Identifier (IRI) portion to a URI
@@ -186,7 +225,7 @@ def iri_to_uri(iri):
# converted.
if iri is None:
return iri
- return quote(smart_bytes(iri), safe=b"/#%[]=:;$&()+,!?*@'~")
+ return quote(force_bytes(iri), safe=b"/#%[]=:;$&()+,!?*@'~")
def filepath_to_uri(path):
"""Convert an file system path to a URI portion that is suitable for
@@ -205,7 +244,7 @@ def filepath_to_uri(path):
return path
# I know about `os.sep` and `os.altsep` but I want to leave
# some flexibility for hardcoding separators.
- return quote(smart_bytes(path).replace("\\", "/"), safe=b"/~!*()'")
+ return quote(force_bytes(path.replace("\\", "/")), safe=b"/~!*()'")
# The encoding of the default system locale but falls back to the
# given fallback encoding if the encoding is unsupported by python or could