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.
--- 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
--- 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