From dcd5369117f44b30d6afee0d10322b79db540612 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 12 Mar 2019 01:38:47 -0400 Subject: [PATCH] Fix vistir's encoding of terminal output for python 2 Signed-off-by: Dan Ryan --- pipenv/__init__.py | 13 ++++++++ pipenv/core.py | 5 ++-- pipenv/vendor/vistir/misc.py | 1 + pipenv/vendor/vistir/spin.py | 57 ++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/pipenv/__init__.py b/pipenv/__init__.py index 7a12158a..769ede20 100644 --- a/pipenv/__init__.py +++ b/pipenv/__init__.py @@ -26,6 +26,8 @@ warnings.filterwarnings("ignore", category=DependencyWarning) warnings.filterwarnings("ignore", category=ResourceWarning) warnings.filterwarnings("ignore", category=UserWarning) + + if sys.version_info >= (3, 1) and sys.version_info <= (3, 6): if sys.stdout.isatty() and sys.stderr.isatty(): import io @@ -46,6 +48,17 @@ try: except Exception: pass +if sys.version_info >= (3, 0): + stdout = sys.stdout.buffer + stderr = sys.stderr.buffer +else: + stdout = sys.stdout + stderr = sys.stderr + +from .vendor.vistir.misc import get_wrapped_stream +sys.stderr = get_wrapped_stream(stderr) +sys.stdout = get_wrapped_stream(stdout) + from .cli import cli from . import resolver diff --git a/pipenv/core.py b/pipenv/core.py index 298aab23..05dba22f 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -923,12 +923,13 @@ def do_create_virtualenv(python=None, site_packages=False, pypi_mirror=None): ) click.echo(crayons.blue("{0}".format(c.out)), err=True) if c.returncode != 0: - sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format("Failed creating virtual environment")) + sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format(u"Failed creating virtual environment")) raise exceptions.VirtualenvCreationException( extra=[crayons.blue("{0}".format(c.err)),] ) else: - sp.green.ok(environments.PIPENV_SPINNER_OK_TEXT.format("Successfully created virtual environment!")) + + sp.green.ok(environments.PIPENV_SPINNER_OK_TEXT.format(u"Successfully created virtual environment!")) # Associate project directory with the environment. # This mimics Pew's "setproject". diff --git a/pipenv/vendor/vistir/misc.py b/pipenv/vendor/vistir/misc.py index 42067b2d..fe88dc1f 100644 --- a/pipenv/vendor/vistir/misc.py +++ b/pipenv/vendor/vistir/misc.py @@ -590,6 +590,7 @@ def decode_for_output(output, target_stream=None, translation_map=None): try: output = _encode(output, encoding=encoding, translation_map=translation_map) except (UnicodeDecodeError, UnicodeEncodeError): + output = to_native_string(output) output = _encode( output, encoding=encoding, errors="replace", translation_map=translation_map ) diff --git a/pipenv/vendor/vistir/spin.py b/pipenv/vendor/vistir/spin.py index 40dfff96..d7b6dfa6 100644 --- a/pipenv/vendor/vistir/spin.py +++ b/pipenv/vendor/vistir/spin.py @@ -14,7 +14,7 @@ import six from .compat import to_native_string from .cursor import hide_cursor, show_cursor -from .misc import decode_for_output +from .misc import decode_for_output, to_text from .termcolors import COLOR_MAP, COLORS, DISABLE_COLORS, colored try: @@ -131,9 +131,9 @@ class DummySpinner(object): target = self.stdout if text is None or isinstance(text, six.string_types) and text == "None": pass - target.write(decode_output("\r", target_stream=target)) + target.write(decode_output(u"\r", target_stream=target)) self._hide_cursor(target=target) - target.write(decode_output("{0}\n".format(text), target_stream=target)) + target.write(decode_output(u"{0}\n".format(text), target_stream=target)) target.write(CLEAR_LINE) self._show_cursor(target=target) @@ -146,9 +146,8 @@ class DummySpinner(object): stdout = self.stdout else: stdout = sys.stdout - text = decode_output(text, target_stream=stdout) - stdout.write(decode_output("\r", target_stream=stdout)) - line = decode_output("{0}\n".format(text), target_stream=stdout) + stdout.write(decode_output(u"\r", target_stream=stdout)) + line = decode_output(u"{0}\n".format(text), target_stream=stdout) stdout.write(line) stdout.write(CLEAR_LINE) @@ -162,9 +161,8 @@ class DummySpinner(object): print(text) return stderr = sys.stderr - text = decode_output(text, target_stream=stderr) - stderr.write(decode_output("\r", target_stream=stderr)) - line = decode_output("{0}\n".format(text), target_stream=stderr) + stderr.write(decode_output(u"\r", target_stream=stderr)) + line = decode_output(u"{0}\n".format(text), target_stream=stderr) stderr.write(line) stderr.write(CLEAR_LINE) @@ -224,32 +222,32 @@ class VistirSpinner(SpinBase): if DISABLE_COLORS: colorama.deinit() - def ok(self, text="OK", err=False): + def ok(self, text=u"OK", err=False): """Set Ok (success) finalizer to a spinner.""" # Do not display spin text for ok state self._text = None - _text = text if text else "OK" + _text = to_text(text) if text else u"OK" err = err or not self.write_to_stdout self._freeze(_text, err=err) - def fail(self, text="FAIL", err=False): + def fail(self, text=u"FAIL", err=False): """Set fail finalizer to a spinner.""" # Do not display spin text for fail state self._text = None - _text = text if text else "FAIL" + _text = text if text else u"FAIL" err = err or not self.write_to_stdout self._freeze(_text, err=err) def hide_and_write(self, text, target=None): if not target: target = self.stdout - if text is None or isinstance(text, six.string_types) and text == "None": + if text is None or isinstance(text, six.string_types) and text == u"None": pass - target.write(decode_output("\r")) + target.write(decode_output(u"\r")) self._hide_cursor(target=target) - target.write(decode_output("{0}\n".format(text))) + target.write(decode_output(u"{0}\n".format(text))) target.write(CLEAR_LINE) self._show_cursor(target=target) @@ -259,24 +257,24 @@ class VistirSpinner(SpinBase): stdout = self.stdout if self.stdout.closed: stdout = sys.stdout - stdout.write(decode_output("\r", target_stream=stdout)) + stdout.write(decode_output(u"\r", target_stream=stdout)) stdout.write(decode_output(CLEAR_LINE, target_stream=stdout)) if text is None: text = "" - text = decode_output("{0}\n".format(text), target_stream=stdout) + text = decode_output(u"{0}\n".format(text), target_stream=stdout) stdout.write(text) - self.out_buff.write(decode_output(text, target_stream=self.out_buff)) + self.out_buff.write(text) def write_err(self, text): """Write error text in the terminal without breaking the spinner.""" stderr = self.stderr if self.stderr.closed: stderr = sys.stderr - stderr.write(decode_output("\r", target_stream=stderr)) + stderr.write(decode_output(u"\r", target_stream=stderr)) stderr.write(decode_output(CLEAR_LINE, target_stream=stderr)) if text is None: text = "" - text = decode_output("{0}\n".format(text), target_stream=stderr) + text = decode_output(u"{0}\n".format(text), target_stream=stderr) self.stderr.write(text) self.out_buff.write(decode_output(text, target_stream=self.out_buff)) @@ -322,8 +320,9 @@ class VistirSpinner(SpinBase): target = self.stderr if err else self.stdout if target.closed: target = sys.stderr if err else sys.stdout - text = decode_output(final_text, target_stream=target) - self._last_frame = self._compose_out(text, mode="last") + text = to_text(final_text) + last_frame = self._compose_out(text, mode="last") + self._last_frame = decode_output(last_frame, target_stream=target) # Should be stopped here, otherwise prints after # self._freeze call will mess up the spinner @@ -339,19 +338,20 @@ class VistirSpinner(SpinBase): def _compose_out(self, frame, mode=None): # Ensure Unicode input - frame = decode_output(frame) + frame = to_text(frame) if self._text is None: - self._text = "" - text = decode_output(self._text) + self._text = u"" + text = to_text(self._text) if self._color_func is not None: frame = self._color_func(frame) if self._side == "right": frame, text = text, frame # Mode + frame = to_text(frame) if not mode: - out = decode_output("\r{0} {1}".format(frame, text)) + out = u"\r{0} {1}".format(frame, text) else: - out = decode_output("{0} {1}\n".format(frame, text)) + out = u"{0} {1}\n".format(frame, text) return out def _spin(self): @@ -367,6 +367,7 @@ class VistirSpinner(SpinBase): # Compose output spin_phase = next(self._cycle) out = self._compose_out(spin_phase) + out = decode_output(out, target) # Write target.write(out)