# HG changeset patch # User Manuel Jacob # Date 1593947362 -7200 # Node ID 8403cc54bc837b728c366ddaae226a4aa8ecf241 # Parent 359884685eabe609f84235ec0a5bdc207594c470 procutil: make mercurial.utils.procutil.stderr unbuffered For most Mercurial code, it doesn’t make a difference, as the ui object flushes stderr explicitly (after the change, we could get rid of the explicit flush). One example where it makes a observable difference is mercurial.util.timed(). Without the patch, the time is not immediately shown on Python 3. With the patch, it’s shown immediately on all Python versions and platforms. diff -r 359884685eab -r 8403cc54bc83 mercurial/utils/procutil.py --- a/mercurial/utils/procutil.py Sun Jul 05 13:05:06 2020 +0200 +++ b/mercurial/utils/procutil.py Sun Jul 05 13:09:22 2020 +0200 @@ -99,6 +99,18 @@ else: stdout = os.fdopen(stdout.fileno(), 'wb', 1) +# stderr should be unbuffered +if pycompat.ispy3: + # On Python 3, buffered streams may expose an underlying raw stream. This is + # definitively the case for the streams initialized by the interpreter. If + # the attribute isn't present, the stream is already unbuffered or doesn't + # expose an underlying raw stream, in which case we use the stream as-is. + stderr = getattr(stderr, 'raw', stderr) +elif pycompat.iswindows: + # On Windows, stderr is buffered at least when connected to a pipe. + stderr = os.fdopen(stderr.fileno(), 'wb', 0) +# On other platforms, stderr is always unbuffered. + findexe = platform.findexe _gethgcmd = platform.gethgcmd diff -r 359884685eab -r 8403cc54bc83 tests/test-stdio.py --- a/tests/test-stdio.py Sun Jul 05 13:05:06 2020 +0200 +++ b/tests/test-stdio.py Sun Jul 05 13:09:22 2020 +0200 @@ -100,6 +100,18 @@ test_stdout_ptys_unbuffered ) + def test_stderr_pipes(self): + self._test('stderr', _pipes, UNBUFFERED) + + def test_stderr_ptys(self): + self._test('stderr', _ptys, UNBUFFERED) + + def test_stderr_pipes_unbuffered(self): + self._test('stderr', _pipes, UNBUFFERED, python_args=['-u']) + + def test_stderr_ptys_unbuffered(self): + self._test('stderr', _ptys, UNBUFFERED, python_args=['-u']) + if __name__ == '__main__': import silenttestrunner