bpo-13601: always use line-buffering for sys.stderr#17646
bpo-13601: always use line-buffering for sys.stderr#17646pitrou merged 13 commits intopython:masterfrom
Conversation
pitrou
left a comment
There was a problem hiding this comment.
LGTM, but it would be nice if you could add a test, for example in Lib/test/test_cmd_line.py.
|
Thanks for your comments! I hope my changes address them adequately. |
Lib/test/test_cmd_line.py
Outdated
| code = f'import os, sys; {buf}.write({txt1!r}); {buf}.write({txt2!r}); os._exit(0)' | ||
| rc, out, err = assert_python_ok('-c', code) | ||
| self.assertEqual(out, out_ok) | ||
| self.assertEqual(err, err_ok) |
There was a problem hiding this comment.
I'm not sure that a functional test is required here to validate manually that buffered are flushed properly. Maybe testing the following attributes are enough?
>>> sys.stdout.write_through, sys.stdout.write_through
(False, False)
What do you think @pitrou?
My worry is that functional tests are more likely to fail and so give me more to work to maintain the CI :-)
There was a problem hiding this comment.
I added non-functional tests and removed the functional tests.
vstinner
left a comment
There was a problem hiding this comment.
Thanks for the documentation update!
Lib/test/test_cmd_line.py
Outdated
| ('sys.stderr.line_buffering', True), | ||
| ] | ||
| for attr, value in cases: | ||
| self.assertEqual(get_value(attr), value, f'{attr} is not {value}') |
There was a problem hiding this comment.
I suggest to rewrite the test to run Python a single time rather than 6 times, to make the test faster:
def test_non_interactive_output_buffering(self):
code = textwrap.dedent("""
import sys
out = sys.stdout
print(out.isatty(), out.write_through, out.line_buffering)
err = sys.stderr
print(err.isatty(), err.write_through, err.line_buffering)
""")
args = [sys.executable, '-c', code]
proc = subprocess.run(args, stdout=subprocess.PIPE,
text=True, check=True)
self.assertEqual(proc.stdout,
'False False False\n'
'True False True\n')
There was a problem hiding this comment.
Good point! I used your code, but added stderr=subprocess.PIPE to ensure that sys.stderr is not a TTY (without this both the old and the new code would pass the test).
| @@ -0,0 +1,2 @@ | |||
| ``sys.stderr`` is always line-buffered now, even if ``stderr`` is | |||
There was a problem hiding this comment.
Unless it is unbuffered.
There was a problem hiding this comment.
This is your first contribution. Please add your name in Misc/ACKS. You can also add "Patch by yourname." here.
There was a problem hiding this comment.
Thanks, I added some explanations.
vstinner
left a comment
There was a problem hiding this comment.
LGTM. @serhiy-storchaka, @pitrou: does it look good to you? I let you merge the change.
There's a fun Python 3.9 only test case failure, where "Daemon started" is output after the error message from parsing options. I ended up needing to bisect to figure out why this breaks consistently on Python 3.9. The issue is caused by python/cpython#17646 (which fixes a surprisingly old issue). I'm biased because I just spent some time figuring this out, but maybe it should be mentioned in the What's New.
There's a fun Python 3.9 only test case failure, where "Daemon started" is output after the error message from parsing options. I ended up needing to bisect to figure out why this consistently breaks on Python 3.9. The issue is caused by python/cpython#17646 (which fixes a surprisingly old BPO).
There's a fun Python 3.9 only test case failure, where "Daemon started" is output after the error message from parsing options. I ended up needing to bisect to figure out why this consistently breaks on Python 3.9. The issue is caused by python/cpython#17646 (which fixes a surprisingly old BPO). Co-authored-by: hauntsaninja <>
Fixes https://bugs.python.org/issue13601
https://bugs.python.org/issue13601