Kaydet (Commit) 1c33280c authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Issue #21425: Fix flushing of standard streams in the interactive interpreter.

...@@ -78,7 +78,7 @@ def assert_python_failure(*args, **env_vars): ...@@ -78,7 +78,7 @@ def assert_python_failure(*args, **env_vars):
""" """
return _assert_python(False, *args, **env_vars) return _assert_python(False, *args, **env_vars)
def spawn_python(*args, **kw): def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
"""Run a Python subprocess with the given arguments. """Run a Python subprocess with the given arguments.
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
...@@ -87,7 +87,7 @@ def spawn_python(*args, **kw): ...@@ -87,7 +87,7 @@ def spawn_python(*args, **kw):
cmd_line = [sys.executable, '-E'] cmd_line = [sys.executable, '-E']
cmd_line.extend(args) cmd_line.extend(args)
return subprocess.Popen(cmd_line, stdin=subprocess.PIPE, return subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=stdout, stderr=stderr,
**kw) **kw)
def kill_python(p): def kill_python(p):
......
# tests command line execution of scripts # tests command line execution of scripts
import contextlib
import importlib import importlib
import importlib.machinery import importlib.machinery
import zipimport import zipimport
...@@ -8,6 +9,7 @@ import sys ...@@ -8,6 +9,7 @@ import sys
import os import os
import os.path import os.path
import py_compile import py_compile
import subprocess
import textwrap import textwrap
from test import support from test import support
...@@ -173,6 +175,53 @@ class CmdLineTest(unittest.TestCase): ...@@ -173,6 +175,53 @@ class CmdLineTest(unittest.TestCase):
expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8") expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8")
self.assertIn(expected, out) self.assertIn(expected, out)
@contextlib.contextmanager
def interactive_python(self, separate_stderr=False):
if separate_stderr:
p = spawn_python('-i', bufsize=1, stderr=subprocess.PIPE)
stderr = p.stderr
else:
p = spawn_python('-i', bufsize=1, stderr=subprocess.STDOUT)
stderr = p.stdout
try:
# Drain stderr until prompt
while True:
data = stderr.read(4)
if data == b">>> ":
break
stderr.readline()
yield p
finally:
kill_python(p)
stderr.close()
def check_repl_stdout_flush(self, separate_stderr=False):
with self.interactive_python(separate_stderr) as p:
p.stdin.write(b"print('foo')\n")
p.stdin.flush()
self.assertEqual(b'foo', p.stdout.readline().strip())
def check_repl_stderr_flush(self, separate_stderr=False):
with self.interactive_python(separate_stderr) as p:
p.stdin.write(b"1/0\n")
p.stdin.flush()
stderr = p.stderr if separate_stderr else p.stdout
self.assertIn(b'Traceback ', stderr.readline())
self.assertIn(b'File "<stdin>"', stderr.readline())
self.assertIn(b'ZeroDivisionError', stderr.readline())
def test_repl_stdout_flush(self):
self.check_repl_stdout_flush()
def test_repl_stdout_flush_separate_stderr(self):
self.check_repl_stdout_flush(True)
def test_repl_stderr_flush(self):
self.check_repl_stderr_flush()
def test_repl_stderr_flush_separate_stderr(self):
self.check_repl_stderr_flush(True)
def test_basic_script(self): def test_basic_script(self):
with temp_dir() as script_dir: with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, 'script') script_name = _make_test_script(script_dir, 'script')
......
...@@ -10,6 +10,9 @@ Release date: TBA ...@@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #21425: Fix flushing of standard streams in the interactive
interpreter.
- Issue #21435: In rare cases, when running finalizers on objects in cyclic - Issue #21435: In rare cases, when running finalizers on objects in cyclic
trash a bad pointer dereference could occur due to a subtle flaw in trash a bad pointer dereference could occur due to a subtle flaw in
internal iteration logic. internal iteration logic.
......
...@@ -1453,12 +1453,13 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) ...@@ -1453,12 +1453,13 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
v = run_mod(mod, filename, d, d, flags, arena); v = run_mod(mod, filename, d, d, flags, arena);
PyArena_Free(arena); PyArena_Free(arena);
flush_io();
if (v == NULL) { if (v == NULL) {
PyErr_Print(); PyErr_Print();
flush_io();
return -1; return -1;
} }
Py_DECREF(v); Py_DECREF(v);
flush_io();
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment