]> granicus.if.org Git - python/commitdiff
Issue #21425: Fix flushing of standard streams in the interactive interpreter.
authorAntoine Pitrou <solipsis@pitrou.net>
Sun, 11 May 2014 11:42:17 +0000 (13:42 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Sun, 11 May 2014 11:42:17 +0000 (13:42 +0200)
Lib/test/script_helper.py
Lib/test/test_cmd_line_script.py
Misc/NEWS
Python/pythonrun.c

index af0545bac239ef56a075512755a8172b9ab32e16..993b199d11c9c6e0c9e9b232819ee2bfec239d2b 100644 (file)
@@ -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):
index 1e6746d43416c3823dcb6b3b3dd0237f1ebe8631..88a9e2bbb523baa687d0ea26cf5d3fda0bb6a90b 100644 (file)
@@ -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')
index d0d9012ffbaf87d13217720ebba3126ccf5a2de4..3c2ead0e4eeb60696d666f87b5dbcdfc34e1a781 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -3,13 +3,16 @@ Python News
 +++++++++++
 
 What's New in Python 3.4.1?
-==========================
+===========================
 
 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.
index b3991ead91afcda4d5a0afed954fc5f66c8fd1e7..0327830247cf27f1cf0f68f6e23c5c58f835e654 100644 (file)
@@ -1444,12 +1444,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;
 }