Skip to content

Commit 68aae88

Browse files
JaeHyuckSasarahboyce
authored andcommitted
Fixed #36434 -- Preserved unbuffered stdio (-u) in autoreloader child.
Signed-off-by: SaJH <wogur981208@gmail.com>
1 parent 5cbd960 commit 68aae88

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

django/utils/autoreload.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,19 @@ def trigger_reload(filename):
268268

269269
def restart_with_reloader():
270270
new_environ = {**os.environ, DJANGO_AUTORELOAD_ENV: "true"}
271+
orig = getattr(sys, "orig_argv", ())
272+
if any(
273+
(arg == "-u")
274+
or (
275+
arg.startswith("-")
276+
and not arg.startswith(("--", "-X", "-W"))
277+
and len(arg) > 2
278+
and arg[1:].isalpha()
279+
and "u" in arg
280+
)
281+
for arg in orig[1:]
282+
):
283+
new_environ.setdefault("PYTHONUNBUFFERED", "1")
271284
args = get_child_arguments()
272285
while True:
273286
p = subprocess.run(args, env=new_environ, close_fds=False)

tests/utils_tests/test_autoreload.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,53 @@ def test_python_m_django(self):
535535
[self.executable, "-Wall", "-m", "django"] + argv[1:],
536536
)
537537

538+
def test_propagates_unbuffered_from_parent(self):
539+
for args in ("-u", "-Iuv"):
540+
with self.subTest(args=args):
541+
with mock.patch.dict(os.environ, {}, clear=True):
542+
with tempfile.TemporaryDirectory() as d:
543+
script = Path(d) / "manage.py"
544+
script.touch()
545+
mock_call = self.patch_autoreload([str(script), "runserver"])
546+
with (
547+
mock.patch("__main__.__spec__", None),
548+
mock.patch.object(
549+
autoreload.sys,
550+
"orig_argv",
551+
[self.executable, args, str(script), "runserver"],
552+
),
553+
):
554+
autoreload.restart_with_reloader()
555+
env = mock_call.call_args.kwargs["env"]
556+
self.assertEqual(env.get("PYTHONUNBUFFERED"), "1")
557+
558+
def test_does_not_propagate_unbuffered_from_parent(self):
559+
for args in (
560+
"-Xdev",
561+
"-Xfaulthandler",
562+
"--user",
563+
"-Wall",
564+
"-Wdefault",
565+
"-Wignore::UserWarning",
566+
):
567+
with self.subTest(args=args):
568+
with mock.patch.dict(os.environ, {}, clear=True):
569+
with tempfile.TemporaryDirectory() as d:
570+
script = Path(d) / "manage.py"
571+
script.touch()
572+
mock_call = self.patch_autoreload([str(script), "runserver"])
573+
with (
574+
mock.patch("__main__.__spec__", None),
575+
mock.patch.object(
576+
autoreload.sys,
577+
"orig_argv",
578+
[self.executable, args, str(script), "runserver"],
579+
),
580+
):
581+
autoreload.restart_with_reloader()
582+
env = mock_call.call_args.kwargs["env"]
583+
self.assertIsNone(env.get("PYTHONUNBUFFERED"))
584+
538585

539586
class ReloaderTests(SimpleTestCase):
540587
RELOADER_CLS = None

0 commit comments

Comments
 (0)