From ead37dfb580136cc27dbd487a1f1ad90c9235d15 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 19 Nov 2020 12:07:15 +0100 Subject: [PATCH] Fixed #32202 -- Fixed autoreloader argument generation for Windows with Python 3.7-. --- django/utils/autoreload.py | 8 ++++++-- docs/releases/3.1.4.txt | 4 ++++ tests/utils_tests/test_autoreload.py | 10 +++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index bb5bdf107e5..4c7e605b4a3 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -232,11 +232,15 @@ def get_child_arguments(): exe_entrypoint = py_script.with_suffix('.exe') if exe_entrypoint.exists(): # Should be executed directly, ignoring sys.executable. - return [exe_entrypoint, *sys.argv[1:]] + # TODO: Remove str() when dropping support for PY37. + # args parameter accepts path-like on Windows from Python 3.8. + return [str(exe_entrypoint), *sys.argv[1:]] script_entrypoint = py_script.with_name('%s-script.py' % py_script.name) if script_entrypoint.exists(): # Should be executed as usual. - return [*args, script_entrypoint, *sys.argv[1:]] + # TODO: Remove str() when dropping support for PY37. + # args parameter accepts path-like on Windows from Python 3.8. + return [*args, str(script_entrypoint), *sys.argv[1:]] raise RuntimeError('Script %s does not exist.' % py_script) else: args += sys.argv diff --git a/docs/releases/3.1.4.txt b/docs/releases/3.1.4.txt index 02408cca688..ca75d303b96 100644 --- a/docs/releases/3.1.4.txt +++ b/docs/releases/3.1.4.txt @@ -17,3 +17,7 @@ Bugfixes * Fixed crash of key transforms for :class:`~django.db.models.JSONField` on PostgreSQL when using on a ``Subquery()`` annotation (:ticket:`32182`). + +* Fixed a regression in Django 3.1 that caused a crash of auto-reloader for + certain invocations of ``runserver`` on Windows with Python 3.7 and below + (:ticket:`32202`). diff --git a/tests/utils_tests/test_autoreload.py b/tests/utils_tests/test_autoreload.py index e21414f702f..b9f2db72763 100644 --- a/tests/utils_tests/test_autoreload.py +++ b/tests/utils_tests/test_autoreload.py @@ -178,10 +178,10 @@ class TestChildArguments(SimpleTestCase): with tempfile.TemporaryDirectory() as tmpdir: exe_path = Path(tmpdir) / 'django-admin.exe' exe_path.touch() - with mock.patch('sys.argv', [exe_path.with_suffix(''), 'runserver']): + with mock.patch('sys.argv', [str(exe_path.with_suffix('')), 'runserver']): self.assertEqual( autoreload.get_child_arguments(), - [exe_path, 'runserver'] + [str(exe_path), 'runserver'] ) @mock.patch('sys.warnoptions', []) @@ -189,10 +189,10 @@ class TestChildArguments(SimpleTestCase): with tempfile.TemporaryDirectory() as tmpdir: script_path = Path(tmpdir) / 'django-admin-script.py' script_path.touch() - with mock.patch('sys.argv', [script_path.with_name('django-admin'), 'runserver']): + with mock.patch('sys.argv', [str(script_path.with_name('django-admin')), 'runserver']): self.assertEqual( autoreload.get_child_arguments(), - [sys.executable, script_path, 'runserver'] + [sys.executable, str(script_path), 'runserver'] ) @mock.patch('sys.argv', ['does-not-exist', 'runserver']) @@ -433,7 +433,7 @@ class RestartWithReloaderTests(SimpleTestCase): with tempfile.TemporaryDirectory() as temp_dir: script = Path(temp_dir) / 'manage.py' script.touch() - argv = [script, 'runserver'] + argv = [str(script), 'runserver'] mock_call = self.patch_autoreload(argv) autoreload.restart_with_reloader() self.assertEqual(mock_call.call_count, 1)