diff --git a/src/pip/_vendor/colorama/ansitowin32.py b/src/pip/_vendor/colorama/ansitowin32.py index 1d6e6059c75..a090008e2a9 100644 --- a/src/pip/_vendor/colorama/ansitowin32.py +++ b/src/pip/_vendor/colorama/ansitowin32.py @@ -1,4 +1,5 @@ # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import errno import re import sys import os @@ -136,12 +137,25 @@ def get_win32_calls(self): } return dict() + def _flush(self): + """Ignore `BrokenPipeErrors` eg. when piped in `head` UNIX cmd.""" + try: + self.wrapped.flush() + except (IOError, OSError) as ex: # Python-2 has no `BrokenPipeError` + # Windows also fails with: + # File "pip\_vendor\colorama\ansitowin32.py", line 143, in _flush + # self.wrapped.flush() + # OSError: [Errno 22] Invalid argument + # + if ex.errno not in (errno.EPIPE, errno.EINVAL): + raise + def write(self, text): if self.strip or self.convert: self.write_and_convert(text) else: self.wrapped.write(text) - self.wrapped.flush() + self._flush() if self.autoreset: self.reset_all() @@ -172,7 +186,7 @@ def write_and_convert(self, text): def write_plain_text(self, text, start, end): if start < end: self.wrapped.write(text[start:end]) - self.wrapped.flush() + self._flush() def convert_ansi(self, paramstring, command): diff --git a/tests/functional/test_logging.py b/tests/functional/test_logging.py index a3a3a3a71c5..debe8cc739d 100644 --- a/tests/functional/test_logging.py +++ b/tests/functional/test_logging.py @@ -6,6 +6,7 @@ import subprocess import pytest +from pip._vendor.six import PY2 @pytest.mark.usefixtures('script') @@ -121,15 +122,16 @@ def test_broken_pipe_logger(): # `download` cmd has a lot of log-statements. cmd = 'pip download -v pip' - # When the stream where logging is writting is broken, - # at least these 2 lines are emitted in stderr: + stderr = _run_and_brake_stdout(cmd, shell=True, check=True) + # When breaks the stream that the logging is writing into, + # in PY3 these 2 lines are emitted in stderr: # Exception ignored in: <_io.TextIOWrapper name='' mode='w' ... # BrokenPipeError: [Errno 32] Broken pipe\n" - exp_stder_nlines = 2 - exp_stderr_msg = b'Exception ignored in' - - stderr = _run_and_brake_stdout(cmd, shell=True, check=True) - # Before #5721, it command does not stop, but it continued - # printing ~4 lines per each broken-pipe error! - assert stderr.count(b'\n') == exp_stder_nlines, stderr - assert exp_stderr_msg in stderr, stderr + # + # Before #5721, pip did not stop the 1st time, but it continued + # printing them lines on each `stream.flush()`! + if PY2: + assert not stderr, stderr + else: + assert stderr.count(b'\n') == 2 + assert b'Exception ignored in' in stderr, stderr