[1.11.x] Fixed #28174 -- Fixed crash in runserver's autoreload with Python 2 on Windows with non-str environment variables.

This commit is contained in:
Mark Rogaski 2017-07-12 00:59:46 -04:00 committed by Tim Graham
parent 30f334cc58
commit fc6b90bdb7
3 changed files with 29 additions and 0 deletions

View File

@ -40,6 +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.six.moves import _thread as thread
# This import does nothing, but it's necessary to avoid some race conditions
@ -285,6 +286,14 @@ def restart_with_reloader():
while True:
args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv
new_environ = os.environ.copy()
if _win and six.PY2:
# 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)
del new_environ[key]
new_environ[str_key] = str_value
new_environ["RUN_MAIN"] = 'true'
exit_code = subprocess.call(args, env=new_environ)
if exit_code != 3:

View File

@ -18,3 +18,6 @@ Bugfixes
* Fixed a regression in pickling of ``LazyObject`` on Python 2 when the wrapped
object doesn't have ``__reduce__()`` (:ticket:`28389`).
* Fixed crash in ``runserver``'s ``autoreload`` with Python 2 on Windows with
non-``str`` environment variables (:ticket:`28174`).

View File

@ -1,6 +1,9 @@
from __future__ import unicode_literals
import gettext
import os
import shutil
import sys
import tempfile
from importlib import import_module
@ -251,3 +254,17 @@ class ResetTranslationsTests(SimpleTestCase):
self.assertEqual(trans_real._translations, {})
self.assertIsNone(trans_real._default)
self.assertIsInstance(trans_real._active, _thread._local)
class TestRestartWithReloader(SimpleTestCase):
def test_environment(self):
""""
With Python 2 on Windows, restart_with_reloader() coerces environment
variables to str to avoid "TypeError: environment can only contain
strings" in Python's subprocess.py.
"""
# With unicode_literals, these values are unicode.
os.environ['SPAM'] = 'spam'
with mock.patch.object(sys, 'argv', ['-c', 'pass']):
autoreload.restart_with_reloader()