본문 바로가기

프로그래밍/Python

pip install 중에 , setup.py 에서 UnicodeDecodeError 'cp949' codec can't decode .... illegal multibyte sequence 가 발생하며 설치가 실패한다.

반응형

pip install 중에 ,setup.py 에서 UnicodeDecodeError 'cp949' codec can't decode .... illegal multibyte sequence 가 발생하며 설치가 실패한다.

파이썬에 처음 입문하고, 이런 저런 패키지(라이브러리)들을 설치해야 한다. 그런데, 간단히 성공해야 마땅한, 패키지 설치 중에 다음과 같이 UnicodeDecodeError 'cp949' codec can't decode 어쩌고 하는 에러가 발생하여, 패키지 설치가 실패하는 경우가 종종 발생한다. 여러가지 원인들 중에서, 매우 사소한 원인으로 패키지 설치가 실패하는 경우에 대해서 원인을 찾아보고, 패키지를 설치하는 방법에 대해서 알아보자.

테스트로 삼은 조건은 다음과 같다.

한국어 윈도우 환경에 python 3.6 버전을 깔았고, 여기에 inception 이라는 패키지를 깔려고 pip install inception 명령을 실행했다. 패키지 설치는 다음과 같은 에러메시지와 함께 실패한다.

(vtest) D:\PythonEnv\ws_test\inception>python --version
Python 3.6.8

(vtest) D:\PythonEnv\ws_test\inception>pip install inception
Collecting inception
  Using cached https://files.pythonhosted.org/packages/4f/4c/b5222986906ff7ba39b52b277a342eb75bf3a87c6db486236dcf7e3fdaec/inception-0.0.3.tar.gz
    ERROR: Command errored out with exit status 1:
     command: 'd:\pythonenv\vtest\scripts\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\daewon\\AppData\\Local\\Temp\\pip-install-rcgpb_on\\inception\\setup.py'"'"'; __file__='"'"'C:\\Users\\daewon\\AppData\\Local\\Temp\\pip-install-rcgpb_on\\inception\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base 'C:\Users\daewon\AppData\Local\Temp\pip-install-rcgpb_on\inception\pip-egg-info'
         cwd: C:\Users\daewon\AppData\Local\Temp\pip-install-rcgpb_on\inception\
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "C:\Users\daewon\AppData\Local\Temp\pip-install-rcgpb_on\inception\setup.py", line 39, in <module>
        long_description=read_description(),
      File "C:\Users\daewon\AppData\Local\Temp\pip-install-rcgpb_on\inception\setup.py", line 12, in read_description
        return fd.read()
    UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 3259: illegal multibyte sequence
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 19.3; however, version 19.3.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

pip 명령으로 패키지 설치를 지시하면, pip 는 pypi 패키지 저장소로부터 inception 패키지의 최신버전 설치파일을 다운로드 받아서, 그걸 임시폴더에 풀고 설치하려 한다. pip 설치패키지는 여러가지 종류가 있는데, 이 버전의 inception 패키지의 경우에는 .tar.gz 확장자의 설치파일이 다운로드 되었다. .tar.gz 압축 파일은 파이썬(그리고 종종 c/cpp) 소스 파일들이 압축되어 들어있는 설치파일이다.

설치 진행은, .tar.gz 파일의 압축을 다시 임시폴더에 풀고, 설치 소스파일에 있는 setup.py 를 실행하며 이루어진다. 보통 setup.py 가 있는 설치파일은 python setup.py install 과 같은 명령으로 설치가 된다. 또는, 해당 폴더로 이동하여 pip install . 을 수행하면, setup.py install 이 실행되면서 설치가 되는 것이다.

지금 에러메시지에서 보면, inception 이라는 설치소스가 풀린 폴더 아래에 있는 setup.py 스크립트 파일안의 12번째 줄의 return fd.read() 부분에서 UnicodeDecodeError 가 발생한 것을 알 수 있다.

이 문제를 어떻게 해결할까?

pip install 명령 과정에서 자동으로 다운로드 받고, setup.py install 을 실행한 것을 수동으로 진행하면서, 디버깅을 할 것이다. 그리 어렵지 않다.

우선 pip download inception 이라고 하면, 동일한 에러가 발생하지만, 명령창에서 dir 명령을 해 보면 inception-0.0.3.tar.gz 이 다운로드 받아져 있을 것이다. 이 파일의 압축을 적당한 압축툴로 푼다. 파일을 잘 풀면 루트폴더에 다음과 같이 파일들이 있을 것이다.

(vtest) D:\PythonEnv\ws_test\inception>dir
 Volume in drive D is dee
 Volume Serial Number is 60E5-48F0

 Directory of D:\PythonEnv\ws_test\inception

2019-11-18  오후 09:12    <DIR>          .
2019-11-18  오후 09:12    <DIR>          ..
2019-11-18  오후 09:12    <DIR>          inception
2019-11-18  오후 09:12    <DIR>          inception.egg-info
2014-12-28  오전 02:53             9,472 PKG-INFO
2014-12-27  오후 04:52             6,663 README.rst
2014-12-28  오전 02:53               137 setup.cfg
2014-12-27  오후 05:37             1,904 setup.py
               4 File(s)         18,176 bytes
               4 Dir(s)  162,267,377,664 bytes free

적당한 폴더에 풀어서, dir 해서 위와 같이 나왔다면, 이 폴더에서 pip install . 이라고 명령을 쳐서 실행해본다. (이 때 명령을 실행하는 디렉토리에 setup.py 가 존재해야 한다.) 동일한 UnicodeDecodeError 가 뜰 것이다.

(vtest) D:\PythonEnv\ws_test\inception>pip install .
Processing d:\pythonenv\ws_test\inception
    ERROR: Command errored out with exit status 1:
     command: 'd:\pythonenv\vtest\scripts\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\daewon\\AppData\\Local\\Temp\\pip-req-build-g5k8484g\\setup.py'"'"'; __file__='"'"'C:\\Users\\daewon\\AppData\\Local\\Temp\\pip-req-build-g5k8484g\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base 'C:\Users\daewon\AppData\Local\Temp\pip-req-build-g5k8484g\pip-egg-info'
         cwd: C:\Users\daewon\AppData\Local\Temp\pip-req-build-g5k8484g\
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "C:\Users\daewon\AppData\Local\Temp\pip-req-build-g5k8484g\setup.py", line 39, in <module>
        long_description=read_description(),
      File "C:\Users\daewon\AppData\Local\Temp\pip-req-build-g5k8484g\setup.py", line 12, in read_description
        return fd.read()
    UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 3259: illegal multibyte sequence
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 19.3; however, version 19.3.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

그럼, 여기서 적당한 편집기로 setup.py 를 열어보자.

# -*- coding: utf-8 -*-

import sys

from setuptools.command.test import test as TestCommand
from setuptools import setup, find_packages
from inception.version import APP


def read_description():
    with open('README.rst') as fd:
        return fd.read()     ## <<<<<<<<<<<<<<<<<<<--- line 12

이렇게 되어 있다. (물론, 뒤쪽에 코드가 더 있다.) read_description 함수 안의 return fd.read() 부분에서 에러가 발생한 것이다.

README.rst 라는 파일을 열어서 읽어서, 그 텍스트를 되돌려주는 함수이고, 파일을 읽는 부분에서 UnicodeDecodeError 가 발생한 것이다.

에러가 발생하는 이유는 무엇일까? README.rst 는 말그대로 패키지에 대한 간단한 설명파일일 뿐이다. 상식적으로 실제 패키지의 실행에는 아무런 영향을 주지 않는다.

원인은 이렇다. REAME.rst 파일을 vscode 로 열어보면, 자동으로 utf-8 인코딩으로 인코딩을 자동 디텍트하면서 잘 보여준다. 그런데, 윈도우에서 setup.py 를 실행하게 되면, open('README.rst') 부분에서 인코딩을 지정하지 않았기 때문에, 한글 windows 의 기본 인코딩인 cp949 로 읽게 된다. open 부분은 단순히 파일핸들을 가져오는 부분이고, fd.read() 부분에서 실제적으로 파일의 바이너리 내용을 cp949로 해석하려는 동작이 일어나게 된다. 여기에서 README.rst 파일 안에 cp949 인코딩으로 해석할 수 없는 바이트열이 포함되어 있는 것이고, 그것이 3259번째 바이트인 e2 로 시작하는 바이트열인 것이다.

이를 README.rst 파일을 헥사모드로 열어 확인해 보면, 아래와 같이 트리구조를 표현하기 위한 그림문자인 것을 알 수 있다. 좀 특이한 3바이트짜리 문자인 것이다.


Structures examples:

.. code::

    .
    ├── files
    │   └── level_1
    │       └── level_2
    │           ├── example1.txt
    │           ├── example2.txt.jinja
    │           └── {{ name }}.txt
    └── settings.py

원인을 파악했으니 문제를 해결하는 방법도 알 수 있다. 여러가지 방법을 써 볼 수 있다.

  1. 무식하게, README.rst 파일을 싹 다 지우고 저장한 후에, pip install . 을 실행해 본다.
  2. README.rst 를 잘 읽어서 설치하고 싶다면, setup.py 의 11번째 라인의 open('README.rst') 부분에 encoding 옵션을 지정하여준다. 즉, open('README.rst', encoding='utf-8') 로 바꾸고, 저장한 후에, pip install . 을 실행한다.

2번째 방법으로 해 본다.

(vtest) D:\PythonEnv\ws_test\inception>pip install .
Processing d:\pythonenv\ws_test\inception
Requirement already satisfied: inquirer>=2.1.2 in d:\pythonenv\vtest\lib\site-packages (from inception==0.0.3) (2.6.3)
Requirement already satisfied: jinja2>=2.7.3 in d:\pythonenv\vtest\lib\site-packages (from inception==0.0.3) (2.10.3)
Requirement already satisfied: blessings==1.7 in d:\pythonenv\vtest\lib\site-packages (from inquirer>=2.1.2->inception==0.0.3) (1.7)
Requirement already satisfied: readchar==2.0.1 in d:\pythonenv\vtest\lib\site-packages (from inquirer>=2.1.2->inception==0.0.3) (2.0.1)
Requirement already satisfied: python-editor==1.0.4 in d:\pythonenv\vtest\lib\site-packages (from inquirer>=2.1.2->inception==0.0.3) (1.0.4)
Requirement already satisfied: MarkupSafe>=0.23 in d:\pythonenv\vtest\lib\site-packages (from jinja2>=2.7.3->inception==0.0.3) (1.1.1)
Requirement already satisfied: six in d:\pythonenv\vtest\lib\site-packages (from blessings==1.7->inquirer>=2.1.2->inception==0.0.3) (1.12.0)
Building wheels for collected packages: inception
  Building wheel for inception (setup.py) ... done
  Created wheel for inception: filename=inception-0.0.3-cp36-none-any.whl size=6886 sha256=2f6495d7b15ed233d86ebab3cdeb2080e7e6efb8f7e49cca0e43501f4d0aec01
  Stored in directory: C:\Users\daewon\AppData\Local\Temp\pip-ephem-wheel-cache-y815f1x4\wheels\cf\b6\e0\3222c958c75735f400a4913aa5193afae83100479d34c4af44
Successfully built inception
Installing collected packages: inception
Successfully installed inception-0.0.3
WARNING: You are using pip version 19.3; however, version 19.3.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

Successfully installed inception-0.0.3 가 나오며, 설치가 정상적으로 완료된 것을 확인할 수 있다.

다소 장황하게 설명을 했는데, 서양의 개발자들이 만든 패키지들 중에 이런 동일한 문제를 가지고 있는 패키지들을 종종 만나게 된다. setup.pyread_description 함수 부분은 거의 표준적으로 사용되는 부분이기 때문에, 다른 패키지 설치용 setup.py에도 동일하게 들어있는 게 정말 많다. 정말 사소한 문제인데, 이런 문제 때문에, 패키지를 못깔아서 시간을 허비하는 경우가 많다. 나 또한 굉장히 많은 시간을 허비했다. 이 과정을 조금 잘 이해해 두면, 나중에 동일한 문제를 만났을 때 쉽게 문제를 피해갈 수 있을 것이다.

728x90