diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-07-20 14:48:51 +0200 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2012-07-22 09:29:54 +0200 |
| commit | bdca5ea345c548a82a80d198906818c9ccbef896 (patch) | |
| tree | 5c3f5fe5ad2522175d67b96a1fce1ff1763ba125 /django | |
| parent | 3cb2457f46b3e40ff6b6acffcb3fd44cbea091e5 (diff) | |
[py3] Replaced unicode/str by six.text_type/bytes.
Diffstat (limited to 'django')
48 files changed, 185 insertions, 149 deletions
diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 11b14dcb51..1bc843cdf9 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -189,7 +189,7 @@ class AdminReadonlyField(object): if value is None: result_repr = EMPTY_CHANGELIST_VALUE elif isinstance(f.rel, ManyToManyRel): - result_repr = ", ".join(map(unicode, value.all())) + result_repr = ", ".join(map(six.text_type, value.all())) else: result_repr = display_for_field(value, f) return conditional_escape(result_repr) diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py index a529bacd18..16bdfe0566 100644 --- a/django/contrib/admin/util.py +++ b/django/contrib/admin/util.py @@ -275,10 +275,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False): except models.FieldDoesNotExist: if name == "__unicode__": label = force_unicode(model._meta.verbose_name) - attr = unicode + attr = six.text_type elif name == "__str__": label = smart_str(model._meta.verbose_name) - attr = str + attr = bytes else: if callable(name): attr = name diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 37f286d0d4..550ed0f7e2 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -15,6 +15,7 @@ from django.utils.text import Truncator from django.utils.translation import ugettext as _ from django.utils.safestring import mark_safe from django.utils.encoding import force_unicode +from django.utils import six class FilteredSelectMultiple(forms.SelectMultiple): @@ -121,7 +122,7 @@ def url_params_from_lookup_dict(lookups): # See django.db.fields.BooleanField.get_prep_lookup v = ('0', '1')[v] else: - v = unicode(v) + v = six.text_type(v) items.append((k, v)) params.update(dict(items)) return params diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 244721065d..95a7494d38 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -8,6 +8,7 @@ from django.db import models from django.db.models.manager import EmptyManager from django.utils.crypto import get_random_string from django.utils.encoding import smart_str +from django.utils import six from django.utils.translation import ugettext_lazy as _ from django.utils import timezone @@ -79,9 +80,9 @@ class Permission(models.Model): def __unicode__(self): return "%s | %s | %s" % ( - unicode(self.content_type.app_label), - unicode(self.content_type), - unicode(self.name)) + six.text_type(self.content_type.app_label), + six.text_type(self.content_type), + six.text_type(self.name)) def natural_key(self): return (self.codename,) + self.content_type.natural_key() @@ -421,7 +422,7 @@ class AnonymousUser(object): return 'AnonymousUser' def __str__(self): - return unicode(self).encode('utf-8') + return six.text_type(self).encode('utf-8') def __eq__(self, other): return isinstance(other, self.__class__) diff --git a/django/contrib/auth/tokens.py b/django/contrib/auth/tokens.py index fcc8c94011..9b2eda83d4 100644 --- a/django/contrib/auth/tokens.py +++ b/django/contrib/auth/tokens.py @@ -2,6 +2,7 @@ from datetime import date from django.conf import settings from django.utils.http import int_to_base36, base36_to_int from django.utils.crypto import constant_time_compare, salted_hmac +from django.utils import six class PasswordResetTokenGenerator(object): """ @@ -56,8 +57,8 @@ class PasswordResetTokenGenerator(object): # Ensure results are consistent across DB backends login_timestamp = user.last_login.replace(microsecond=0, tzinfo=None) - value = (unicode(user.id) + user.password + - unicode(login_timestamp) + unicode(timestamp)) + value = (six.text_type(user.id) + user.password + + six.text_type(login_timestamp) + six.text_type(timestamp)) hash = salted_hmac(key_salt, value).hexdigest()[::2] return "%s-%s" % (ts_b36, hash) diff --git a/django/contrib/contenttypes/tests.py b/django/contrib/contenttypes/tests.py index e9caa20cf2..1ecabc16e9 100644 --- a/django/contrib/contenttypes/tests.py +++ b/django/contrib/contenttypes/tests.py @@ -9,6 +9,7 @@ from django.contrib.sites.models import Site from django.http import HttpRequest, Http404 from django.test import TestCase from django.utils.encoding import smart_str +from django.utils import six class ConcreteModel(models.Model): @@ -271,4 +272,4 @@ class ContentTypesTests(TestCase): app_label = 'contenttypes', model = 'OldModel', ) - self.assertEqual(unicode(ct), 'Old model') + self.assertEqual(six.text_type(ct), 'Old model') diff --git a/django/contrib/formtools/wizard/views.py b/django/contrib/formtools/wizard/views.py index 6222d1ddab..466af1cac9 100644 --- a/django/contrib/formtools/wizard/views.py +++ b/django/contrib/formtools/wizard/views.py @@ -7,6 +7,7 @@ from django.forms import formsets, ValidationError from django.views.generic import TemplateView from django.utils.datastructures import SortedDict from django.utils.decorators import classonlymethod +from django.utils import six from django.contrib.formtools.wizard.storage import get_storage from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured @@ -157,10 +158,10 @@ class WizardView(TemplateView): if isinstance(form, (list, tuple)): # if the element is a tuple, add the tuple to the new created # sorted dictionary. - init_form_list[unicode(form[0])] = form[1] + init_form_list[six.text_type(form[0])] = form[1] else: # if not, add the form with a zero based counter as unicode - init_form_list[unicode(i)] = form + init_form_list[six.text_type(i)] = form # walk through the new created list of forms for form in init_form_list.itervalues(): diff --git a/django/contrib/gis/db/backends/base.py b/django/contrib/gis/db/backends/base.py index 26e97622a8..d9f3546cff 100644 --- a/django/contrib/gis/db/backends/base.py +++ b/django/contrib/gis/db/backends/base.py @@ -4,6 +4,7 @@ Base/mixin classes for the spatial backend database operations and the """ import re from django.contrib.gis import gdal +from django.utils import six class BaseSpatialOperations(object): """ @@ -88,7 +89,7 @@ class BaseSpatialOperations(object): # For quoting column values, rather than columns. def geo_quote_name(self, name): - if isinstance(name, unicode): + if isinstance(name, six.text_type): name = name.encode('ascii') return "'%s'" % name @@ -330,6 +331,6 @@ class SpatialRefSysMixin(object): it will be 'pretty' OGC WKT. """ try: - return unicode(self.srs) + return six.text_type(self.srs) except: - return unicode(self.wkt) + return six.text_type(self.wkt) diff --git a/django/contrib/gis/db/backends/util.py b/django/contrib/gis/db/backends/util.py index b899934a01..648fcfe963 100644 --- a/django/contrib/gis/db/backends/util.py +++ b/django/contrib/gis/db/backends/util.py @@ -12,7 +12,7 @@ def gqn(val): backend quotename function). """ if isinstance(val, six.string_types): - if isinstance(val, unicode): val = val.encode('ascii') + if isinstance(val, six.text_type): val = val.encode('ascii') return "'%s'" % val else: return str(val) diff --git a/django/contrib/gis/gdal/geometries.py b/django/contrib/gis/gdal/geometries.py index f38aeba838..4ad8f91d06 100644 --- a/django/contrib/gis/gdal/geometries.py +++ b/django/contrib/gis/gdal/geometries.py @@ -81,7 +81,7 @@ class OGRGeometry(GDALBase): # Constructing the geometry, if str_instance: # Checking if unicode - if isinstance(geom_input, unicode): + if isinstance(geom_input, six.text_type): # Encoding to ASCII, WKT or HEX doesn't need any more. geom_input = geom_input.encode('ascii') diff --git a/django/contrib/gis/gdal/srs.py b/django/contrib/gis/gdal/srs.py index 6003ce75ad..cdeaaca690 100644 --- a/django/contrib/gis/gdal/srs.py +++ b/django/contrib/gis/gdal/srs.py @@ -56,7 +56,7 @@ class SpatialReference(GDALBase): if isinstance(srs_input, six.string_types): # Encoding to ASCII if unicode passed in. - if isinstance(srs_input, unicode): + if isinstance(srs_input, six.text_type): srs_input = srs_input.encode('ascii') try: # If SRID is a string, e.g., '4326', then make acceptable diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py index 703b11bc02..4e5409de1d 100644 --- a/django/contrib/gis/geos/geometry.py +++ b/django/contrib/gis/geos/geometry.py @@ -55,7 +55,7 @@ class GEOSGeometry(GEOSBase, ListMixin): (SRID) number for this Geometry. If not set, the SRID will be None. """ if isinstance(geo_input, six.string_types): - if isinstance(geo_input, unicode): + if isinstance(geo_input, six.text_type): # Encoding to ASCII, WKT or HEXEWKB doesn't need any more. geo_input = geo_input.encode('ascii') diff --git a/django/contrib/gis/geos/tests/test_io.py b/django/contrib/gis/geos/tests/test_io.py index b39d705f03..ebf178a807 100644 --- a/django/contrib/gis/geos/tests/test_io.py +++ b/django/contrib/gis/geos/tests/test_io.py @@ -13,7 +13,7 @@ class GEOSIOTest(unittest.TestCase): # read() should return a GEOSGeometry ref = GEOSGeometry(wkt) g1 = wkt_r.read(wkt) - g2 = wkt_r.read(unicode(wkt)) + g2 = wkt_r.read(six.text_type(wkt)) for geom in (g1, g2): self.assertEqual(ref, geom) diff --git a/django/contrib/gis/tests/geoapp/tests.py b/django/contrib/gis/tests/geoapp/tests.py index 4136a65d5c..bcdbe734ff 100644 --- a/django/contrib/gis/tests/geoapp/tests.py +++ b/django/contrib/gis/tests/geoapp/tests.py @@ -11,6 +11,7 @@ from django.contrib.gis.tests.utils import ( no_mysql, no_oracle, no_spatialite, mysql, oracle, postgis, spatialite) from django.test import TestCase +from django.utils import six from .models import Country, City, PennsylvaniaCity, State, Track @@ -663,7 +664,7 @@ class GeoModelTest(TestCase): # Let's try and break snap_to_grid() with bad combinations of arguments. for bad_args in ((), range(3), range(5)): self.assertRaises(ValueError, Country.objects.snap_to_grid, *bad_args) - for bad_args in (('1.0',), (1.0, None), tuple(map(unicode, range(4)))): + for bad_args in (('1.0',), (1.0, None), tuple(map(six.text_type, range(4)))): self.assertRaises(TypeError, Country.objects.snap_to_grid, *bad_args) # Boundary for San Marino, courtesy of Bjorn Sandvik of thematicmapping.org diff --git a/django/contrib/gis/utils/layermapping.py b/django/contrib/gis/utils/layermapping.py index 770bbe63db..e898f6de2e 100644 --- a/django/contrib/gis/utils/layermapping.py +++ b/django/contrib/gis/utils/layermapping.py @@ -330,7 +330,7 @@ class LayerMapping(object): if self.encoding: # The encoding for OGR data sources may be specified here # (e.g., 'cp437' for Census Bureau boundary files). - val = unicode(ogr_field.value, self.encoding) + val = six.text_type(ogr_field.value, self.encoding) else: val = ogr_field.value if model_field.max_length and len(val) > model_field.max_length: diff --git a/django/contrib/localflavor/mx/forms.py b/django/contrib/localflavor/mx/forms.py index 2dcf17d26c..4a7c005ad5 100644 --- a/django/contrib/localflavor/mx/forms.py +++ b/django/contrib/localflavor/mx/forms.py @@ -7,6 +7,7 @@ import re from django.forms import ValidationError from django.forms.fields import Select, RegexField +from django.utils import six from django.utils.translation import ugettext_lazy as _ from django.core.validators import EMPTY_VALUES from django.contrib.localflavor.mx.mx_states import STATE_CHOICES @@ -155,7 +156,7 @@ class MXRFCField(RegexField): elif checksum == 11: return '0' - return unicode(checksum) + return six.text_type(checksum) def _has_inconvenient_word(self, rfc): first_four = rfc[:4] @@ -219,7 +220,7 @@ class MXCURPField(RegexField): if checksum == 10: return '0' - return unicode(checksum) + return six.text_type(checksum) def _has_inconvenient_word(self, curp): first_four = curp[:4] diff --git a/django/contrib/localflavor/se/utils.py b/django/contrib/localflavor/se/utils.py index 5e7c2b7dae..783062ebb4 100644 --- a/django/contrib/localflavor/se/utils.py +++ b/django/contrib/localflavor/se/utils.py @@ -1,4 +1,5 @@ import datetime +from django.utils import six def id_number_checksum(gd): """ @@ -65,7 +66,7 @@ def validate_id_birthday(gd, fix_coordination_number_day=True): def format_personal_id_number(birth_day, gd): # birth_day.strftime cannot be used, since it does not support dates < 1900 - return unicode(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) + return six.text_type(str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) def format_organisation_number(gd): if gd['century'] is None: @@ -73,7 +74,7 @@ def format_organisation_number(gd): else: century = gd['century'] - return unicode(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) + return six.text_type(century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']) def valid_organisation(gd): return gd['century'] in (None, 16) and \ diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py index a524e64f65..7c868e4b60 100644 --- a/django/core/management/commands/inspectdb.py +++ b/django/core/management/commands/inspectdb.py @@ -3,6 +3,7 @@ from optparse import make_option from django.core.management.base import NoArgsCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS +from django.utils import six class Command(NoArgsCommand): help = "Introspects the database tables in the given database and outputs a Django model module." @@ -115,7 +116,7 @@ class Command(NoArgsCommand): if att_name[0].isdigit(): att_name = 'number_%s' % att_name - extra_params['db_column'] = unicode(column_name) + extra_params['db_column'] = six.text_type(column_name) comment_notes.append("Field renamed because it wasn't a " "valid Python identifier.") diff --git a/django/core/management/validation.py b/django/core/management/validation.py index 51eeae4e91..274f98ee79 100644 --- a/django/core/management/validation.py +++ b/django/core/management/validation.py @@ -120,7 +120,7 @@ def get_validation_errors(outfile, app=None): e.add(opts, "'%s' has a relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section - if isinstance(f.rel.to, (str, unicode)): + if isinstance(f.rel.to, six.string_types): continue # Make sure the related field specified by a ForeignKey is unique @@ -162,7 +162,7 @@ def get_validation_errors(outfile, app=None): e.add(opts, "'%s' has an m2m relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section - if isinstance(f.rel.to, (str, unicode)): + if isinstance(f.rel.to, six.string_types): continue # Check that the field is not set to unique. ManyToManyFields do not support unique. diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index e88975f849..7397cf3b3d 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -169,7 +169,7 @@ class LocaleRegexProvider(object): except re.error as e: raise ImproperlyConfigured( '"%s" is not a valid regular expression: %s' % - (regex, unicode(e))) + (regex, six.text_type(e))) self._regex_dict[language_code] = compiled_regex return self._regex_dict[language_code] diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 3075bdb3e4..b416343f88 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -12,6 +12,7 @@ from django.db.backends import util from django.db.transaction import TransactionManagementError from django.utils.functional import cached_property from django.utils.importlib import import_module +from django.utils import six from django.utils.timezone import is_aware @@ -808,7 +809,7 @@ class BaseDatabaseOperations(object): """ if value is None: return None - return unicode(value) + return six.text_type(value) def value_to_db_datetime(self, value): """ @@ -817,7 +818,7 @@ class BaseDatabaseOperations(object): """ if value is None: return None - return unicode(value) + return six.text_type(value) def value_to_db_time(self, value): """ @@ -828,7 +829,7 @@ class BaseDatabaseOperations(object): return None if is_aware(value): raise ValueError("Django does not support timezone-aware times.") - return unicode(value) + return six.text_type(value) def value_to_db_decimal(self, value, max_digits, decimal_places): """ diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index a7668dec49..ec65207ed8 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -297,7 +297,7 @@ class DatabaseOperations(BaseDatabaseOperations): raise ValueError("MySQL backend does not support timezone-aware datetimes when USE_TZ is False.") # MySQL doesn't support microseconds - return unicode(value.replace(microsecond=0)) + return six.text_type(value.replace(microsecond=0)) def value_to_db_time(self, value): if value is None: @@ -308,7 +308,7 @@ class DatabaseOperations(BaseDatabaseOperations): raise ValueError("MySQL backend does not support timezone-aware times.") # MySQL doesn't support microseconds - return unicode(value.replace(microsecond=0)) + return six.text_type(value.replace(microsecond=0)) def year_lookup_bounds(self, value): # Again, no microseconds @@ -399,8 +399,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[unicode] - self.connection.encoders[SafeString] = self.connection.encoders[str] + self.connection.encoders[SafeUnicode] = self.connection.encoders[six.text_type] + self.connection.encoders[SafeString] = self.connection.encoders[bytes] connection_created.send(sender=self.__class__, connection=self) cursor = self.connection.cursor() if new_connection: diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 9ac41a5741..32ae420ce0 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -356,7 +356,7 @@ WHEN (new.%(col_name)s IS NULL) else: raise ValueError("Oracle backend does not support timezone-aware datetimes when USE_TZ is False.") - return unicode(value) + return six.text_type(value) def value_to_db_time(self, value): if value is None: diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index e2149ca8d8..0a97449789 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -177,7 +177,7 @@ class DatabaseOperations(BaseDatabaseOperations): else: raise ValueError("SQLite backend does not support timezone-aware datetimes when USE_TZ is False.") - return unicode(value) + return six.text_type(value) def value_to_db_time(self, value): if value is None: @@ -187,7 +187,7 @@ class DatabaseOperations(BaseDatabaseOperations): if timezone.is_aware(value): raise ValueError("SQLite backend does not support timezone-aware times.") - return unicode(value) + return six.text_type(value) def year_lookup_bounds(self, value): first = '%s-01-01' diff --git a/django/db/models/base.py b/django/db/models/base.py index 04ae4bc96d..8c448b2f39 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -375,7 +375,7 @@ class ModelWithoutMeta(object): def __repr__(self): try: - u = unicode(self) + u = six.text_type(self) except (UnicodeEncodeError, UnicodeDecodeError): u = '[Bad Unicode data]' return smart_str('<%s: %s>' % (self.__class__.__name__, u)) @@ -790,8 +790,8 @@ class ModelWithoutMeta(object): def date_error_message(self, lookup_type, field, unique_for): opts = self._meta return _("%(field_name)s must be unique for %(date_field)s %(lookup)s.") % { - 'field_name': unicode(capfirst(opts.get_field(field).verbose_name)), - 'date_field': unicode(capfirst(opts.get_field(unique_for).verbose_name)), + 'field_name': six.text_type(capfirst(opts.get_field(field).verbose_name)), + 'date_field': six.text_type(capfirst(opts.get_field(unique_for).verbose_name)), 'lookup': lookup_type, } @@ -806,16 +806,16 @@ class ModelWithoutMeta(object): field_label = capfirst(field.verbose_name) # Insert the error into the error dict, very sneaky return field.error_messages['unique'] % { - 'model_name': unicode(model_name), - 'field_label': unicode(field_label) + 'model_name': six.text_type(model_name), + 'field_label': six.text_type(field_label) } # unique_together else: field_labels = map(lambda f: capfirst(opts.get_field(f).verbose_name), unique_check) field_labels = get_text_list(field_labels, _('and')) return _("%(model_name)s with this %(field_label)s already exists.") % { - 'model_name': unicode(model_name), - 'field_label': unicode(field_labels) + 'model_name': six.text_type(model_name), + 'field_label': six.text_type(field_labels) } def full_clean(self, exclude=None): diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index d3f1327315..b51ef1d5d6 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -265,7 +265,7 @@ class FileField(Field): # Need to convert File objects provided via a form to unicode for database insertion if value is None: return None - return unicode(value) + return six.text_type(value) def pre_save(self, model_instance, add): "Returns field's value just before saving." diff --git a/django/forms/fields.py b/django/forms/fields.py index 4c4209dddd..9c944ad0ac 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -331,10 +331,10 @@ class BaseTemporalField(Field): def to_python(self, value): # Try to coerce the value to unicode. unicode_value = force_unicode(value, strings_only=True) - if isinstance(unicode_value, unicode): + if isinstance(unicode_value, six.text_type): value = unicode_value.strip() # If unicode, try to strptime against each input format. - if isinstance(value, unicode): + if isinstance(value, six.text_type): for format in self.input_formats: try: return self.strptime(value, format) diff --git a/django/forms/forms.py b/django/forms/forms.py index 0af71918d8..4bc3ee9d26 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -151,7 +151,7 @@ class BaseForm(StrAndUnicode): if bf.is_hidden: if bf_errors: top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors]) - hidden_fields.append(unicode(bf)) + hidden_fields.append(six.text_type(bf)) else: # Create a 'class="..."' atribute if the row should have any # CSS classes applied. @@ -181,7 +181,7 @@ class BaseForm(StrAndUnicode): output.append(normal_row % { 'errors': force_unicode(bf_errors), 'label': force_unicode(label), - 'field': unicode(bf), + 'field': six.text_type(bf), 'help_text': help_text, 'html_class_attr': html_class_attr }) diff --git a/django/forms/formsets.py b/django/forms/formsets.py index 31ca088bdb..8a61f6cd62 100644 --- a/django/forms/formsets.py +++ b/django/forms/formsets.py @@ -7,6 +7,7 @@ from django.forms.util import ErrorList from django.forms.widgets import Media, HiddenInput from django.utils.encoding import StrAndUnicode from django.utils.safestring import mark_safe +from django.utils import six from django.utils.translation import ugettext as _ @@ -345,17 +346,17 @@ class BaseFormSet(StrAndUnicode): # probably should be. It might make sense to render each form as a # table row with each field as a td. forms = ' '.join([form.as_table() for form in self]) - return mark_safe('\n'.join([unicode(self.management_form), forms])) + return mark_safe('\n'.join([six.text_type(self.management_form), forms])) def as_p(self): "Returns this formset rendered as HTML <p>s." forms = ' '.join([form.as_p() for form in self]) - return mark_safe('\n'.join([unicode(self.management_form), forms])) + return mark_safe('\n'.join([six.text_type(self.management_form), forms])) def as_ul(self): "Returns this formset rendered as HTML <li>s." forms = ' '.join([form.as_ul() for form in self]) - return mark_safe('\n'.join([unicode(self.management_form), forms])) + return mark_safe('\n'.join([six.text_type(self.management_form), forms])) def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, can_delete=False, max_num=None): diff --git a/django/forms/models.py b/django/forms/models.py index 1ef308d93a..0831d5f4b2 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -576,7 +576,7 @@ class BaseModelFormSet(BaseFormSet): else: return ugettext("Please correct the duplicate data for %(field)s, " "which must be unique.") % { - "field": get_text_list(unique_check, unicode(_("and"))), + "field": get_text_list(unique_check, six.text_type(_("and"))), } def get_date_error_message(self, date_check): @@ -584,7 +584,7 @@ class BaseModelFormSet(BaseFormSet): "which must be unique for the %(lookup)s in %(date_field)s.") % { 'field_name': date_check[2], 'date_field': date_check[3], - 'lookup': unicode(date_check[1]), + 'lookup': six.text_type(date_check[1]), } def get_form_error(self): diff --git a/django/http/__init__.py b/django/http/__init__.py index da1f9edc63..7c5184a329 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -137,10 +137,10 @@ def build_request_repr(request, path_override=None, GET_override=None, return smart_str('<%s\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % (request.__class__.__name__, path, - unicode(get), - unicode(post), - unicode(cookies), - unicode(meta))) + six.text_type(get), + six.text_type(post), + six.text_type(cookies), + six.text_type(meta))) class UnreadablePostError(IOError): pass @@ -544,7 +544,7 @@ class HttpResponse(object): def _convert_to_ascii(self, *values): """Converts all values to ascii strings.""" for value in values: - if isinstance(value, unicode): + if isinstance(value, six.text_type): try: value = value.encode('us-ascii') except UnicodeError as e: @@ -663,7 +663,7 @@ class HttpResponse(object): def next(self): chunk = next(self._iterator) - if isinstance(chunk, unicode): + if isinstance(chunk, six.text_type): chunk = chunk.encode(self._charset) return str(chunk) @@ -740,8 +740,8 @@ def str_to_unicode(s, encoding): Returns any non-basestring objects without change. """ - if isinstance(s, str): - return unicode(s, encoding, 'replace') + if isinstance(s, bytes): + return six.text_type(s, encoding, 'replace') else: return s diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py index bbe4b052b7..0e28a55c3a 100644 --- a/django/http/multipartparser.py +++ b/django/http/multipartparser.py @@ -11,6 +11,7 @@ from django.conf import settings from django.core.exceptions import SuspiciousOperation from django.utils.datastructures import MultiValueDict from django.utils.encoding import force_unicode +from django.utils import six from django.utils.text import unescape_entities from django.core.files.uploadhandler import StopUpload, SkipFile, StopFutureHandlers @@ -77,7 +78,7 @@ class MultiPartParser(object): # This means we shouldn't continue...raise an error. raise MultiPartParserError("Invalid content length: %r" % content_length) - if isinstance(boundary, unicode): + if isinstance(boundary, six.text_type): boundary = boundary.encode('ascii') self._boundary = boundary self._input_data = input_data diff --git a/django/template/base.py b/django/template/base.py index cbf6de2d40..489b1681e0 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -86,7 +86,7 @@ class VariableDoesNotExist(Exception): self.params = params def __str__(self): - return unicode(self).encode('utf-8') + return six.text_type(self).encode('utf-8') def __unicode__(self): return self.msg % tuple([force_unicode(p, errors='replace') diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index b9cdd94296..fa799cd46f 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -18,6 +18,7 @@ from django.utils.html import (conditional_escape, escapejs, fix_ampersands, from django.utils.http import urlquote from django.utils.text import Truncator, wrap, phone2numeric from django.utils.safestring import mark_safe, SafeData, mark_for_escaping +from django.utils import six from django.utils.timesince import timesince, timeuntil from django.utils.translation import ugettext, ungettext from django.utils.text import normalize_newlines @@ -176,7 +177,7 @@ def floatformat(text, arg=-1): # and `exponent` from `Decimal.as_tuple()` directly. sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)).as_tuple() - digits = [unicode(digit) for digit in reversed(digits)] + digits = [six.text_type(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append('0') digits.insert(-exponent, '.') @@ -200,7 +201,7 @@ def linenumbers(value, autoescape=None): lines = value.split('\n') # Find the maximum width of the line count, for use with zero padding # string format command - width = unicode(len(unicode(len(lines)))) + width = six.text_type(len(six.text_type(len(lines)))) if not autoescape or isinstance(value, SafeData): for i, line in enumerate(lines): lines[i] = ("%0" + width + "d. %s") % (i + 1, line) @@ -234,7 +235,7 @@ def slugify(value): and converts spaces to hyphens. """ value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') - value = unicode(re.sub('[^\w\s-]', '', value).strip().lower()) + value = six.text_type(re.sub('[^\w\s-]', '', value).strip().lower()) return mark_safe(re.sub('[-\s]+', '-', value)) @register.filter(is_safe=True) @@ -249,7 +250,7 @@ def stringformat(value, arg): of Python string formatting """ try: - return ("%" + unicode(arg)) % value + return ("%" + six.text_type(arg)) % value except (ValueError, TypeError): return "" diff --git a/django/test/_doctest.py b/django/test/_doctest.py index 0388714094..75f16e202a 100644 --- a/django/test/_doctest.py +++ b/django/test/_doctest.py @@ -211,7 +211,7 @@ def _normalize_module(module, depth=2): """ if inspect.ismodule(module): return module - elif isinstance(module, (str, unicode)): + elif isinstance(module, six.string_types): return __import__(module, globals(), locals(), ["*"]) elif module is None: return sys.modules[sys._getframe(depth).f_globals['__name__']] diff --git a/django/test/html.py b/django/test/html.py index a44eb72322..8d577d91fd 100644 --- a/django/test/html.py +++ b/django/test/html.py @@ -125,14 +125,14 @@ class Element(object): output += ' %s' % key if self.children: output += '>\n' - output += ''.join(unicode(c) for c in self.children) + output += ''.join(six.text_type(c) for c in self.children) output += '\n</%s>' % self.name else: output += ' />' return output def __repr__(self): - return unicode(self) + return six.text_type(self) class RootElement(Element): @@ -140,7 +140,7 @@ class RootElement(Element): super(RootElement, self).__init__(None, ()) def __unicode__(self): - return ''.join(unicode(c) for c in self.children) + return ''.join(six.text_type(c) for c in self.children) class Parser(HTMLParser): diff --git a/django/test/testcases.py b/django/test/testcases.py index 0a0b029796..eb7bd70d12 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -38,6 +38,7 @@ from django.test.utils import (get_warnings_state, restore_warnings_state, from django.test.utils import ContextList from django.utils import unittest as ut2 from django.utils.encoding import smart_str, force_unicode +from django.utils import six from django.utils.unittest.util import safe_repr from django.views.static import serve @@ -421,8 +422,8 @@ class SimpleTestCase(ut2.TestCase): standardMsg = '%s != %s' % ( safe_repr(dom1, True), safe_repr(dom2, True)) diff = ('\n' + '\n'.join(difflib.ndiff( - unicode(dom1).splitlines(), - unicode(dom2).splitlines()))) + six.text_type(dom1).splitlines(), + six.text_type(dom2).splitlines()))) standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg)) diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py index d410bce63e..c9a6138aed 100644 --- a/django/utils/dateformat.py +++ b/django/utils/dateformat.py @@ -21,6 +21,7 @@ from django.utils.dates import MONTHS, MONTHS_3, MONTHS_ALT, MONTHS_AP, WEEKDAYS from django.utils.tzinfo import LocalTimezone from django.utils.translation import ugettext as _ from django.utils.encoding import force_unicode +from django.utils import six from django.utils.timezone import is_aware, is_naive re_formatchars = re.compile(r'(?<!\\)([aAbBcdDeEfFgGhHiIjlLmMnNoOPrsStTUuwWyYzZ])') @@ -236,7 +237,7 @@ class DateFormat(TimeFormat): name = self.timezone and self.timezone.tzname(self.data) or None if name is None: name = self.format('O') - return unicode(name) + return six.text_type(name) def U(self): "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)" @@ -277,7 +278,7 @@ class DateFormat(TimeFormat): def y(self): "Year, 2 digits; e.g. '99'" - return unicode(self.data.year)[2:] + return six.text_type(self.data.year)[2:] def Y(self): "Year, 4 digits; e.g. '1999'" diff --git a/django/utils/encoding.py b/django/utils/encoding.py index 716d46ceff..789e709da5 100644 --- a/django/utils/encoding.py +++ b/django/utils/encoding.py @@ -25,8 +25,12 @@ class StrAndUnicode(object): Useful as a mix-in. """ - def __str__(self): - return self.__unicode__().encode('utf-8') + if six.PY3: + def __str__(self): + return self.__unicode__() + else: + def __str__(self): + return self.__unicode__().encode('utf-8') def smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): """ @@ -59,17 +63,23 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): # Handle the common case first, saves 30-40% in performance when s # is an instance of unicode. This function gets called often in that # setting. - if isinstance(s, unicode): + if isinstance(s, six.text_type): return s if strings_only and is_protected_type(s): return s try: - if not isinstance(s, six.string_types,): + if not isinstance(s, six.string_types): if hasattr(s, '__unicode__'): - s = unicode(s) + s = s.__unicode__() else: try: - s = unicode(str(s), encoding, errors) + if six.PY3: + if isinstance(s, bytes): + s = six.text_type(s, encoding, errors) + else: + s = six.text_type(s) + else: + s = six.text_type(bytes(s), encoding, errors) except UnicodeEncodeError: if not isinstance(s, Exception): raise @@ -81,8 +91,8 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): # output should be. s = ' '.join([force_unicode(arg, encoding, strings_only, errors) for arg in s]) - elif not isinstance(s, unicode): - # Note: We use .decode() here, instead of unicode(s, encoding, + elif not isinstance(s, six.text_type): + # 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. s = s.decode(encoding, errors) @@ -108,10 +118,13 @@ def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): if strings_only and (s is None or isinstance(s, int)): return s if isinstance(s, Promise): - return unicode(s).encode(encoding, errors) + return six.text_type(s).encode(encoding, errors) elif not isinstance(s, six.string_types): try: - return str(s) + if six.PY3: + return six.text_type(s).encode(encoding) + else: + return bytes(s) except UnicodeEncodeError: if isinstance(s, Exception): # An Exception subclass containing non-ASCII data that doesn't @@ -119,8 +132,8 @@ def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): # further exception. return ' '.join([smart_str(arg, encoding, strings_only, errors) for arg in s]) - return unicode(s).encode(encoding, errors) - elif isinstance(s, unicode): + return six.text_type(s).encode(encoding, errors) + elif isinstance(s, six.text_type): return s.encode(encoding, errors) elif s and encoding != 'utf-8': return s.decode('utf-8', errors).encode(encoding, errors) diff --git a/django/utils/formats.py b/django/utils/formats.py index eae40970da..2e54d792fa 100644 --- a/django/utils/formats.py +++ b/django/utils/formats.py @@ -89,7 +89,7 @@ def get_format(format_type, lang=None, use_l10n=None): _format_cache[cache_key] = None return getattr(settings, format_type) -get_format_lazy = lazy(get_format, unicode, list, tuple) +get_format_lazy = lazy(get_format, six.text_type, list, tuple) def date_format(value, format=None, use_l10n=None): """ @@ -139,7 +139,7 @@ def localize(value, use_l10n=None): be localized (or not), overriding the value of settings.USE_L10N. """ if isinstance(value, bool): - return mark_safe(unicode(value)) + return mark_safe(six.text_type(value)) elif isinstance(value, (decimal.Decimal, float) + six.integer_types): return number_format(value, use_l10n=use_l10n) elif isinstance(value, datetime.datetime): diff --git a/django/utils/functional.py b/django/utils/functional.py index 31466ee8b8..2dca182b99 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -3,6 +3,7 @@ import operator from functools import wraps, update_wrapper import sys +from django.utils import six # You can't trivially replace this `functools.partial` because this binds to # classes and returns bound instances, whereas functools.partial (on CPython) @@ -92,8 +93,8 @@ def lazy(func, *resultclasses): if hasattr(cls, k): continue setattr(cls, k, meth) - cls._delegate_str = str in resultclasses - cls._delegate_unicode = unicode in resultclasses + cls._delegate_str = bytes in resultclasses + cls._delegate_unicode = six.text_type in resultclasses assert not (cls._delegate_str and cls._delegate_unicode), "Cannot call lazy() with both str and unicode return types." if cls._delegate_unicode: cls.__unicode__ = cls.__unicode_cast @@ -147,7 +148,7 @@ def lazy(func, *resultclasses): if self._delegate_str: return str(self) % rhs elif self._delegate_unicode: - return unicode(self) % rhs + return six.text_type(self) % rhs else: raise AssertionError('__mod__ not supported for non-string types') @@ -255,8 +256,8 @@ class SimpleLazyObject(LazyObject): def _setup(self): self._wrapped = self._setupfunc() - __str__ = new_method_proxy(str) - __unicode__ = new_method_proxy(unicode) + __str__ = new_method_proxy(bytes) + __unicode__ = new_method_proxy(six.text_type) def __deepcopy__(self, memo): if self._wrapped is empty: diff --git a/django/utils/html.py b/django/utils/html.py index 390c45dcec..d5881996d9 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -10,6 +10,7 @@ import urlparse from django.utils.safestring import SafeData, mark_safe from django.utils.encoding import smart_str, force_unicode from django.utils.functional import allow_lazy +from django.utils import six from django.utils.text import normalize_newlines # Configuration for urlize() function. @@ -36,7 +37,7 @@ def escape(text): Returns the given text with ampersands, quotes and angle brackets encoded for use in HTML. """ return mark_safe(force_unicode(text).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''')) -escape = allow_lazy(escape, unicode) +escape = allow_lazy(escape, six.text_type) _base_js_escapes = ( ('\\', '\\u005C'), @@ -61,7 +62,7 @@ def escapejs(value): for bad, good in _js_escapes: value = mark_safe(force_unicode(value).replace(bad, good)) return value -escapejs = allow_lazy(escapejs, unicode) +escapejs = allow_lazy(escapejs, six.text_type) def conditional_escape(text): """ @@ -112,7 +113,7 @@ def linebreaks(value, autoescape=False): else: paras = ['<p>%s</p>' % p.replace('\n', '<br />') for p in paras] return '\n\n'.join(paras) -linebreaks = allow_lazy(linebreaks, unicode) +linebreaks = allow_lazy(linebreaks, six.text_type) def strip_tags(value): """Returns the given HTML with all tags stripped.""" @@ -122,17 +123,17 @@ strip_tags = allow_lazy(strip_tags) def strip_spaces_between_tags(value): """Returns the given HTML with spaces between tags removed.""" return re.sub(r'>\s+<', '><', force_unicode(value)) -strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, unicode) +strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, six.text_type) def strip_entities(value): """Returns the given HTML with all entities (&something;) stripped.""" return re.sub(r'&(?:\w+|#\d+);', '', force_unicode(value)) -strip_entities = allow_lazy(strip_entities, unicode) +strip_entities = allow_lazy(strip_entities, six.text_type) def fix_ampersands(value): """Returns the given HTML with all unencoded ampersands encoded correctly.""" return unencoded_ampersands_re.sub('&', force_unicode(value)) -fix_ampersands = allow_lazy(fix_ampersands, unicode) +fix_ampersands = allow_lazy(fix_ampersands, six.text_type) def smart_urlquote(url): "Quotes a URL if it isn't already quoted." @@ -226,7 +227,7 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): elif autoescape: words[i] = escape(word) return ''.join(words) -urlize = allow_lazy(urlize, unicode) +urlize = allow_lazy(urlize, six.text_type) def clean_html(text): """ @@ -260,4 +261,4 @@ def clean_html(text): # of the text. text = trailing_empty_content_re.sub('', text) return text -clean_html = allow_lazy(clean_html, unicode) +clean_html = allow_lazy(clean_html, six.text_type) diff --git a/django/utils/http.py b/django/utils/http.py index 87db284416..ec94d62903 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -9,6 +9,7 @@ from email.utils import formatdate from django.utils.datastructures import MultiValueDict from django.utils.encoding import smart_str, force_unicode from django.utils.functional import allow_lazy +from django.utils import six ETAG_MATCH = re.compile(r'(?:W/)?"((?:\\.|[^"])*)"') @@ -31,7 +32,7 @@ def urlquote(url, safe='/'): without double-quoting occurring. """ return force_unicode(urllib.quote(smart_str(url), smart_str(safe))) -urlquote = allow_lazy(urlquote, unicode) +urlquote = allow_lazy(urlquote, six.text_type) def urlquote_plus(url, safe=''): """ @@ -41,7 +42,7 @@ def urlquote_plus(url, safe=''): iri_to_uri() call without double-quoting occurring. """ return force_unicode(urllib.quote_plus(smart_str(url), smart_str(safe))) -urlquote_plus = allow_lazy(urlquote_plus, unicode) +urlquote_plus = allow_lazy(urlquote_plus, six.text_type) def urlunquote(quoted_url): """ @@ -49,7 +50,7 @@ def urlunquote(quoted_url): the result of django.utils.http.urlquote(). """ return force_unicode(urllib.unquote(smart_str(quoted_url))) -urlunquote = allow_lazy(urlunquote, unicode) +urlunquote = allow_lazy(urlunquote, six.text_type) def urlunquote_plus(quoted_url): """ @@ -57,7 +58,7 @@ def urlunquote_plus(quoted_url): the result of django.utils.http.urlquote_plus(). """ return force_unicode(urllib.unquote_plus(smart_str(quoted_url))) -urlunquote_plus = allow_lazy(urlunquote_plus, unicode) +urlunquote_plus = allow_lazy(urlunquote_plus, six.text_type) def urlencode(query, doseq=0): """ diff --git a/django/utils/numberformat.py b/django/utils/numberformat.py index 924d06511b..d51b230823 100644 --- a/django/utils/numberformat.py +++ b/django/utils/numberformat.py @@ -1,5 +1,6 @@ from django.conf import settings from django.utils.safestring import mark_safe +from django.utils import six def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='', @@ -18,13 +19,13 @@ def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='', use_grouping = use_grouping and grouping > 0 # Make the common case fast if isinstance(number, int) and not use_grouping and not decimal_pos: - return mark_safe(unicode(number)) + return mark_safe(six.text_type(number)) # sign if float(number) < 0: sign = '-' else: sign = '' - str_number = unicode(number) + str_number = six.text_type(number) if str_number[0] == '-': str_number = str_number[1:] # decimal part diff --git a/django/utils/safestring.py b/django/utils/safestring.py index 2e31c23676..1599fc2a66 100644 --- a/django/utils/safestring.py +++ b/django/utils/safestring.py @@ -5,17 +5,18 @@ 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 curry, Promise +from django.utils import six class EscapeData(object): pass -class EscapeString(str, EscapeData): +class EscapeString(bytes, EscapeData): """ A string that should be HTML-escaped when output. """ pass -class EscapeUnicode(unicode, EscapeData): +class EscapeUnicode(six.text_type, EscapeData): """ A unicode object that should be HTML-escaped when output. """ @@ -24,7 +25,7 @@ class EscapeUnicode(unicode, EscapeData): class SafeData(object): pass -class SafeString(str, SafeData): +class SafeString(bytes, SafeData): """ A string subclass that has been specifically marked as "safe" (requires no further escaping) for HTML output purposes. @@ -40,7 +41,7 @@ class SafeString(str, SafeData): elif isinstance(rhs, SafeString): return SafeString(t) return t - + def _proxy_method(self, *args, **kwargs): """ Wrap a call to a normal unicode method up so that we return safe @@ -49,14 +50,14 @@ class SafeString(str, SafeData): """ method = kwargs.pop('method') data = method(self, *args, **kwargs) - if isinstance(data, str): + if isinstance(data, bytes): return SafeString(data) else: return SafeUnicode(data) - decode = curry(_proxy_method, method = str.decode) + decode = curry(_proxy_method, method=bytes.decode) -class SafeUnicode(unicode, SafeData): +class SafeUnicode(six.text_type, SafeData): """ A unicode subclass that has been specifically marked as "safe" for HTML output purposes. @@ -70,7 +71,7 @@ class SafeUnicode(unicode, SafeData): if isinstance(rhs, SafeData): return SafeUnicode(t) return t - + def _proxy_method(self, *args, **kwargs): """ Wrap a call to a normal unicode method up so that we return safe @@ -79,12 +80,12 @@ class SafeUnicode(unicode, SafeData): """ method = kwargs.pop('method') data = method(self, *args, **kwargs) - if isinstance(data, str): + if isinstance(data, bytes): return SafeString(data) else: return SafeUnicode(data) - encode = curry(_proxy_method, method = unicode.encode) + encode = curry(_proxy_method, method=six.text_type.encode) def mark_safe(s): """ @@ -95,11 +96,11 @@ def mark_safe(s): """ if isinstance(s, SafeData): return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): + if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_str): return SafeString(s) - if isinstance(s, (unicode, Promise)): + if isinstance(s, (six.text_type, Promise)): return SafeUnicode(s) - return SafeString(str(s)) + return SafeString(bytes(s)) def mark_for_escaping(s): """ @@ -111,9 +112,9 @@ def mark_for_escaping(s): """ if isinstance(s, (SafeData, EscapeData)): return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): + if isinstance(s, bytes) or (isinstance(s, Promise) and s._delegate_str): return EscapeString(s) - if isinstance(s, (unicode, Promise)): + if isinstance(s, (six.text_type, Promise)): return EscapeUnicode(s) - return EscapeString(str(s)) + return EscapeString(bytes(s)) diff --git a/django/utils/text.py b/django/utils/text.py index 2546f770b5..9f773ad41b 100644 --- a/django/utils/text.py +++ b/django/utils/text.py @@ -9,11 +9,12 @@ from io import BytesIO from django.utils.encoding import force_unicode from django.utils.functional import allow_lazy, SimpleLazyObject +from django.utils import six from django.utils.translation import ugettext_lazy, ugettext as _, pgettext # Capitalizes the first letter of a string. capfirst = lambda x: x and force_unicode(x)[0].upper() + force_unicode(x)[1:] -capfirst = allow_lazy(capfirst, unicode) +capfirst = allow_lazy(capfirst, six.text_type) # Set up regular expressions re_words = re.compile(r'&.*?;|<.*?>|(\w[\w-]*)', re.U|re.S) @@ -46,7 +47,7 @@ def wrap(text, width): pos = len(lines[-1]) yield word return ''.join(_generator()) -wrap = allow_lazy(wrap, unicode) +wrap = allow_lazy(wrap, six.text_type) class Truncator(SimpleLazyObject): @@ -207,14 +208,14 @@ def truncate_words(s, num, end_text='...'): 'in django.utils.text instead.', category=DeprecationWarning) truncate = end_text and ' %s' % end_text or '' return Truncator(s).words(num, truncate=truncate) -truncate_words = allow_lazy(truncate_words, unicode) +truncate_words = allow_lazy(truncate_words, six.text_type) def truncate_html_words(s, num, end_text='...'): warnings.warn('This function has been deprecated. Use the Truncator class ' 'in django.utils.text instead.', category=DeprecationWarning) truncate = end_text and ' %s' % end_text or '' return Truncator(s).words(num, truncate=truncate, html=True) -truncate_html_words = allow_lazy(truncate_html_words, unicode) +truncate_html_words = allow_lazy(truncate_html_words, six.text_type) def get_valid_filename(s): """ @@ -227,7 +228,7 @@ def get_valid_filename(s): """ s = force_unicode(s).strip().replace(' ', '_') return re.sub(r'(?u)[^-\w.]', '', s) -get_valid_filename = allow_lazy(get_valid_filename, unicode) +get_valid_filename = allow_lazy(get_valid_filename, six.text_type) def get_text_list(list_, last_word=ugettext_lazy('or')): """ @@ -248,11 +249,11 @@ def get_text_list(list_, last_word=ugettext_lazy('or')): # Translators: This string is used as a separator between list elements _(', ').join([force_unicode(i) for i in list_][:-1]), force_unicode(last_word), force_unicode(list_[-1])) -get_text_list = allow_lazy(get_text_list, unicode) +get_text_list = allow_lazy(get_text_list, six.text_type) def normalize_newlines(text): return force_unicode(re.sub(r'\r\n|\r|\n', '\n', text)) -normalize_newlines = allow_lazy(normalize_newlines, unicode) +normalize_newlines = allow_lazy(normalize_newlines, six.text_type) def recapitalize(text): "Recapitalizes text, placing caps after end-of-sentence punctuation." @@ -288,9 +289,9 @@ def javascript_quote(s, quote_double_quotes=False): def fix(match): return b"\u%04x" % ord(match.group(1)) - if type(s) == str: + if type(s) == bytes: s = s.decode('utf-8') - elif type(s) != unicode: + elif type(s) != six.text_type: raise TypeError(s) s = s.replace('\\', '\\\\') s = s.replace('\r', '\\r') @@ -300,7 +301,7 @@ def javascript_quote(s, quote_double_quotes=False): if quote_double_quotes: s = s.replace('"', '"') return str(ustring_re.sub(fix, s)) -javascript_quote = allow_lazy(javascript_quote, unicode) +javascript_quote = allow_lazy(javascript_quote, six.text_type) # Expression to match some_token and some_token="with spaces" (and similarly # for single-quoted strings). @@ -332,7 +333,7 @@ def smart_split(text): text = force_unicode(text) for bit in smart_split_re.finditer(text): yield bit.group(0) -smart_split = allow_lazy(smart_split, unicode) +smart_split = allow_lazy(smart_split, six.text_type) def _replace_entity(match): text = match.group(1) @@ -356,7 +357,7 @@ _entity_re = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));") def unescape_entities(text): return _entity_re.sub(_replace_entity, text) -unescape_entities = allow_lazy(unescape_entities, unicode) +unescape_entities = allow_lazy(unescape_entities, six.text_type) def unescape_string_literal(s): r""" diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py index 0f1f28e5c4..d31a7aebf1 100644 --- a/django/utils/translation/__init__.py +++ b/django/utils/translation/__init__.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from django.utils.encoding import force_unicode from django.utils.functional import lazy +from django.utils import six __all__ = [ @@ -78,12 +79,12 @@ def pgettext(context, message): def npgettext(context, singular, plural, number): return _trans.npgettext(context, singular, plural, number) -ngettext_lazy = lazy(ngettext, str) -gettext_lazy = lazy(gettext, str) -ungettext_lazy = lazy(ungettext, unicode) -ugettext_lazy = lazy(ugettext, unicode) -pgettext_lazy = lazy(pgettext, unicode) -npgettext_lazy = lazy(npgettext, unicode) +ngettext_lazy = lazy(ngettext, bytes) +gettext_lazy = lazy(gettext, bytes) +ungettext_lazy = lazy(ungettext, six.text_type) +ugettext_lazy = lazy(ugettext, six.text_type) +pgettext_lazy = lazy(pgettext, six.text_type) +npgettext_lazy = lazy(npgettext, six.text_type) def activate(language): return _trans.activate(language) @@ -139,7 +140,7 @@ def _string_concat(*strings): constructed from multiple parts. """ return ''.join([force_unicode(s) for s in strings]) -string_concat = lazy(_string_concat, unicode) +string_concat = lazy(_string_concat, six.text_type) def get_language_info(lang_code): from django.conf.locale import LANG_INFO diff --git a/django/views/debug.py b/django/views/debug.py index 65226b5ca7..8e81b8239b 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -362,7 +362,7 @@ class ExceptionReporter(object): if match: encoding = match.group(1) break - source = [unicode(sline, encoding, 'replace') for sline in source] + source = [six.text_type(sline, encoding, 'replace') for sline in source] lower_bound = max(0, lineno - context_lines) upper_bound = lineno + context_lines |
