diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py --- a/mercurial/utils/procutil.py +++ b/mercurial/utils/procutil.py @@ -99,6 +99,18 @@ if isatty(stdout): 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 --git a/tests/test-stdio.py b/tests/test-stdio.py --- a/tests/test-stdio.py +++ b/tests/test-stdio.py @@ -100,6 +100,18 @@ class TestStdio(unittest.TestCase): 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