summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Rogaski <mrogaski@pobox.com>2017-08-28 12:40:27 -0400
committerTim Graham <timograham@gmail.com>2017-08-31 07:33:01 -0400
commit80a0016c49331bf0a14ef76e714acbff6c6640bd (patch)
tree3bb54b3aada8e44f5e13874c100b22a4ebac4158
parent046b8c80ce76ed1d410910aa92f67c405b8a15ba (diff)
[1.11.x] Fixed #28487 -- Fixed runserver crash with non-Unicode system encodings on Python 2 + Windows.
-rw-r--r--django/utils/autoreload.py6
-rw-r--r--docs/releases/1.11.5.txt3
-rw-r--r--tests/utils_tests/test_autoreload.py31
3 files changed, 36 insertions, 4 deletions
diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py
index cf2cefeea9..7a9702aebb 100644
--- a/django/utils/autoreload.py
+++ b/django/utils/autoreload.py
@@ -40,7 +40,7 @@ from django.conf import settings
from django.core.signals import request_finished
from django.utils import six
from django.utils._os import npath
-from django.utils.encoding import force_bytes, get_system_encoding
+from django.utils.encoding import get_system_encoding
from django.utils.six.moves import _thread as thread
# This import does nothing, but it's necessary to avoid some race conditions
@@ -290,8 +290,8 @@ def restart_with_reloader():
# Environment variables on Python 2 + Windows must be str.
encoding = get_system_encoding()
for key in new_environ.keys():
- str_key = force_bytes(key, encoding=encoding)
- str_value = force_bytes(new_environ[key], encoding=encoding)
+ str_key = key.decode(encoding).encode('utf-8')
+ str_value = new_environ[key].decode(encoding).encode('utf-8')
del new_environ[key]
new_environ[str_key] = str_value
new_environ["RUN_MAIN"] = 'true'
diff --git a/docs/releases/1.11.5.txt b/docs/releases/1.11.5.txt
index 92fa8820a0..91620eb740 100644
--- a/docs/releases/1.11.5.txt
+++ b/docs/releases/1.11.5.txt
@@ -32,3 +32,6 @@ Bugfixes
* Fixed a regression where ``SelectDateWidget`` localized the years in the
select box (:ticket:`28530`).
+
+* Fixed a regression in 1.11.4 where ``runserver`` crashed with non-Unicode
+ system encodings on Python 2 + Windows (:ticket:`28487`).
diff --git a/tests/utils_tests/test_autoreload.py b/tests/utils_tests/test_autoreload.py
index 78206135fa..cab48309fb 100644
--- a/tests/utils_tests/test_autoreload.py
+++ b/tests/utils_tests/test_autoreload.py
@@ -5,13 +5,14 @@ import os
import shutil
import sys
import tempfile
+import unittest
from importlib import import_module
from django import conf
from django.contrib import admin
from django.test import SimpleTestCase, mock, override_settings
from django.test.utils import extend_sys_path
-from django.utils import autoreload
+from django.utils import autoreload, six
from django.utils._os import npath, upath
from django.utils.six.moves import _thread
from django.utils.translation import trans_real
@@ -258,6 +259,13 @@ class ResetTranslationsTests(SimpleTestCase):
class TestRestartWithReloader(SimpleTestCase):
+ def setUp(self):
+ self._orig_environ = os.environ.copy()
+
+ def tearDown(self):
+ os.environ.clear()
+ os.environ.update(self._orig_environ)
+
def test_environment(self):
""""
With Python 2 on Windows, restart_with_reloader() coerces environment
@@ -268,3 +276,24 @@ class TestRestartWithReloader(SimpleTestCase):
os.environ['SPAM'] = 'spam'
with mock.patch.object(sys, 'argv', ['-c', 'pass']):
autoreload.restart_with_reloader()
+
+ @unittest.skipUnless(six.PY2 and sys.platform == 'win32', 'This is a Python 2 + Windows-specific issue.')
+ def test_environment_decoding(self):
+ """The system encoding is used for decoding."""
+ os.environ['SPAM'] = 'spam'
+ os.environ['EGGS'] = b'\xc6u vi komprenas?'
+ with mock.patch('locale.getdefaultlocale') as default_locale:
+ # Latin-3 is the correct mapping.
+ default_locale.return_value = ('eo', 'latin3')
+ with mock.patch.object(sys, 'argv', ['-c', 'pass']):
+ autoreload.restart_with_reloader()
+ # CP1252 interprets latin3's C circumflex as AE ligature.
+ # It's incorrect but doesn't raise an error.
+ default_locale.return_value = ('en_US', 'cp1252')
+ with mock.patch.object(sys, 'argv', ['-c', 'pass']):
+ autoreload.restart_with_reloader()
+ # Interpreting the string as UTF-8 is fatal.
+ with self.assertRaises(UnicodeDecodeError):
+ default_locale.return_value = ('en_US', 'utf-8')
+ with mock.patch.object(sys, 'argv', ['-c', 'pass']):
+ autoreload.restart_with_reloader()