summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/utils/autoreload.py16
-rw-r--r--tests/utils_tests/test_autoreload.py53
2 files changed, 68 insertions, 1 deletions
diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py
index 845c46c8d4..1ef10a15f9 100644
--- a/django/utils/autoreload.py
+++ b/django/utils/autoreload.py
@@ -207,12 +207,26 @@ def get_child_arguments():
on reloading.
"""
import django.__main__
+ django_main_path = Path(django.__main__.__file__)
+ py_script = Path(sys.argv[0])
args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions]
- if sys.argv[0] == django.__main__.__file__:
+ if py_script == django_main_path:
# The server was started with `python -m django runserver`.
args += ['-m', 'django']
args += sys.argv[1:]
+ elif not py_script.exists():
+ # sys.argv[0] may not exist for several reasons on Windows.
+ # It may exist with a .exe extension or have a -script.py suffix.
+ exe_entrypoint = py_script.with_suffix('.exe')
+ if exe_entrypoint.exists():
+ # Should be executed directly, ignoring sys.executable.
+ return [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:]]
+ raise RuntimeError('Script %s does not exist.' % py_script)
else:
args += sys.argv
return args
diff --git a/tests/utils_tests/test_autoreload.py b/tests/utils_tests/test_autoreload.py
index 09656b8599..f4ecb38777 100644
--- a/tests/utils_tests/test_autoreload.py
+++ b/tests/utils_tests/test_autoreload.py
@@ -14,6 +14,7 @@ from pathlib import Path
from subprocess import CompletedProcess
from unittest import mock, skip, skipIf
+import django.__main__
from django.apps.registry import Apps
from django.test import SimpleTestCase
from django.test.utils import extend_sys_path
@@ -153,6 +154,55 @@ class TestIterModulesAndFiles(SimpleTestCase):
)
+class TestChildArguments(SimpleTestCase):
+ @mock.patch('sys.argv', [django.__main__.__file__, 'runserver'])
+ @mock.patch('sys.warnoptions', [])
+ def test_run_as_module(self):
+ self.assertEqual(
+ autoreload.get_child_arguments(),
+ [sys.executable, '-m', 'django', 'runserver']
+ )
+
+ @mock.patch('sys.argv', [__file__, 'runserver'])
+ @mock.patch('sys.warnoptions', ['error'])
+ def test_warnoptions(self):
+ self.assertEqual(
+ autoreload.get_child_arguments(),
+ [sys.executable, '-Werror', __file__, 'runserver']
+ )
+
+ @mock.patch('sys.warnoptions', [])
+ def test_exe_fallback(self):
+ tmpdir = tempfile.TemporaryDirectory()
+ self.addCleanup(tmpdir.cleanup)
+ exe_path = Path(tmpdir.name) / 'django-admin.exe'
+ exe_path.touch()
+ with mock.patch('sys.argv', [exe_path.with_suffix(''), 'runserver']):
+ self.assertEqual(
+ autoreload.get_child_arguments(),
+ [exe_path, 'runserver']
+ )
+
+ @mock.patch('sys.warnoptions', [])
+ def test_entrypoint_fallback(self):
+ tmpdir = tempfile.TemporaryDirectory()
+ self.addCleanup(tmpdir.cleanup)
+ script_path = Path(tmpdir.name) / 'django-admin-script.py'
+ script_path.touch()
+ with mock.patch('sys.argv', [script_path.with_name('django-admin'), 'runserver']):
+ self.assertEqual(
+ autoreload.get_child_arguments(),
+ [sys.executable, script_path, 'runserver']
+ )
+
+ @mock.patch('sys.argv', ['does-not-exist', 'runserver'])
+ @mock.patch('sys.warnoptions', [])
+ def test_raises_runtimeerror(self):
+ msg = 'Script does-not-exist does not exist.'
+ with self.assertRaisesMessage(RuntimeError, msg):
+ autoreload.get_child_arguments()
+
+
class TestCommonRoots(SimpleTestCase):
def test_common_roots(self):
paths = (
@@ -360,6 +410,9 @@ class RestartWithReloaderTests(SimpleTestCase):
return mock_call
def test_manage_py(self):
+ script = Path('manage.py')
+ script.touch()
+ self.addCleanup(script.unlink)
argv = ['./manage.py', 'runserver']
mock_call = self.patch_autoreload(argv)
autoreload.restart_with_reloader()