Skip to content

Commit 5b90771

Browse files
jendrikseipppitrou
authored andcommitted
bpo-13601: always use line-buffering for sys.stderr (GH-17646)
1 parent 46abfc1 commit 5b90771

File tree

5 files changed

+33
-4
lines changed

5 files changed

+33
-4
lines changed

Doc/library/sys.rst

+9-3
Original file line numberDiff line numberDiff line change
@@ -1446,9 +1446,15 @@ always available.
14461446
for the Windows console, this only applies when
14471447
:envvar:`PYTHONLEGACYWINDOWSSTDIO` is also set.
14481448

1449-
* When interactive, ``stdout`` and ``stderr`` streams are line-buffered.
1450-
Otherwise, they are block-buffered like regular text files. You can
1451-
override this value with the :option:`-u` command-line option.
1449+
* When interactive, the ``stdout`` stream is line-buffered. Otherwise,
1450+
it is block-buffered like regular text files. The ``stderr`` stream
1451+
is line-buffered in both cases. You can make both streams unbuffered
1452+
by passing the :option:`-u` command-line option or setting the
1453+
:envvar:`PYTHONUNBUFFERED` environment variable.
1454+
1455+
.. versionchanged:: 3.9
1456+
Non-interactive ``stderr`` is now line-buffered instead of fully
1457+
buffered.
14521458

14531459
.. note::
14541460

Lib/test/test_cmd_line.py

+16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import subprocess
77
import sys
88
import tempfile
9+
import textwrap
910
import unittest
1011
from test import support
1112
from test.support.script_helper import (
@@ -219,6 +220,21 @@ def check_output(text):
219220
)
220221
check_output(text)
221222

223+
def test_non_interactive_output_buffering(self):
224+
code = textwrap.dedent("""
225+
import sys
226+
out = sys.stdout
227+
print(out.isatty(), out.write_through, out.line_buffering)
228+
err = sys.stderr
229+
print(err.isatty(), err.write_through, err.line_buffering)
230+
""")
231+
args = [sys.executable, '-c', code]
232+
proc = subprocess.run(args, stdout=subprocess.PIPE,
233+
stderr=subprocess.PIPE, text=True, check=True)
234+
self.assertEqual(proc.stdout,
235+
'False False False\n'
236+
'False False True\n')
237+
222238
def test_unbuffered_output(self):
223239
# Test expected operation of the '-u' switch
224240
for stream in ('stdout', 'stderr'):

Misc/ACKS

+1
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,7 @@ Steven Scott
15101510
Nick Seidenman
15111511
Michael Seifert
15121512
Žiga Seilnacht
1513+
Jendrik Seipp
15131514
Michael Selik
15141515
Yury Selivanov
15151516
Fred Sells
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
By default, ``sys.stderr`` is line-buffered now, even if ``stderr`` is
2+
redirected to a file. You can still make ``sys.stderr`` unbuffered by
3+
passing the :option:`-u` command-line option or setting the
4+
:envvar:`PYTHONUNBUFFERED` environment variable.
5+
6+
(Contributed by Jendrik Seipp in bpo-13601.)

Python/pylifecycle.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,7 @@ create_stdio(const PyConfig *config, PyObject* io,
18171817
write_through = Py_True;
18181818
else
18191819
write_through = Py_False;
1820-
if (isatty && buffered_stdio)
1820+
if (buffered_stdio && (isatty || fd == fileno(stderr)))
18211821
line_buffering = Py_True;
18221822
else
18231823
line_buffering = Py_False;

0 commit comments

Comments
 (0)