[1.11.x] Fixed #28487 -- Fixed runserver crash with non-Unicode system encodings on Python 2 + Windows.
This commit is contained in:
parent
046b8c80ce
commit
80a0016c49
@ -40,7 +40,7 @@ from django.conf import settings
|
|||||||
from django.core.signals import request_finished
|
from django.core.signals import request_finished
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils._os import npath
|
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
|
from django.utils.six.moves import _thread as thread
|
||||||
|
|
||||||
# This import does nothing, but it's necessary to avoid some race conditions
|
# 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.
|
# Environment variables on Python 2 + Windows must be str.
|
||||||
encoding = get_system_encoding()
|
encoding = get_system_encoding()
|
||||||
for key in new_environ.keys():
|
for key in new_environ.keys():
|
||||||
str_key = force_bytes(key, encoding=encoding)
|
str_key = key.decode(encoding).encode('utf-8')
|
||||||
str_value = force_bytes(new_environ[key], encoding=encoding)
|
str_value = new_environ[key].decode(encoding).encode('utf-8')
|
||||||
del new_environ[key]
|
del new_environ[key]
|
||||||
new_environ[str_key] = str_value
|
new_environ[str_key] = str_value
|
||||||
new_environ["RUN_MAIN"] = 'true'
|
new_environ["RUN_MAIN"] = 'true'
|
||||||
|
@ -32,3 +32,6 @@ Bugfixes
|
|||||||
|
|
||||||
* Fixed a regression where ``SelectDateWidget`` localized the years in the
|
* Fixed a regression where ``SelectDateWidget`` localized the years in the
|
||||||
select box (:ticket:`28530`).
|
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`).
|
||||||
|
@ -5,13 +5,14 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import unittest
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django import conf
|
from django import conf
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.test import SimpleTestCase, mock, override_settings
|
from django.test import SimpleTestCase, mock, override_settings
|
||||||
from django.test.utils import extend_sys_path
|
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._os import npath, upath
|
||||||
from django.utils.six.moves import _thread
|
from django.utils.six.moves import _thread
|
||||||
from django.utils.translation import trans_real
|
from django.utils.translation import trans_real
|
||||||
@ -258,6 +259,13 @@ class ResetTranslationsTests(SimpleTestCase):
|
|||||||
|
|
||||||
class TestRestartWithReloader(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):
|
def test_environment(self):
|
||||||
""""
|
""""
|
||||||
With Python 2 on Windows, restart_with_reloader() coerces environment
|
With Python 2 on Windows, restart_with_reloader() coerces environment
|
||||||
@ -268,3 +276,24 @@ class TestRestartWithReloader(SimpleTestCase):
|
|||||||
os.environ['SPAM'] = 'spam'
|
os.environ['SPAM'] = 'spam'
|
||||||
with mock.patch.object(sys, 'argv', ['-c', 'pass']):
|
with mock.patch.object(sys, 'argv', ['-c', 'pass']):
|
||||||
autoreload.restart_with_reloader()
|
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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user