summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2014-05-11 11:43:31 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2014-05-11 11:43:31 (GMT)
commit1c33280c9534180733c595de160919dd86e74659 (patch)
tree94634b5bead1da641297df511d5123911b43b303
parentc89a451ae13339d803cad639f2c61af2c67f5fc2 (diff)
parent9845c7ebc5cf5af495123701664f275562f45243 (diff)
downloadcpython-1c33280c9534180733c595de160919dd86e74659.zip
cpython-1c33280c9534180733c595de160919dd86e74659.tar.gz
cpython-1c33280c9534180733c595de160919dd86e74659.tar.bz2
Issue #21425: Fix flushing of standard streams in the interactive interpreter.
-rw-r--r--Lib/test/script_helper.py4
-rw-r--r--Lib/test/test_cmd_line_script.py49
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/pythonrun.c3
4 files changed, 56 insertions, 3 deletions
diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py
index af0545b..993b199 100644
--- a/Lib/test/script_helper.py
+++ b/Lib/test/script_helper.py
@@ -78,7 +78,7 @@ def assert_python_failure(*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.
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
@@ -87,7 +87,7 @@ def spawn_python(*args, **kw):
cmd_line = [sys.executable, '-E']
cmd_line.extend(args)
return subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ stdout=stdout, stderr=stderr,
**kw)
def kill_python(p):
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
index 1e6746d..88a9e2b 100644
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -1,5 +1,6 @@
# tests command line execution of scripts
+import contextlib
import importlib
import importlib.machinery
import zipimport
@@ -8,6 +9,7 @@ import sys
import os
import os.path
import py_compile
+import subprocess
import textwrap
from test import support
@@ -173,6 +175,53 @@ class CmdLineTest(unittest.TestCase):
expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8")
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):
with temp_dir() as script_dir:
script_name = _make_test_script(script_dir, 'script')
diff --git a/Misc/NEWS b/Misc/NEWS
index 27b6eee..b80c066 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ Release date: TBA
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
trash a bad pointer dereference could occur due to a subtle flaw in
internal iteration logic.
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 4fd5149..b2d5464 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -1453,12 +1453,13 @@ PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
d = PyModule_GetDict(m);
v = run_mod(mod, filename, d, d, flags, arena);
PyArena_Free(arena);
- flush_io();
if (v == NULL) {
PyErr_Print();
+ flush_io();
return -1;
}
Py_DECREF(v);
+ flush_io();
return 0;
}