Quellcode durchsuchen

Refs #23919 -- Removed unneeded force_str calls

Claude Paroz vor 8 Jahren
Ursprung
Commit
dc8834cad4
44 geänderte Dateien mit 100 neuen und 167 gelöschten Zeilen
  1. 2 5
      django/contrib/admin/utils.py
  2. 3 3
      django/contrib/auth/hashers.py
  3. 1 2
      django/contrib/auth/management/commands/changepassword.py
  4. 5 6
      django/contrib/auth/management/commands/createsuperuser.py
  5. 0 5
      django/core/cache/backends/memcached.py
  6. 2 2
      django/core/checks/messages.py
  7. 2 2
      django/core/files/base.py
  8. 1 3
      django/core/files/uploadedfile.py
  9. 3 6
      django/core/handlers/wsgi.py
  10. 1 2
      django/core/mail/backends/smtp.py
  11. 5 5
      django/core/management/base.py
  12. 3 3
      django/core/management/commands/makemessages.py
  13. 6 11
      django/core/signing.py
  14. 1 2
      django/db/backends/mysql/base.py
  15. 1 2
      django/db/backends/postgresql/base.py
  16. 2 2
      django/db/models/base.py
  17. 2 2
      django/db/models/fields/files.py
  18. 4 4
      django/forms/fields.py
  19. 2 2
      django/forms/widgets.py
  20. 3 7
      django/http/request.py
  21. 1 4
      django/http/response.py
  22. 2 3
      django/template/base.py
  23. 5 5
      django/test/client.py
  24. 1 2
      django/test/utils.py
  25. 2 2
      django/urls/resolvers.py
  26. 3 5
      django/utils/formats.py
  27. 3 3
      django/utils/html.py
  28. 3 3
      django/utils/tree.py
  29. 2 2
      django/views/debug.py
  30. 2 2
      django/views/generic/dates.py
  31. 1 1
      tests/admin_scripts/tests.py
  32. 1 5
      tests/admin_utils/tests.py
  33. 1 2
      tests/auth_tests/test_management.py
  34. 2 2
      tests/contenttypes_tests/tests.py
  35. 10 20
      tests/dbshell/test_postgresql_psycopg2.py
  36. 2 4
      tests/file_uploads/views.py
  37. 1 2
      tests/generic_views/test_list.py
  38. 1 5
      tests/handlers/tests.py
  39. 2 8
      tests/httpwrappers/tests.py
  40. 1 2
      tests/middleware/tests.py
  41. 1 2
      tests/migrations/test_writer.py
  42. 2 3
      tests/or_lookups/tests.py
  43. 1 2
      tests/requests/tests.py
  44. 1 2
      tests/signing/tests.py

+ 2 - 5
django/contrib/admin/utils.py

@@ -11,7 +11,7 @@ from django.db.models.sql.constants import QUERY_TERMS
 from django.forms.utils import pretty_name
 from django.urls import NoReverseMatch, reverse
 from django.utils import formats, timezone
-from django.utils.encoding import force_str, force_text, smart_text
+from django.utils.encoding import force_text, smart_text
 from django.utils.html import format_html
 from django.utils.text import capfirst
 from django.utils.translation import (
@@ -340,12 +340,9 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
             # field is likely a ForeignObjectRel
             label = field.related_model._meta.verbose_name
     except FieldDoesNotExist:
-        if name == "__unicode__":
+        if name == "__str__":
             label = force_text(model._meta.verbose_name)
             attr = str
-        elif name == "__str__":
-            label = force_str(model._meta.verbose_name)
-            attr = bytes
         else:
             if callable(name):
                 attr = name

+ 3 - 3
django/contrib/auth/hashers.py

@@ -13,7 +13,7 @@ from django.dispatch import receiver
 from django.utils.crypto import (
     constant_time_compare, get_random_string, pbkdf2,
 )
-from django.utils.encoding import force_bytes, force_str, force_text
+from django.utils.encoding import force_bytes, force_text
 from django.utils.module_loading import import_string
 from django.utils.translation import ugettext_noop as _
 
@@ -627,7 +627,7 @@ class CryptPasswordHasher(BasePasswordHasher):
     def encode(self, password, salt):
         crypt = self._load_library()
         assert len(salt) == 2
-        data = crypt.crypt(force_str(password), salt)
+        data = crypt.crypt(password, salt)
         assert data is not None  # A platform like OpenBSD with a dummy crypt module.
         # we don't need to store the salt, but Django used to do this
         return "%s$%s$%s" % (self.algorithm, '', data)
@@ -636,7 +636,7 @@ class CryptPasswordHasher(BasePasswordHasher):
         crypt = self._load_library()
         algorithm, salt, data = encoded.split('$', 2)
         assert algorithm == self.algorithm
-        return constant_time_compare(data, crypt.crypt(force_str(password), data))
+        return constant_time_compare(data, crypt.crypt(password, data))
 
     def safe_summary(self, encoded):
         algorithm, salt, data = encoded.split('$', 2)

+ 1 - 2
django/contrib/auth/management/commands/changepassword.py

@@ -5,7 +5,6 @@ from django.contrib.auth.password_validation import validate_password
 from django.core.exceptions import ValidationError
 from django.core.management.base import BaseCommand, CommandError
 from django.db import DEFAULT_DB_ALIAS
-from django.utils.encoding import force_str
 
 UserModel = get_user_model()
 
@@ -16,7 +15,7 @@ class Command(BaseCommand):
     requires_system_checks = False
 
     def _get_pass(self, prompt="Password: "):
-        p = getpass.getpass(prompt=force_str(prompt))
+        p = getpass.getpass(prompt=prompt)
         if not p:
             raise CommandError("aborted")
         return p

+ 5 - 6
django/contrib/auth/management/commands/createsuperuser.py

@@ -10,7 +10,6 @@ from django.contrib.auth.password_validation import validate_password
 from django.core import exceptions
 from django.core.management.base import BaseCommand, CommandError
 from django.db import DEFAULT_DB_ALIAS
-from django.utils.encoding import force_str
 from django.utils.text import capfirst
 
 
@@ -103,12 +102,12 @@ class Command(BaseCommand):
                     if default_username:
                         input_msg += " (leave blank to use '%s')" % default_username
                     username_rel = self.username_field.remote_field
-                    input_msg = force_str('%s%s: ' % (
+                    input_msg = '%s%s: ' % (
                         input_msg,
                         ' (%s.%s)' % (
                             username_rel.model._meta.object_name,
                             username_rel.field_name
-                        ) if username_rel else '')
+                        ) if username_rel else ''
                     )
                     username = self.get_input_data(self.username_field, input_msg, default_username)
                     if not username:
@@ -126,13 +125,13 @@ class Command(BaseCommand):
                     field = self.UserModel._meta.get_field(field_name)
                     user_data[field_name] = options[field_name]
                     while user_data[field_name] is None:
-                        message = force_str('%s%s: ' % (
+                        message = '%s%s: ' % (
                             capfirst(field.verbose_name),
                             ' (%s.%s)' % (
                                 field.remote_field.model._meta.object_name,
                                 field.remote_field.field_name,
                             ) if field.remote_field else '',
-                        ))
+                        )
                         input_value = self.get_input_data(field, message)
                         user_data[field_name] = input_value
                         fake_user_data[field_name] = input_value
@@ -144,7 +143,7 @@ class Command(BaseCommand):
                 # Get a password
                 while password is None:
                     password = getpass.getpass()
-                    password2 = getpass.getpass(force_str('Password (again): '))
+                    password2 = getpass.getpass('Password (again): ')
                     if password != password2:
                         self.stderr.write("Error: Your passwords didn't match.")
                         password = None

+ 0 - 5
django/core/cache/backends/memcached.py

@@ -7,7 +7,6 @@ import warnings
 
 from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
 from django.utils.deprecation import RemovedInDjango21Warning
-from django.utils.encoding import force_str
 from django.utils.functional import cached_property
 
 
@@ -65,10 +64,6 @@ class BaseMemcachedCache(BaseCache):
             timeout += int(time.time())
         return int(timeout)
 
-    def make_key(self, key, version=None):
-        # Python 2 memcache requires the key to be a byte string.
-        return force_str(super(BaseMemcachedCache, self).make_key(key, version))
-
     def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
         key = self.make_key(key, version=version)
         return self._cache.add(key, value, self.get_backend_timeout(timeout))

+ 2 - 2
django/core/checks/messages.py

@@ -1,4 +1,4 @@
-from django.utils.encoding import force_str
+from django.utils.encoding import force_text
 
 # Levels
 DEBUG = 10
@@ -35,7 +35,7 @@ class CheckMessage:
             # method doesn't return "applabel.modellabel" and cannot be changed.
             obj = self.obj._meta.label
         else:
-            obj = force_str(self.obj)
+            obj = force_text(self.obj)
         id = "(%s) " % self.id if self.id else ""
         hint = "\n\tHINT: %s" % self.hint if self.hint else ''
         return "%s: %s%s%s" % (obj, id, self.msg, hint)

+ 2 - 2
django/core/files/base.py

@@ -2,7 +2,7 @@ import os
 from io import BytesIO, StringIO, UnsupportedOperation
 
 from django.core.files.utils import FileProxyMixin
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 
 
 class File(FileProxyMixin):
@@ -20,7 +20,7 @@ class File(FileProxyMixin):
         return force_text(self.name or '')
 
     def __repr__(self):
-        return force_str("<%s: %s>" % (self.__class__.__name__, self or "None"))
+        return "<%s: %s>" % (self.__class__.__name__, self or "None")
 
     def __bool__(self):
         return bool(self.name)

+ 1 - 3
django/core/files/uploadedfile.py

@@ -9,7 +9,6 @@ from io import BytesIO
 from django.conf import settings
 from django.core.files import temp as tempfile
 from django.core.files.base import File
-from django.utils.encoding import force_str
 
 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
            'SimpleUploadedFile')
@@ -33,8 +32,7 @@ class UploadedFile(File):
         self.content_type_extra = content_type_extra
 
     def __repr__(self):
-        return force_str("<%s: %s (%s)>" % (
-            self.__class__.__name__, self.name, self.content_type))
+        return "<%s: %s (%s)>" % (self.__class__.__name__, self.name, self.content_type)
 
     def _get_name(self):
         return self._name

+ 3 - 6
django/core/handlers/wsgi.py

@@ -8,13 +8,10 @@ from django.conf import settings
 from django.core import signals
 from django.core.handlers import base
 from django.urls import set_script_prefix
-from django.utils.encoding import (
-    force_str, force_text, repercent_broken_unicode,
-)
+from django.utils.encoding import force_text, repercent_broken_unicode
 from django.utils.functional import cached_property
 
-# encode() and decode() expect the charset to be a native string.
-ISO_8859_1, UTF_8 = str('iso-8859-1'), str('utf-8')
+ISO_8859_1, UTF_8 = 'iso-8859-1', 'utf-8'
 
 _slashes_re = re.compile(br'/+')
 
@@ -159,7 +156,7 @@ class WSGIHandler(base.BaseHandler):
         response_headers = [(str(k), str(v)) for k, v in response.items()]
         for c in response.cookies.values():
             response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
-        start_response(force_str(status), response_headers)
+        start_response(status, response_headers)
         if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
             response = environ['wsgi.file_wrapper'](response.file_to_stream)
         return response

+ 1 - 2
django/core/mail/backends/smtp.py

@@ -8,7 +8,6 @@ from django.conf import settings
 from django.core.mail.backends.base import BaseEmailBackend
 from django.core.mail.message import sanitize_address
 from django.core.mail.utils import DNS_NAME
-from django.utils.encoding import force_str
 
 
 class EmailBackend(BaseEmailBackend):
@@ -68,7 +67,7 @@ class EmailBackend(BaseEmailBackend):
             if not self.use_ssl and self.use_tls:
                 self.connection.starttls(keyfile=self.ssl_keyfile, certfile=self.ssl_certfile)
             if self.username and self.password:
-                self.connection.login(force_str(self.username), force_str(self.password))
+                self.connection.login(self.username, self.password)
             return True
         except (smtplib.SMTPException, socket.error):
             if not self.fail_silently:

+ 5 - 5
django/core/management/base.py

@@ -5,6 +5,7 @@ be executed through ``django-admin`` or ``manage.py``).
 import os
 import sys
 from argparse import ArgumentParser
+from io import TextIOBase
 
 import django
 from django.core import checks
@@ -12,7 +13,6 @@ from django.core.exceptions import ImproperlyConfigured
 from django.core.management.color import color_style, no_style
 from django.db import DEFAULT_DB_ALIAS, connections
 from django.db.migrations.exceptions import MigrationSchemaMissing
-from django.utils.encoding import force_str
 
 
 class CommandError(Exception):
@@ -73,7 +73,7 @@ def handle_default_options(options):
         sys.path.insert(0, options.pythonpath)
 
 
-class OutputWrapper:
+class OutputWrapper(TextIOBase):
     """
     Wrapper around stdout/stderr
     """
@@ -104,7 +104,7 @@ class OutputWrapper:
         if ending and not msg.endswith(ending):
             msg += ending
         style_func = style_func or self.style_func
-        self._out.write(force_str(style_func(msg)))
+        self._out.write(style_func(msg))
 
 
 class BaseCommand:
@@ -377,9 +377,9 @@ class BaseCommand:
                 if issues:
                     visible_issue_count += len(issues)
                     formatted = (
-                        self.style.ERROR(force_str(e))
+                        self.style.ERROR(str(e))
                         if e.is_serious()
-                        else self.style.WARNING(force_str(e))
+                        else self.style.WARNING(str(e))
                         for e in issues)
                     formatted = "\n".join(sorted(formatted))
                     body += '\n%s:\n%s\n' % (group_name, formatted)

+ 3 - 3
django/core/management/commands/makemessages.py

@@ -15,7 +15,7 @@ from django.core.management.utils import (
     find_command, handle_extensions, popen_wrapper,
 )
 from django.utils._os import upath
-from django.utils.encoding import DEFAULT_LOCALE_ENCODING, force_str
+from django.utils.encoding import DEFAULT_LOCALE_ENCODING
 from django.utils.functional import cached_property
 from django.utils.jslex import prepare_js_for_gettext
 from django.utils.text import get_text_list
@@ -557,7 +557,7 @@ class Command(BaseCommand):
 
         input_files = [bf.work_path for bf in build_files]
         with NamedTemporaryFile(mode='w+') as input_files_list:
-            input_files_list.write(force_str('\n'.join(input_files), encoding=DEFAULT_LOCALE_ENCODING))
+            input_files_list.write(('\n'.join(input_files)))
             input_files_list.flush()
             args.extend(['--files-from', input_files_list.name])
             args.extend(self.xgettext_options)
@@ -649,7 +649,7 @@ class Command(BaseCommand):
                 with open(django_po, 'r', encoding='utf-8') as fp:
                     m = plural_forms_re.search(fp.read())
                 if m:
-                    plural_form_line = force_str(m.group('value'))
+                    plural_form_line = m.group('value')
                     if self.verbosity > 1:
                         self.stdout.write("copying plural forms: %s\n" % plural_form_line)
                     lines = []

+ 6 - 11
django/core/signing.py

@@ -43,7 +43,7 @@ import zlib
 from django.conf import settings
 from django.utils import baseconv
 from django.utils.crypto import constant_time_compare, salted_hmac
-from django.utils.encoding import force_bytes, force_str, force_text
+from django.utils.encoding import force_bytes, force_text
 from django.utils.module_loading import import_string
 
 _SEP_UNSAFE = re.compile(r'^[A-z0-9-_=]*$')
@@ -152,25 +152,21 @@ class Signer:
     def __init__(self, key=None, sep=':', salt=None):
         # Use of native strings in all versions of Python
         self.key = key or settings.SECRET_KEY
-        self.sep = force_str(sep)
+        self.sep = sep
         if _SEP_UNSAFE.match(self.sep):
             raise ValueError(
                 'Unsafe Signer separator: %r (cannot be empty or consist of '
                 'only A-z0-9-_=)' % sep,
             )
-        self.salt = force_str(salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__))
+        self.salt = salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
 
     def signature(self, value):
-        signature = base64_hmac(self.salt + 'signer', value, self.key)
-        # Convert the signature from bytes to str only on Python 3
-        return force_str(signature)
+        return force_text(base64_hmac(self.salt + 'signer', value, self.key))
 
     def sign(self, value):
-        value = force_str(value)
-        return str('%s%s%s') % (value, self.sep, self.signature(value))
+        return '%s%s%s' % (value, self.sep, self.signature(value))
 
     def unsign(self, signed_value):
-        signed_value = force_str(signed_value)
         if self.sep not in signed_value:
             raise BadSignature('No "%s" found in value' % self.sep)
         value, sig = signed_value.rsplit(self.sep, 1)
@@ -185,8 +181,7 @@ class TimestampSigner(Signer):
         return baseconv.base62.encode(int(time.time()))
 
     def sign(self, value):
-        value = force_str(value)
-        value = str('%s%s%s') % (value, self.sep, self.timestamp())
+        value = '%s%s%s' % (force_text(value), self.sep, self.timestamp())
         return super(TimestampSigner, self).sign(value)
 
     def unsign(self, value, max_age=None):

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

@@ -12,7 +12,6 @@ from django.db import utils
 from django.db.backends import utils as backend_utils
 from django.db.backends.base.base import BaseDatabaseWrapper
 from django.utils import six
-from django.utils.encoding import force_str
 from django.utils.functional import cached_property
 from django.utils.safestring import SafeBytes, SafeText
 
@@ -225,7 +224,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         if settings_dict['NAME']:
             kwargs['db'] = settings_dict['NAME']
         if settings_dict['PASSWORD']:
-            kwargs['passwd'] = force_str(settings_dict['PASSWORD'])
+            kwargs['passwd'] = settings_dict['PASSWORD']
         if settings_dict['HOST'].startswith('/'):
             kwargs['unix_socket'] = settings_dict['HOST']
         elif settings_dict['HOST']:

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

@@ -12,7 +12,6 @@ from django.core.exceptions import ImproperlyConfigured
 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.encoding import force_str
 from django.utils.functional import cached_property
 from django.utils.safestring import SafeBytes, SafeText
 
@@ -160,7 +159,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         if settings_dict['USER']:
             conn_params['user'] = settings_dict['USER']
         if settings_dict['PASSWORD']:
-            conn_params['password'] = force_str(settings_dict['PASSWORD'])
+            conn_params['password'] = settings_dict['PASSWORD']
         if settings_dict['HOST']:
             conn_params['host'] = settings_dict['HOST']
         if settings_dict['PORT']:

+ 2 - 2
django/db/models/base.py

@@ -26,7 +26,7 @@ from django.db.models.signals import (
     class_prepared, post_init, post_save, pre_init, pre_save,
 )
 from django.db.models.utils import make_model_tuple
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.functional import curry
 from django.utils.text import capfirst, get_text_list
 from django.utils.translation import ugettext_lazy as _
@@ -505,7 +505,7 @@ class Model(metaclass=ModelBase):
             u = str(self)
         except (UnicodeEncodeError, UnicodeDecodeError):
             u = '[Bad Unicode data]'
-        return force_str('<%s: %s>' % (self.__class__.__name__, u))
+        return '<%s: %s>' % (self.__class__.__name__, u)
 
     def __str__(self):
         return '%s object' % self.__class__.__name__

+ 2 - 2
django/db/models/fields/files.py

@@ -9,7 +9,7 @@ from django.core.files.storage import default_storage
 from django.core.validators import validate_image_file_extension
 from django.db.models import signals
 from django.db.models.fields import Field
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -304,7 +304,7 @@ class FileField(Field):
         if callable(self.upload_to):
             filename = self.upload_to(instance, filename)
         else:
-            dirname = force_text(datetime.datetime.now().strftime(force_str(self.upload_to)))
+            dirname = force_text(datetime.datetime.now().strftime(self.upload_to))
             filename = posixpath.join(dirname, filename)
         return self.storage.generate_filename(filename)
 

+ 4 - 4
django/forms/fields.py

@@ -29,7 +29,7 @@ from django.forms.widgets import (
 from django.utils import formats, six
 from django.utils.dateparse import parse_duration
 from django.utils.duration import duration_string
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.ipv6 import clean_ipv6_address
 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
 
@@ -429,7 +429,7 @@ class DateField(BaseTemporalField):
         return super(DateField, self).to_python(value)
 
     def strptime(self, value, format):
-        return datetime.datetime.strptime(force_str(value), format).date()
+        return datetime.datetime.strptime(value, format).date()
 
 
 class TimeField(BaseTemporalField):
@@ -451,7 +451,7 @@ class TimeField(BaseTemporalField):
         return super(TimeField, self).to_python(value)
 
     def strptime(self, value, format):
-        return datetime.datetime.strptime(force_str(value), format).time()
+        return datetime.datetime.strptime(value, format).time()
 
 
 class DateTimeField(BaseTemporalField):
@@ -482,7 +482,7 @@ class DateTimeField(BaseTemporalField):
         return from_current_timezone(result)
 
     def strptime(self, value, format):
-        return datetime.datetime.strptime(force_str(value), format)
+        return datetime.datetime.strptime(value, format)
 
 
 class DurationField(Field):

+ 2 - 2
django/forms/widgets.py

@@ -13,7 +13,7 @@ from django.forms.utils import to_current_timezone
 from django.templatetags.static import static
 from django.utils import datetime_safe, formats
 from django.utils.dates import MONTHS
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.formats import get_format
 from django.utils.html import format_html, html_safe
 from django.utils.safestring import mark_safe
@@ -986,7 +986,7 @@ class SelectDateWidget(Widget):
             if settings.USE_L10N:
                 try:
                     input_format = get_format('DATE_INPUT_FORMATS')[0]
-                    d = datetime.datetime.strptime(force_str(value), input_format)
+                    d = datetime.datetime.strptime(value, input_format)
                     year, month, day = d.year, d.month, d.day
                 except ValueError:
                     pass

+ 3 - 7
django/http/request.py

@@ -14,9 +14,7 @@ from django.core.files import uploadhandler
 from django.http.multipartparser import MultiPartParser, MultiPartParserError
 from django.utils import six
 from django.utils.datastructures import ImmutableList, MultiValueDict
-from django.utils.encoding import (
-    escape_uri_path, force_bytes, force_str, iri_to_uri,
-)
+from django.utils.encoding import escape_uri_path, force_bytes, iri_to_uri
 from django.utils.http import is_same_domain, limited_parse_qsl
 
 RAISE_ERROR = object()
@@ -64,10 +62,8 @@ class HttpRequest:
 
     def __repr__(self):
         if self.method is None or not self.get_full_path():
-            return force_str('<%s>' % self.__class__.__name__)
-        return force_str(
-            '<%s: %s %r>' % (self.__class__.__name__, self.method, force_str(self.get_full_path()))
-        )
+            return '<%s>' % self.__class__.__name__
+        return '<%s: %s %r>' % (self.__class__.__name__, self.method, self.get_full_path())
 
     def _get_raw_host(self):
         """

+ 1 - 4
django/http/response.py

@@ -13,9 +13,7 @@ from django.core.exceptions import DisallowedRedirect
 from django.core.serializers.json import DjangoJSONEncoder
 from django.http.cookie import SimpleCookie
 from django.utils import timezone
-from django.utils.encoding import (
-    force_bytes, force_str, force_text, iri_to_uri,
-)
+from django.utils.encoding import force_bytes, force_text, iri_to_uri
 from django.utils.http import cookie_date
 
 _charset_from_content_type_re = re.compile(r';\s*charset=(?P<charset>[^\s;]+)', re.I)
@@ -170,7 +168,6 @@ class HttpResponseBase:
         - an aware ``datetime.datetime`` object in any time zone.
         If it is a ``datetime.datetime`` object then ``max_age`` will be calculated.
         """
-        value = force_str(value)
         self.cookies[key] = value
         if expires is not None:
             if isinstance(expires, datetime.datetime):

+ 2 - 3
django/template/base.py

@@ -56,7 +56,7 @@ import re
 from django.template.context import (  # NOQA: imported for backwards compatibility
     BaseContext, Context, ContextPopException, RequestContext,
 )
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.formats import localize
 from django.utils.html import conditional_escape, escape
 from django.utils.inspect import getargspec
@@ -971,8 +971,7 @@ class TextNode(Node):
         self.s = s
 
     def __repr__(self):
-        rep = "<%s: %r>" % (self.__class__.__name__, self.s[:25])
-        return force_str(rep, 'ascii', errors='replace')
+        return "<%s: %r>" % (self.__class__.__name__, self.s[:25])
 
     def render(self, context):
         return self.s

+ 5 - 5
django/test/client.py

@@ -21,7 +21,7 @@ from django.test import signals
 from django.test.utils import ContextList
 from django.urls import resolve
 from django.utils import six
-from django.utils.encoding import force_bytes, force_str, uri_to_iri
+from django.utils.encoding import force_bytes, uri_to_iri
 from django.utils.functional import SimpleLazyObject, curry
 from django.utils.http import urlencode
 from django.utils.itercompat import is_iterable
@@ -317,10 +317,10 @@ class RequestFactory:
             return force_bytes(data, encoding=charset)
 
     def _get_path(self, parsed):
-        path = force_str(parsed[2])
+        path = parsed.path
         # If there are parameters, add them
-        if parsed[3]:
-            path += str(";") + force_str(parsed[3])
+        if parsed.params:
+            path += ";" + parsed.params
         path = uri_to_iri(path).encode(UTF_8)
         # Replace the behavior where non-ASCII values in the WSGI environ are
         # arbitrarily decoded with ISO-8859-1.
@@ -389,7 +389,7 @@ class RequestFactory:
                 content_type='application/octet-stream', secure=False,
                 **extra):
         """Constructs an arbitrary HTTP request."""
-        parsed = urlparse(force_str(path))
+        parsed = urlparse(str(path))  # path can be lazy
         data = force_bytes(data, settings.DEFAULT_CHARSET)
         r = {
             'PATH_INFO': self._get_path(parsed),

+ 1 - 2
django/test/utils.py

@@ -23,7 +23,6 @@ from django.template import Template
 from django.test.signals import setting_changed, template_rendered
 from django.urls import get_script_prefix, set_script_prefix
 from django.utils.decorators import available_attrs
-from django.utils.encoding import force_str
 from django.utils.translation import deactivate
 
 try:
@@ -317,7 +316,7 @@ def get_runner(settings, test_runner_class=None):
         test_module_name = '.'.join(test_path[:-1])
     else:
         test_module_name = '.'
-    test_module = __import__(test_module_name, {}, {}, force_str(test_path[-1]))
+    test_module = __import__(test_module_name, {}, {}, test_path[-1])
     test_runner = getattr(test_module, test_path[-1])
     return test_runner
 

+ 2 - 2
django/urls/resolvers.py

@@ -15,7 +15,7 @@ from django.core.checks import Warning
 from django.core.checks.urls import check_resolver
 from django.core.exceptions import ImproperlyConfigured
 from django.utils.datastructures import MultiValueDict
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.functional import cached_property
 from django.utils.http import RFC3986_SUBDELIMS, urlquote
 from django.utils.regex_helper import normalize
@@ -160,7 +160,7 @@ class RegexURLPattern(LocaleRegexProvider):
         self.name = name
 
     def __repr__(self):
-        return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
+        return '<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern)
 
     def check(self):
         warnings = self._check_pattern_name()

+ 3 - 5
django/utils/formats.py

@@ -5,7 +5,6 @@ from importlib import import_module
 
 from django.conf import settings
 from django.utils import dateformat, datetime_safe, numberformat
-from django.utils.encoding import force_str
 from django.utils.functional import lazy
 from django.utils.safestring import mark_safe
 from django.utils.translation import (
@@ -111,7 +110,6 @@ def get_format(format_type, lang=None, use_l10n=None):
     If use_l10n is provided and is not None, that will force the value to
     be localized (or not), overriding the value of settings.USE_L10N.
     """
-    format_type = force_str(format_type)
     use_l10n = use_l10n or (use_l10n is None and settings.USE_L10N)
     if use_l10n and lang is None:
         lang = get_language()
@@ -229,14 +227,14 @@ def localize_input(value, default=None):
         return number_format(value)
     elif isinstance(value, datetime.datetime):
         value = datetime_safe.new_datetime(value)
-        format = force_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
+        format = default or get_format('DATETIME_INPUT_FORMATS')[0]
         return value.strftime(format)
     elif isinstance(value, datetime.date):
         value = datetime_safe.new_date(value)
-        format = force_str(default or get_format('DATE_INPUT_FORMATS')[0])
+        format = default or get_format('DATE_INPUT_FORMATS')[0]
         return value.strftime(format)
     elif isinstance(value, datetime.time):
-        format = force_str(default or get_format('TIME_INPUT_FORMATS')[0])
+        format = default or get_format('TIME_INPUT_FORMATS')[0]
         return value.strftime(format)
     return value
 

+ 3 - 3
django/utils/html.py

@@ -5,7 +5,7 @@ from urllib.parse import (
     parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit,
 )
 
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.functional import keep_lazy, keep_lazy_text
 from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
 from django.utils.safestring import SafeData, SafeText, mark_safe
@@ -189,7 +189,7 @@ def strip_spaces_between_tags(value):
 def smart_urlquote(url):
     "Quotes a URL if it isn't already quoted."
     def unquote_quote(segment):
-        segment = unquote(force_str(segment))
+        segment = unquote(segment)
         # Tilde is part of RFC3986 Unreserved Characters
         # http://tools.ietf.org/html/rfc3986#section-2.3
         # See also http://bugs.python.org/issue16285
@@ -211,7 +211,7 @@ def smart_urlquote(url):
     if query:
         # Separately unquoting key/value, so as to not mix querystring separators
         # included in query values. See #22267.
-        query_parts = [(unquote(force_str(q[0])), unquote(force_str(q[1])))
+        query_parts = [(unquote(q[0]), unquote(q[1]))
                        for q in parse_qsl(query, keep_blank_values=True)]
         # urlencode will take care of quoting
         query = urlencode(query_parts)

+ 3 - 3
django/utils/tree.py

@@ -5,7 +5,7 @@ ORM.
 
 import copy
 
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 
 
 class Node:
@@ -45,10 +45,10 @@ class Node:
 
     def __str__(self):
         template = '(NOT (%s: %s))' if self.negated else '(%s: %s)'
-        return force_str(template % (self.connector, ', '.join(force_text(c) for c in self.children)))
+        return template % (self.connector, ', '.join(force_text(c) for c in self.children))
 
     def __repr__(self):
-        return str("<%s: %s>") % (self.__class__.__name__, self)
+        return "<%s: %s>" % (self.__class__.__name__, self)
 
     def __deepcopy__(self, memodict):
         """

+ 2 - 2
django/views/debug.py

@@ -10,7 +10,7 @@ from django.template.defaultfilters import force_escape, pprint
 from django.urls import Resolver404, resolve
 from django.utils import timezone
 from django.utils.datastructures import MultiValueDict
-from django.utils.encoding import force_bytes, force_text
+from django.utils.encoding import force_text
 from django.utils.module_loading import import_string
 from django.utils.translation import ugettext as _
 
@@ -505,7 +505,7 @@ def technical_404_response(request, exception):
         'root_urlconf': settings.ROOT_URLCONF,
         'request_path': error_url,
         'urlpatterns': tried,
-        'reason': force_bytes(exception, errors='replace'),
+        'reason': str(exception),
         'request': request,
         'settings': get_safe_settings(),
         'raising_view_name': caller,

+ 2 - 2
django/views/generic/dates.py

@@ -5,7 +5,7 @@ from django.core.exceptions import ImproperlyConfigured
 from django.db import models
 from django.http import Http404
 from django.utils import timezone
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 from django.utils.functional import cached_property
 from django.utils.translation import ugettext as _
 from django.views.generic.base import View
@@ -687,7 +687,7 @@ def _date_from_string(year, year_format, month='', month_format='', day='', day_
     format = delim.join((year_format, month_format, day_format))
     datestr = delim.join((year, month, day))
     try:
-        return datetime.datetime.strptime(force_str(datestr), format).date()
+        return datetime.datetime.strptime(datestr, format).date()
     except ValueError:
         raise Http404(_("Invalid date string '%(datestr)s' given format '%(format)s'") % {
             'datestr': datestr,

+ 1 - 1
tests/admin_scripts/tests.py

@@ -1397,7 +1397,7 @@ class ManageRunserverEmptyAllowedHosts(AdminScriptTestCase):
 class ManageTestserver(AdminScriptTestCase):
     from django.core.management.commands.testserver import Command as TestserverCommand
 
-    @mock.patch.object(TestserverCommand, 'handle')
+    @mock.patch.object(TestserverCommand, 'handle', return_value='')
     def test_testserver_handle_params(self, mock_handle):
         out = StringIO()
         call_command('testserver', 'blah.json', stdout=out)

+ 1 - 5
tests/admin_utils/tests.py

@@ -217,13 +217,9 @@ class UtilsTests(SimpleTestCase):
             ("History", None)
         )
 
-        self.assertEqual(
-            label_for_field("__unicode__", Article),
-            "article"
-        )
         self.assertEqual(
             label_for_field("__str__", Article),
-            str("article")
+            "article"
         )
 
         with self.assertRaises(AttributeError):

+ 1 - 2
tests/auth_tests/test_management.py

@@ -15,7 +15,6 @@ from django.core.management import call_command
 from django.core.management.base import CommandError
 from django.db import migrations
 from django.test import TestCase, mock, override_settings
-from django.utils.encoding import force_str
 from django.utils.translation import ugettext_lazy as _
 
 from .models import (
@@ -44,7 +43,7 @@ def mock_inputs(inputs):
                 assert str('__proxy__') not in prompt
                 response = ''
                 for key, val in inputs.items():
-                    if force_str(key) in prompt.lower():
+                    if key in prompt.lower():
                         response = val
                         break
                 return response

+ 2 - 2
tests/contenttypes_tests/tests.py

@@ -15,7 +15,7 @@ from django.test import (
     SimpleTestCase, TestCase, TransactionTestCase, mock, override_settings,
 )
 from django.test.utils import captured_stdout, isolate_apps
-from django.utils.encoding import force_str, force_text
+from django.utils.encoding import force_text
 
 from .models import (
     Article, Author, ModelWithNullFKToSite, Post, SchemeIncludedURL,
@@ -144,7 +144,7 @@ class GenericForeignKeyTests(SimpleTestCase):
         class Model(models.Model):
             field = GenericForeignKey()
         expected = "contenttypes_tests.Model.field"
-        actual = force_str(Model.field)
+        actual = force_text(Model.field)
         self.assertEqual(expected, actual)
 
     def test_missing_content_type_field(self):

+ 10 - 20
tests/dbshell/test_postgresql_psycopg2.py

@@ -1,9 +1,7 @@
-import locale
 import os
 
 from django.db.backends.postgresql.client import DatabaseClient
 from django.test import SimpleTestCase, mock
-from django.utils.encoding import force_bytes, force_str
 
 
 class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
@@ -13,13 +11,12 @@ class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
         That function invokes the runshell command, while mocking
         subprocess.call. It returns a 2-tuple with:
         - The command line list
-        - The binary content of file pointed by environment PGPASSFILE, or
-          None.
+        - The content of the file pointed by environment PGPASSFILE, or None.
         """
         def _mock_subprocess_call(*args):
             self.subprocess_args = list(*args)
             if 'PGPASSFILE' in os.environ:
-                with open(os.environ['PGPASSFILE'], 'rb') as f:
+                with open(os.environ['PGPASSFILE'], 'r') as f:
                     self.pgpass = f.read().strip()  # ignore line endings
             else:
                 self.pgpass = None
@@ -40,7 +37,7 @@ class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
                 'port': '444',
             }), (
                 ['psql', '-U', 'someuser', '-h', 'somehost', '-p', '444', 'dbname'],
-                b'somehost:444:dbname:someuser:somepassword',
+                'somehost:444:dbname:someuser:somepassword',
             )
         )
 
@@ -67,7 +64,7 @@ class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
                 'port': '444',
             }), (
                 ['psql', '-U', 'some:user', '-h', '::1', '-p', '444', 'dbname'],
-                b'\\:\\:1:444:dbname:some\\:user:some\\:password',
+                '\\:\\:1:444:dbname:some\\:user:some\\:password',
             )
         )
 
@@ -81,30 +78,23 @@ class PostgreSqlDbshellCommandTestCase(SimpleTestCase):
                 'port': '444',
             }), (
                 ['psql', '-U', 'some\\user', '-h', 'somehost', '-p', '444', 'dbname'],
-                b'somehost:444:dbname:some\\\\user:some\\\\password',
+                'somehost:444:dbname:some\\\\user:some\\\\password',
             )
         )
 
     def test_accent(self):
-        # The pgpass temporary file needs to be encoded using the system locale.
-        encoding = locale.getpreferredencoding()
         username = 'rôle'
         password = 'sésame'
-        username_str = force_str(username, encoding)
-        password_str = force_str(password, encoding)
-        pgpass_bytes = force_bytes(
-            'somehost:444:dbname:%s:%s' % (username, password),
-            encoding=encoding,
-        )
+        pgpass_string = 'somehost:444:dbname:%s:%s' % (username, password)
         self.assertEqual(
             self._run_it({
                 'database': 'dbname',
-                'user': username_str,
-                'password': password_str,
+                'user': username,
+                'password': password,
                 'host': 'somehost',
                 'port': '444',
             }), (
-                ['psql', '-U', username_str, '-h', 'somehost', '-p', '444', 'dbname'],
-                pgpass_bytes,
+                ['psql', '-U', username, '-h', 'somehost', '-p', '444', 'dbname'],
+                pgpass_string,
             )
         )

+ 2 - 4
tests/file_uploads/views.py

@@ -4,7 +4,7 @@ import os
 
 from django.core.files.uploadedfile import UploadedFile
 from django.http import HttpResponse, HttpResponseServerError
-from django.utils.encoding import force_bytes, force_str
+from django.utils.encoding import force_bytes, force_text
 
 from .models import FileModel
 from .tests import UNICODE_FILENAME, UPLOAD_TO
@@ -152,9 +152,7 @@ def file_upload_content_type_extra(request):
     """
     params = {}
     for file_name, uploadedfile in request.FILES.items():
-        params[file_name] = {
-            k: force_str(v) for k, v in uploadedfile.content_type_extra.items()
-        }
+        params[file_name] = {k: force_text(v) for k, v in uploadedfile.content_type_extra.items()}
     return HttpResponse(json.dumps(params))
 
 

+ 1 - 2
tests/generic_views/test_list.py

@@ -2,7 +2,6 @@ import datetime
 
 from django.core.exceptions import ImproperlyConfigured
 from django.test import TestCase, override_settings
-from django.utils.encoding import force_str
 from django.views.generic.base import View
 
 from .models import Artist, Author, Book, Page
@@ -235,7 +234,7 @@ class ListViewTests(TestCase):
         self._make_authors(1)
         res = self.client.get('/list/authors/paginated/2/')
         self.assertEqual(res.status_code, 404)
-        self.assertEqual(force_str(res.context.get('reason')), "Invalid page (2): That page contains no results")
+        self.assertEqual(res.context.get('reason'), "Invalid page (2): That page contains no results")
 
     def _make_authors(self, n):
         Author.objects.all().delete()

+ 1 - 5
tests/handlers/tests.py

@@ -7,7 +7,6 @@ from django.db import close_old_connections, connection
 from django.test import (
     RequestFactory, SimpleTestCase, TransactionTestCase, override_settings,
 )
-from django.utils.encoding import force_str
 
 try:
     from http import HTTPStatus
@@ -65,10 +64,7 @@ class HandlerTests(SimpleTestCase):
         raw_cookie = 'want="café"'.encode('utf-8').decode('iso-8859-1')
         environ['HTTP_COOKIE'] = raw_cookie
         request = WSGIRequest(environ)
-        # If would be nicer if request.COOKIES returned unicode values.
-        # However the current cookie parser doesn't do this and fixing it is
-        # much more work than fixing #20557. Feel free to remove force_str()!
-        self.assertEqual(request.COOKIES['want'], force_str("café"))
+        self.assertEqual(request.COOKIES['want'], "café")
 
     def test_invalid_unicode_cookie(self):
         """

+ 2 - 8
tests/httpwrappers/tests.py

@@ -17,7 +17,6 @@ from django.http import (
 )
 from django.test import SimpleTestCase
 from django.utils._os import upath
-from django.utils.encoding import force_str
 from django.utils.functional import lazystr
 
 
@@ -294,13 +293,8 @@ class HttpResponseTests(unittest.TestCase):
         self.assertIsInstance(r['key'], str)
         self.assertIn(b'test', r.serialize_headers())
 
-        # Latin-1 unicode or bytes values are also converted to native strings.
+        # Non-ASCII values are serialized to Latin-1.
         r['key'] = 'café'
-        self.assertEqual(r['key'], force_str('café', 'latin-1'))
-        self.assertIsInstance(r['key'], str)
-        r['key'] = 'café'.encode('latin-1')
-        self.assertEqual(r['key'], force_str('café', 'latin-1'))
-        self.assertIsInstance(r['key'], str)
         self.assertIn('café'.encode('latin-1'), r.serialize_headers())
 
         # Other unicode values are MIME-encoded (there's no way to pass them as bytes).
@@ -759,7 +753,7 @@ class CookieTests(unittest.TestCase):
         # More characters the spec forbids.
         self.assertEqual(parse_cookie('a   b,c<>@:/[]?{}=d  "  =e,f g'), {'a   b,c<>@:/[]?{}': 'd  "  =e,f g'})
         # Unicode characters. The spec only allows ASCII.
-        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': force_str('André Bessette')})
+        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': 'André Bessette'})
         # Browsers don't send extra whitespace or semicolons in Cookie headers,
         # but parse_cookie() should parse whitespace the same way
         # document.cookie parses whitespace.

+ 1 - 2
tests/middleware/tests.py

@@ -22,7 +22,6 @@ from django.test import (
     RequestFactory, SimpleTestCase, ignore_warnings, override_settings,
 )
 from django.utils.deprecation import RemovedInDjango21Warning
-from django.utils.encoding import force_str
 
 int2byte = struct.Struct(">B").pack
 
@@ -350,7 +349,7 @@ class CommonMiddlewareTest(SimpleTestCase):
     def test_non_ascii_query_string_does_not_crash(self):
         """Regression test for #15152"""
         request = self.rf.get('/slash')
-        request.META['QUERY_STRING'] = force_str('drink=café')
+        request.META['QUERY_STRING'] = 'drink=café'
         r = CommonMiddleware().process_request(request)
         self.assertEqual(r.status_code, 301)
 

+ 1 - 2
tests/migrations/test_writer.py

@@ -24,7 +24,6 @@ from django.test import SimpleTestCase, ignore_warnings, mock
 from django.utils import datetime_safe
 from django.utils._os import upath
 from django.utils.deconstruct import deconstructible
-from django.utils.encoding import force_str
 from django.utils.functional import SimpleLazyObject
 from django.utils.timezone import FixedOffset, get_default_timezone, utc
 from django.utils.translation import ugettext_lazy as _
@@ -170,7 +169,7 @@ class WriterTests(SimpleTestCase):
     def safe_exec(self, string, value=None):
         d = {}
         try:
-            exec(force_str(string), globals(), d)
+            exec(string, globals(), d)
         except Exception as e:
             if value:
                 self.fail("Could not exec %r (from value %r): %s" % (string.strip(), value, e))

+ 2 - 3
tests/or_lookups/tests.py

@@ -3,7 +3,6 @@ from operator import attrgetter
 
 from django.db.models import Q
 from django.test import TestCase
-from django.utils.encoding import force_str
 
 from .models import Article
 
@@ -124,9 +123,9 @@ class OrLookupsTests(TestCase):
 
     def test_q_repr(self):
         or_expr = Q(baz=Article(headline="Foö"))
-        self.assertEqual(repr(or_expr), force_str("<Q: (AND: ('baz', <Article: Foö>))>"))
+        self.assertEqual(repr(or_expr), "<Q: (AND: ('baz', <Article: Foö>))>")
         negated_or = ~Q(baz=Article(headline="Foö"))
-        self.assertEqual(repr(negated_or), force_str("<Q: (NOT (AND: ('baz', <Article: Foö>)))>"))
+        self.assertEqual(repr(negated_or), "<Q: (NOT (AND: ('baz', <Article: Foö>)))>")
 
     def test_q_negated(self):
         # Q objects can be negated

+ 1 - 2
tests/requests/tests.py

@@ -14,7 +14,6 @@ from django.http.request import split_domain_port
 from django.test import RequestFactory, SimpleTestCase, override_settings
 from django.test.client import FakePayload
 from django.test.utils import freeze_time, str_prefix
-from django.utils.encoding import force_str
 from django.utils.http import cookie_date, urlencode
 from django.utils.timezone import utc
 
@@ -270,7 +269,7 @@ class RequestsTests(SimpleTestCase):
         response = HttpResponse()
         cookie_value = '清風'
         response.set_cookie('test', cookie_value)
-        self.assertEqual(force_str(cookie_value), response.cookies['test'].value)
+        self.assertEqual(cookie_value, response.cookies['test'].value)
 
     def test_limited_stream(self):
         # Read all of a limited stream

+ 1 - 2
tests/signing/tests.py

@@ -3,7 +3,6 @@ import datetime
 from django.core import signing
 from django.test import SimpleTestCase
 from django.test.utils import freeze_time
-from django.utils.encoding import force_str
 
 
 class TestSigner(SimpleTestCase):
@@ -47,7 +46,7 @@ class TestSigner(SimpleTestCase):
         for example in examples:
             signed = signer.sign(example)
             self.assertIsInstance(signed, str)
-            self.assertNotEqual(force_str(example), signed)
+            self.assertNotEqual(example, signed)
             self.assertEqual(example, signer.unsign(signed))
 
     def test_unsign_detects_tampering(self):