Windows系统中用Pycharm给项目创建Pipenv虚拟环境失败,网上找了一些都和遇到的问题有稍许差别,在仔细看过其他类似问题后,对于这个问题也有了些许思路,通过简单调整源码,轻松解决。做个简单分享,希望能帮到遇到相同问题的同学。
环境: Python2.7.5
操作:用Pycharm给项目创建Pipenv虚拟环境
异常:UnicodeDecodeError: 'utf8' codec can't decode byte 0xc8 in position 0: invalid continuation byte
输出错误代码:
File "d:\developtool\python\python27\lib\contextlib.py", line 17, in __enter__
return self.gen.next()
File "d:\developtool\python\python27\lib\site-packages\pipenv\utils.py", line 2309, in interrupt_handled_subprocess
combine_stderr=False, block=True, nospin=True, env=env,
File "d:\developtool\python\python27\lib\site-packages\pipenv\vendor\vistir\misc.py", line 597, in run
_env = {_fs_encode(k): _fs_encode(v) for k, v in _env.items()}
File "d:\developtool\python\python27\lib\site-packages\pipenv\vendor\vistir\misc.py", line 597, in <dictcomp>
_env = {_fs_encode(k): _fs_encode(v) for k, v in _env.items()}
File "d:\developtool\python\python27\lib\site-packages\pipenv\vendor\vistir\misc.py", line 731, in to_bytes
return string.decode(unicode_name).encode(encoding, errors)
File "d:\developtool\python\python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc8 in position 0: invalid continuation byte
解决方法:
修改 python27\lib\site-packages\pipenv\vendor\vistir\misc.py 717行
注释掉:
#unicode_name = get_canonical_encoding_name("utf-8")
填加:
unicode_name = get_canonical_encoding_name("gbk")
修改后源码:
# -*- coding=utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
import atexit
import io
import itertools
import json
import locale
import logging
import os
import subprocess
import sys
import threading
from collections import OrderedDict
from functools import partial
from itertools import islice, tee
from weakref import WeakKeyDictionary
import six
from six.moves.queue import Empty, Queue
from .cmdparse import Script
from .compat import (
Iterable,
Path,
StringIO,
TimeoutError,
_fs_decode_errors,
_fs_encode_errors,
fs_str,
is_bytes,
partialmethod,
to_native_string,
)
from .contextmanagers import spinner as spinner
from .environment import MYPY_RUNNING
from .termcolors import ANSI_REMOVAL_RE, colorize
if os.name != "nt":
class WindowsError(OSError):
pass
__all__ = [
"shell_escape",
"unnest",
"dedup",
"run",
"load_path",
"partialclass",
"to_text",
"to_bytes",
"locale_encoding",
"chunked",
"take",
"divide",
"getpreferredencoding",
"decode_for_output",
"get_canonical_encoding_name",
"get_wrapped_stream",
"StreamWrapper",
]
if MYPY_RUNNING:
from typing import Any, Dict, Generator, IO, List, Optional, Text, Tuple, Union
from .spin import VistirSpinner
def _get_logger(name=None, level="ERROR"):
# type: (Optional[str], str) -> logging.Logger
if not name:
name = __name__
level = getattr(logging, level.upper())
logger = logging.getLogger(name)
logger.setLevel(level)
formatter = logging.Formatter(
"%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s"
)
handler = logging.StreamHandler(stream=sys.stderr)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def shell_escape(cmd):
# type: (Union[str, List[str]]) -> str
"""Escape strings for use in :func:`~subprocess.Popen` and :func:`run`.
This is a passthrough method for instantiating a
:class:`~vistir.cmdparse.Script` object which can be used to escape
commands to output as a single string.
"""
cmd = Script.parse(cmd)
return cmd.cmdify()
def unnest(elem):
# type: (Iterable) -> Any
"""Flatten an arbitrarily nested iterable.
:param elem: An iterable to flatten
:type elem: :class:`~collections.Iterable`
>>> nested_iterable = (
1234, (3456, 4398345, (234234)), (
2396, (
23895750, 9283798, 29384, (
289375983275, 293759, 2347, (
2098, 7987, 27599
)
)
)
)
)
>>> list(vistir.misc.unnest(nested_iterable))
[1234, 3456, 4398345, 234234, 2396, 23895750, 9283798, 29384, 289375983275, 293759,
2347, 2098, 7987, 27599]
"""
if isinstance(elem, Iterable) and not isinstance(elem, six.string_types):
elem, target = tee(elem, 2)
else:
target = elem
if not target or not _is_iterable(target):
yield target
else:
for el in target:
if isinstance(el, Iterable) and not isinstance(el, six.string_types):
el, el_copy = tee(el, 2)
for sub in unnest(el_copy):
yield sub
else:
yield el
def _is_iterable(elem):
# type: (Any) -> bool
if getattr(elem, "__iter__", False) or isinstance(elem, Iterable):
return True
return False
def dedup(iterable):
# type: (Iterable) -> Iterable
"""Deduplicate an iterable object like iter(set(iterable)) but order-
preserved."""
return iter(OrderedDict.fromkeys(iterable))
def _spawn_subprocess(
script, # type: Union[str, List[str]]
env=None, # type: Optional[Dict[str, str]]
block=True, # type: bool
cwd=None, # type: Optional[Union[str, Path]]
combine_stderr=True, # type: bool
):
# type: (...) -> subprocess.Popen
from distutils.spawn import find_executable
if not env:
env = os.environ.copy()
command = find_executable(script.command)
options = {
"env": env,
"universal_newlines": True,
"stdout": subprocess.PIPE,
"stderr": subprocess.PIPE if not combine_stderr else subprocess.STDOUT,
"shell": False,
}
if sys.version_info[:2] > (3, 5):
options.update({"universal_newlines": True, "encoding": "utf-8"})
elif os.name != "nt":
options["universal_newlines"] = True
if not block:
options["stdin"] = subprocess.PIPE
if cwd:
options["cwd"] = cwd
# Command not found, maybe this is a shell built-in?
cmd = [command] + script.args
if not command: # Try to use CreateProcess directly if possible.
cmd = script.cmdify()
options["shell"] = True
# Try to use CreateProcess directly if possible. Specifically catch
# Windows error 193 "Command is not a valid Win32 application" to handle
# a "command" that is non-executable. See pypa/pipenv#2727.
try:
return subprocess.Popen(cmd, **options)
except WindowsError as e: # pragma: no cover
if getattr(e, "winerror", 9999) != 193:
raise
options["shell"] = True
# Try shell mode to use Windows's file association for file launch.
return subprocess.Popen(script.cmdify(), **options)
class SubprocessStreamWrapper(object):
def __init__(
self,
display_stderr_maxlen=200, # type: int
display_line_for_loops=20, # type: int
subprocess=None, # type: subprocess.Popen
spinner=None, # type: Optional[VistirSpinner]
verbose=False, # type: bool
stdout_allowed=False, # type: bool
):
# type: (...) -> None
stdout_encoding = None
stderr_encoding = None
preferred_encoding = getpreferredencoding()
if subprocess is not None:
stdout_encoding = self.get_subprocess_encoding(subprocess, "stdout")
stderr_encoding = self.get_subprocess_encoding(subprocess, "stderr")
self.stdout_encoding = stdout_encoding or preferred_encoding
self.stderr_encoding = stderr_encoding or preferred_encoding
self.stdout_lines = []
self.text_stdout_lines = []
self.stderr_lines = []
self.text_stderr_lines = []
self.display_line = ""
self.display_line_loops_displayed = 0
self.display_line_shown_for_loops = display_line_for_loops
self.display_line_max_len = display_stderr_maxlen
self.spinner = spinner
self.st