youngfromnowhere
[Python] pyenv로 가상환경 구축하기. 본문
1. Python의 여러 가상환경 관리 툴
지금 듣고 있는 강의에서 가상환경 구축을 위해 pyenv라는 툴을 이용하라고 한다. 근데 이게 좀 복잡해 보인다. 가상환경만 만드는게 아니라 python 버전 관리 기능까지 포함하고 있다.
가상환경은 외부 라이브러리에 대한 의존성을 관리하기 위한 것인데, 사실 어떤 프로젝트가 외부 라이브러리 뿐 아니라 python의 버전 그 자체에도 의존성을 가질 수 있기 때문에 버전 관리 기능을 동시에 할 수 있는 툴을 쓰는 것 같다.
난 이미 이전에 python 버전 관리는 update-alternatives 명령으로, 가상환경은 python -m venv로 했었기 때문에 그
냥 그렇게 하려고 했는데, 다음과 같은 메세지가 떴다. (현재 python 버전은 3.10.12)
본래 venv는 python이 설치될 때 같이 설치되는 걸로 알았는데 뭔가 바뀌었나보다. stackoverflow에서 python의 가상환경 구축과 관련한 패키지들에 대해 잘 정리된 글을 찾았다.
What is the difference between venv, pyvenv, pyenv, virtualenv, virtualenvwrapper, pipenv, etc?
Python 3.3 includes in its standard library the new package venv. What does it do, and how does it differ from all the other packages that match the regex (py)?(v|virtual|pip)?env?
stackoverflow.com
맨 위의 답변글을 요약하면.
pyvenv
python3.3부터 python3.7까지, python과 함께 설치되는 스크립트. python3.8부터는 제거됨. python -m venv 명령은 이 pyvenv와 완전히 똑같은 기능을 가진다.
즉, 맥락상, python3.3~3.7까지 pyvenv가 venv의 역할을 대신한 것으로 보인다. (개인적인 추측)
venv
python3와 함께 설치되는 패키지. python -m venv 명령으로 실행할 수 있다. 단, 어떤 배포판에서는 외부 패키지 로 분리되었다. (Ubuntu/Debian 배포판의 경우 python3-venv를 설치해야 한다. 위 이미지에서 설치를 요구하라고 한 그 패키지다.)
virtualenv
기본으로 설치되는 venv보다 더 확장된 기능을 제공한다.
실행하면 현재 디렉토리에 env/ directory를 생성하고 그 안에 여러 파일들이 설치된다. 그리고 PATH 환경변수의 앞 쪽에 (pwd)/env/bin/을 등록한다. env/bin에는 python3의 binary가 설치되며, 여기에 설치된 python은 (/usr/bin/python이 아닌) 자신의 경로를 기준으로 library를 탐색한다.
(사용법은 기존의 venv와 같은것으로 보인다.)
pyenv
python의 버전을 분리하기 위한 패키지. 활성화하면 PATH 환경변수의 앞에 ~/.pyenv/shims를 추가한다. shims는 python, pip 등의 "Python command" 호출을 '가로채서' 다른 곳으로 redirect 한다. (자세한 작동 원리는 뒤에서 다시 알아보자.)
기존의 가상환경은 외부 패키지의 버전은 분리하지만 python 자체의 버전은 분리하지 않기 때문에, 서로 python 버전이 호환되지 않는 프로젝트를 동시에 다루면서 패키지 버전과 python 버전을 동시에 관리하고자 할 때 쓴다.
pyenv-virtualenv
pyenv와 virtualenv를 동시에 쓸 수 있도록 해주는 (즉 python 버전관리와 패키지 버전관리를 동시에 할 수 있도록 하는) pyenv의 plug-in이다.
그러나 python 3.3 이후부터는, pyenv-virtualenv를 실행할 때 "python3 -m venv(즉 pyvenv 혹은 venv)"가 실행된다.
pyenv-virtualenv를 통하지 않고 pyenv와 virtualenv를 동시에 쓸 수도 있다.
virtualenvwrapper
virtualenv의 extension
pyenv-virtualenvwrapper
pyenv와 virtualenvwrapper를 동시에 쓸 수 있도록 해주는 pyenv의 plug-in
2. pyenv 설정하기
Python 버전 관리와 패키지 버전 관리가 동시에 필요한 상황을 가정하고 pyenv로 가상환경을 구축해보자.
https://github.com/pyenv/pyenv
GitHub - pyenv/pyenv: Simple Python version management
Simple Python version management. Contribute to pyenv/pyenv development by creating an account on GitHub.
github.com
- pyenv의 공식 github repo
다음 명령으로 install한다.
$ curl https://pyenv.run | bash
https://pyenv.run url로 get 요청을 보내서 받아온 data를 bash에 input으로 넣는다.
bash의 설정파일을 통해 환경변수를 설정하라는 내용이다. 메세지에 언급된 ~/.bash_profile, ~/.profile, ~/.bashrc 등은 bash가 로그인할 때 사용하는 설정파일들이며, eval 명령어는 "argument로 입력된 것들을 합하여 command를 구축하고, 실행하라"는 명령이다. 이에 대해서도 따로 글로 다루기로 한다.
.bashrc에 $(pyenv virtualenv-init -)를 추가하고 나자 shell의 반응이 너무 느려졌다. pyenv 공식 레포의 이슈 페이지에 따르면, pyenv virtualenv-init - 에 의해 추가되는 스크립트 중간 중간에 $() command마다 100ms 만큼의 delay가 걸려있기 때문이라고 한다.
해당 이슈를 다루고 있는 깃헙 이슈
https://github.com/pyenv/pyenv-virtualenv/issues/259
Slow shell performance after running pyenv virtualenv-init · Issue #259 · pyenv/pyenv-virtualenv
It looks like there is some issue on my system that is causing very poor runtime performance after running pyenv virtualenv-init. Related to #132 I think the issue is with pyenv verision-name. What...
github.com
마지막에 추가한 "pyenv virtualenv-init -"가 문제가 되는것 같은데, 이 부분을 생략하고 가상환경을 수동으로 활성화/비활성화 하는 것을 고려할 수도 있겠다.
3. pyenv 사용하기
3.1. pyenv로 python 배포판 설치하기
먼저, 다음 명령으로 "pyenv install"로 설치할 수 있는 python 배포판의 목록을 확인한다.
$ pyenv install --list
목록 중 몇가지를 골라 설치해보자. 여기서는 Python3.7.13과 Python3.8.13을 설치해본다.
$ pyenv install 3.7.13
$ pyenv install 3.8.13
"pyenv versions"를 통해 현재 설치된 python 배포판들의 목록을 확인할 수 있다.
3.2. pyenv로 가상환경 생성하기
pyenv virtualenv 명령으로 현재 디렉토리에 가상환경을 생성한다.
$ pyenv virtualenv <python_version> <venv_name>
pyenv versions 명령으로 생성된 가상환경의 목록을 볼 수 있다.
3.3. pyenv로 사용할 version(파이썬 배포판 + 가상환경) 설정하기
pyenv 공식문서를 참조하면, pyenv는 다음과 같은 과정을 통해 shims가 python 관련 command (python, pip 등)를 어디로 redirect할지 결정한다.
Understanding Python version selection
When you execute a shim, pyenv determines which Python version to use by reading it from the following sources, in this order:
- The PYENV_VERSION environment variable (if specified). You can use the pyenv shell command to set this environment variable in your current shell session.
- The application-specific .python-version file in the current directory (if present). You can modify the current directory's .python-version file with the pyenv local command.
- The first .python-version file found (if any) by searching each parent directory, until reaching the root of your filesystem.
- The global $(pyenv root)/version file. You can modify this file using the pyenv global command. If the global version file is not present, pyenv assumes you want to use the "system" Python (see below).
A special version name "system" means to use whatever Python is found on PATH after the shims PATH entry (in other words, whatever would be run if Pyenv shims weren't on PATH). Note that Pyenv considers those installations outside its control and does not attempt to inspect or distinguish them in any way. So e.g. if you are on MacOS and have OS-bundled Python 3.8.9 and Homebrew-installed Python 3.9.12 and 3.10.2 -- for Pyenv, this is still a single "system" version, and whichever of those is first on PATH under the executable name you specified will be run.
1. PYENV_VERSION 환경변수를 참조한다. pyenv shell 명령을 통해 현재 shell에서 이 변수의 값을 설정할 수 있다.
2. 특정 application에서만 적용할 version을 (해당 디렉토리의) .python-version 파일에서 참조한다. pyenv local 명령을 통해 현재 directory의 .python-version 파일을 수정할 수 있다.
3. (2에서 version을 특정하지 못하면) 부모 directory를 올라가면서 .python-version 파일을 찾아 참조한다. (root directory에 도달할때까지 검색한다.)
4. $(pyenv root) directory (즉, pyenv를 install한 사용자의 홈 디렉토리)의 version 파일. 이 파일은 pyenv global 명령을 통해 수정할 수 있다. 이 파일을 찾지 못하면, pyenv는 사용자가 "system" Python을 사용하겠다는 것으로 간주한다.
"system python"이란? > PATH 환경변수에 등록된 directory를 순서대로 탐색하면서, shims의 directory 이후로 처음으로 발견되는 Python 배포판.
다시 정리하면
pyenv shell <python version or env name> - 현재 shell에서 사용할 파이썬 배포판을 설정 (PYENV_VERSION 환경변수 참조)
pyenv local <python version or env name> - 현재 directory(와 그 하위 directory)에서 사용할 파이썬 배포판을 설정 (.python-version 파일 참조)
pyenv global <python version or env name> - 사용자의 home directory 내에서 global하게 사용할 파이썬 배포판을 설정 (/home/(user name)/.python-version 파일 참조)
(위 명령으로 설정하는 것은 '사용할 python 배포판'이지 가상환경이 아니다. 가상환경은 pyenv activate 명령으로 활성화 시킨다. 위에서 .bashrc에 eval "$(pyenv virtualenv-init -)"를 추가하지 않았기 때문에 수동으로 활성화 시켜야 한다.)
pyenv shell test
python의 빌트인 모듈인 sys모듈에서는 version이 어떻게 확인되는지 또한 확인해 보았다.
pyenv를 이용하여 python version을 바꾸었더라도, script의 첫 줄에 shebang line을 이용해 인터프리터를 /usr/bin/python3로 특정하면 version은 3.10.12로 표시된다.
이러한 충돌을 피하려면 (즉 shebang line이 pyenv가 설정한 version의 python을 지정하도록 하려면) 첫 라인을 #!/usr/bin/env python(혹은 python3)로 바꿔주면 된다.
#!/usr/bin/env로 shebang line을 바꾸면 시스템은 인터프리터를 $PATH 환경변수에 등록된 디렉토리에서 찾게 되며, 따라서 pyenv를 설치하면서 등록된 /home/(user name)/.pyenv/shims directory를 만나면서 pyenv가 설정한 version의 python을 사용하게 되는 것이다.
한편, pyenv shell로 등록한 python version은 자식shell에서도 유지된다. 환경변수는 자식shell에서도 공유되므로 당연한 결과이다.
shell의 기본 python version을 기존의 것으로 되돌리고 싶을 때는 "pyenv shell system" 명령을 사용한다. 그럼 이제 python3 명령은 기존의 /usr/bin/python3를 구동시키게 된다.
pyenv local 로 특정 directory에 가상환경 적용하기
first_project directory를 만들고 first_env 가상환경을 활성화 하자. 그리고 해당 가상환경에 numpy를 설치하고, pip freeze를 이용해 해당 환경에 설치된 패키지의 리스트를 담은 requirements.txt 파일을 생성해보자.
pyenv activate 명령으로 가상환경을 활성화 하면 프롬프트 앞쪽에 가상환경의 이름이 보인다. pip으로 numpy를 install하고, pip freeze로 numpy가 설치되어 있는 것을 확인했다.
가상환경을 비활성화 하면, pip freeze로 볼 수 있는 패키지 리스트에 numpy가 없는 것을 볼 수 있다.
pyenv activate 명령 전후의 변화 살펴보기
django_env 가상환경을 설정하고, 해당 가상환경을 pyenv local에 등록하였다.
그 후 pyenv activate로 django_env 가상환경을 활성화 하면 다음과 같은 변화가 발생한다.
비활성화 상태에서는 codeit_django/.python-version을 참조하여 python version을 인식하지만, 활성화 상태에서는 $PYENV_VERSION 환경변수를 통해 python version을 인식한다. (pyenv shell로 가상환경/python version을 등록한 것과 같은 상태)
'Python' 카테고리의 다른 글
[Python] Generator and yield (0) | 2024.10.23 |
---|---|
[Python] Iterator (0) | 2024.10.23 |
[Python] python의 special methods (0) | 2022.11.17 |
[Python] Decorator3. Property (0) | 2022.11.16 |
[Python] Decorator 2. abstractmethod() (0) | 2022.11.15 |