본문 바로가기

Python/Python

[Python] pyenv 와 poetry의 개념, 그리고 두 개를 함께 사용하기

반응형

오랫동안 파이썬을 사용해오면서 가상환경 관리 도구는 conda, 패키지 관리 도구는 pip 으로 사용해왔다. 사실 이 2가지를 굳이 선택한 이유는 따로 없었다. 단지 처음 파이썬을 입문하기 시작할 때 사용하던 도구가 굳혀진 것일 뿐.. 그런데 최근에 두 도구를 사용하면서 드디어(?) 불편한 점으로부터 고통을 받았다. 특히, conda의 경우는 conda 명령어로 설치할 수 있는 패키지가 매우 한정적이라는 점이여서 특히, 여러가지 파이썬 버전을 설치하는 데 제약이 많은 듯 했다. 그리고 pip은 서로 다른 패키지 간에 버전이 다름으로써 충돌이 날 수 있는 문제를 사전에 알려주지 않고, 설치한 것은 다 설치하고 잘 될거라 생각했지만 막상 코드를 실행하면 에러가 발생하는 난항을 겪었다.

 

순수한 파이썬 환경에서 가상환경과 패키지를 관리해보자


그래서 이번 기회에 conda에서 벗어나서 순수하고 깨끗한 파이썬 환경에서 가상환경을 구축하고 관리하고 싶었다. 그래서 본격적으로 다양한 라이브러리들을 살펴보았다. 그 중에서 pyenv라는 것을 선택했는데, 이유는 패키지 관리 도구랑 약간 맞물려 있었다. 개인적으로 이번에 여러가지를 찾아보면서 가상환경 도구를 선택할 때는 패키지 관리 도구랑 같이 결합해서 생각해야 하지 않을까? 라는 느낌이 들었다. 우선 필자를 포함해서 다른 분 들 대부분은 다음과 같은 용어들을 들어본 적이 있을 것이다. pip, pipenv, conda, virtualenv, venv, pyenv, poetry, pdm, .. 등등.. 처음에는 이게 다 동일한 도구인 줄 알 았다. 하지만 이것들은 크게 2가지 분류로 나뉜다.

 

크게 가상환경 관리 도구와 패키지 관리 도구로 나눌 수 있다

 

사실 위 그림이 정확한 것은 아니다. 왜냐하면 conda 자체가 가상환경도 관리하고 패키지도 설치할 수 있기도 하다. 또 pipenv도 내부적으로 virtualenv로 가상환경을 관리하기 때문에 위처럼 두 개로 엄격히 분리하는 게 맞지 않을 수 있지만, 전달하고 싶은 핵심은 어쨌건 파이썬에서는 가상환경 관리와 패키지 관리, 이 두 개의 부분으로 나누어져있다는 것이다.

 

이번 포스팅에서는 위 그림 중에서 pyenv에 대해서 알아보려고 한다. 이를 선택해서 알아보고자 한 이유는 다음과 같다. 참고로 pyenv는 안타깝게도 Window OS에서는 지원하지 않는다.

 

  • 여러 개의 파이썬 버전을 설치할 수 있으며 스위칭이 가능하고, globally, locally 하게 파이썬 버전을 선택 가능한 게 강점이라고 느꼈음
  • 동시에 내부적으로 virtualenv를 활용해서 가상환경도 생성이 가능하기 때문에 특정 파이썬 버전의 특정 가상환경 생성이 가능함
  • 최근 오픈소스 진영과 컨퍼런스에서 자주 보이는 poetry, pdm 패키지 도구에서 pyenv를 함께 사용하는 것을 공식문서에서 소개함
  • pyenv는 패키지 관리 도구를 pip으로 사용해도 되고 poetry, pdm과 결합해서 사용이 가능해 자유도가 높다고 생각(사내에서는 아직 pip을 사용 중이여서)

그리고 해당 포스팅 말미에서는 개인적으로 배워보고 싶은 poetry에 대해서 배워보려고 한다. 사실 poetry는 기존에 파이썬 공식문서에서 권장하는 pipenv와 커버하는 스코프가 매우 유사하다. 일단 pyenv에 대한 사용법에 대해서 하나씩 배워보도록 하자.


1. pyenv 사용해보기

1.1 pyenv 설치

설치하는 방법은 다음과 같다. MacOS 기준으로 하였다. curl을 통해 셸 스크립트를 실행하면서 설치해도 되고, brew를 통해 설치할 수 있다. 참고로 curl 로 설치하면 부가적으로 설치해야 하는 virtualenv 설치 과정도 한번에 해준다.

 

curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
brew install pyenv pyenv-virtualenv

 

성공적으로 설치되었다면 셸이 활성화 될 때마다 pyenv를 시작할 수 있도록 initialization 하는 과정이 필요하다. .bashrc 나 .zshrc 파일에 아래 내용을 추가해준다.

 

export PATH="${HOME}/.pyenv/bin:$PATH"
# shell init 시 pyenv 시작 명령어
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

 

그리고 난 뒤 셸을 종료하고 다시 키거나 source 명령어을 실행해준다.

 

source ~/.zshrc

 

그리고 난 뒤 pyenv가 잘 설치되었는지 확인하기 위해 아래 명령어를 실행해서 pyenv 명령어의 파일 경로를 체크해본다.

 

which pyenv

1.2 pyenv로 여러가지 파이썬 버전 설치해보기

이제 pyenv를 설치했으니, 기본적인 기능인 여러가지 파이썬 버전을 설치해보도록 하자.

 

pyenv install {VERSION}

 

만약에 어떤 버전이 있는지 확인해보려면 아래 명령어를 입력해보고, 해당하는 버전을 위 명렁어의 {VERSION} 에 넣어주면 된다.

 

pyenv install -l

 

그리고 난 뒤, 설치된 파이썬 버전을 확인해보려면 아래 명령어를 입력해보자. 참고로 pyenv로 설치한 파이썬 파일 경로를 보고 싶다면 pyenv which {VERSION} 명령어를 입력하면 된다.

 

pyenv versions

 

다음은 설치한 특정 파이썬 버전을 삭제하는 명령어이다.

 

pyenv uninstall {VERSION}

 

다음은 pyenv 자체를 삭제하는 방법이다. pyenv 자체를 삭제하는 명령어는 pyenv root 경로의 디렉토리를 삭제하면 되는데, 기본적으로는 ~/.pynev 라는 디렉토리에 있지만, 환경마다 다를 수 있으니 우선 아래 명령어로 pyenv root 경로를 확인해보자.

 

pyenv root

 

위 명령어를 입력하고 나면 .pyenv 디렉토리가 있는 경로가 뜰 것인데, 해당 경로를 삭제해주면 pyenv가 삭제된 것이다.

1.3 pyenv가 관리하는 디렉토리들 : pyenv가 파이썬을 선택하는 눈(eye) !

pyenv는 여러가지 파이썬 버전을 선택하는 자유도가 있지만 그만큼 pyenv가 파이썬을 선택하는 기준이 여러가지가 되게 된다. 결국, 이 선택을 하기 위해 pyenv는 파이썬을 선택하기 위해 관리하는 디렉토리들 및 변수가 존재하고 파이썬을 선택하는 순서가 있다. 이를 알고 pyenv를 사용하게 된다면 훨씬 더 pyenv를 효율적이고 편하게 사용할 수 있을 것이다.

1.3.1. PYENV_VERSION 환경변수

pyenv는 가장 먼저 셸이 시작되면 PYENV_VERSION 이라는 환경변수 값에 있는 파이썬 버전을 global 하게 적용한다. 하지만 보통은 PYENV_VERSION 환경변수 값을 출력해보면 비어있을 것이다. 

 

환경변수 값이 비어있음

 

그래서 .bashrc 나 .zshrc 파일에 해당 환경변수 값에 파이썬 버전 값을 넣어주면 셸이 활성화 될 때마다 사용될 파이썬 버전을 global 하게 적용하고, pyenv는 해당 환경변수 값에 있는 파이썬 버전을 가장 1순위로 채택해서 사용한다. 여기서 헷갈리지 말아야 할 것은 (밑에서 배우겠지만) pyenv를 활용해서 특정 프로젝트 디렉토리 단위로 해서 파이썬 버전을 다르게 선택할 수 있는데, 그럴 경우에도 PYENV_VERSION 값에 있는 파이썬 버전이 override 된다.

 

헷갈릴 수 있으니 예를 들어보자. 나는 현재 my_project 디렉토리에서 python3.12.0 버전을 사용하기로 설정을 해놓았다. 하지만 PYENV_VERSION 환경변수 값에 python3.10.12 버전이 명시되어 있다면 my_project 디렉토리에 들어가서 파이썬 스크립트를 실행하면 pyyhon3.12.0이 아닌 python3.10.12 버전이 사용된다. 이에 대한 내용은 공식 github 설명에도 나와있다.

1.3.2 .python-version 파일 내의 버전 값

직전에 배운 PYENV_VERSION 환경 변수 값이 비어있을 경우, 다음으로는 pyenv가 locally 하게 특정 파이썬 버전을 설정해놓았을 때라면, 해당 버전의 파이썬 버전을 사용한다. 이를 이해하기 위해서는 우선 pyenv local 명령어를 알아야 한다. 해당 명령어로 특정 프로젝트 디렉토리 내에서 사용할 파이썬 버전을 명시해서 사용할 수 있다. 이렇게 되면 해당 디렉토리 내의 모든 재귀적인 파일들에서는 locally 하게 명시한 파이썬 버전을 사용한다

 

예를 한번 들어보자. 필자는 현재 pyenv-local 이라는 디렉토리로 이동해서 아래 명령어를 수행했다. 물론 먼저 pyenv install 명령어로 사용할 파이썬 버전을 설치해주어야 한다.

 

 

위 사진을 보고 명령어 한줄씩 상황을 이해해보자. 가장 먼저 셸이 초기에 활성화되고, 파이썬 버전을 확인했다. 3.10.12 버전이다. 그리고 python-local 이라는 디렉토리로 들어가서 해당 디렉토리에서는 3.12.0 버전만을 쓸 것이라고 명령어를 입력한다. 그러면 해당 디렉토리에 숨겨진 파일로 .python-version 이라는 파일이 생긴다. 해당 파일의 내용을 보니까 3.12.0 이라는 숫자가 입력되어 있는 것을 볼 수 있다. 이제 해당 디렉토리에서 사용중인 파이썬 버전을 다시 출력해보니까 이번엔 locally 하게 설정한 3.12.0 버전이 출력되는 것을 볼 수 있다.

 

이렇게 pyenv는 특정 디렉토리의 .python-version 파일 내에 명시된 값을 보고 해당 디렉토리 내에서 사용할 파이썬 버전을 선택한다. 위에서 언급했지만, 만약 PYENV_VERSION 이라는 환경변수 값이 3.12.0이 아닌 3.10.12 로 설정되어 있다면 locally 하게 설정한 버전이 3.12.0 이라 하여도 3.10.12를 사용함을 주의하자. 왜냐하면 pyenv는 PYENV_VERSION 값을 가장 1순위로 채택하기 때문!

1.3.3 $(pyenv root) 디렉토리 내의 파이썬 버전

pyenv가 파이썬 버전을 선택하는 마지막 기준은 pyenv root 경로 즉, .pyenv 디렉토리가 있는 경로 내의 version 디렉토리에 있는 파이썬 버전값들이다. 여기 내에 있는 파이썬 버전들은 pyenv global 명령어로 설정할 수 있다. 해당 명령어는 이름 그대로 전역 스코프에서 사용되는 파이썬 버전을 설정할 수 있다. 만약 해당 디렉토리에 아무런 파이썬 버전들이 없다면 기본적으로 환경 내에 디폴트로 설치되어 있는 파이썬을 사용한다. 그런 파이썬을 pyenv는 'system' 이라는 키워드로 나타낸다.

 

이렇게 pyenv가 파이썬을 선택하는 세가지 우선순위를 살펴보았다. 위와 같은 내용을 이해하고 있다면 내가 현재 사용하고 있는 파이썬 버전이 왜 그 버전인지 이해할 수 있게 될 것이다. 

1.3.4 global 하게 사용할 파이썬을 결정하는 또 다른 방법 : pyenv shell

추가적으로, pyenv shell 이라는 명령어도 별도로 살펴보려고 한다. pyenv shell 명령어는 argument로 파이썬 버전을 설정해주지 않으면 기본적으로 PYENV_VERSION 이라는 환경변수 값에 설정되어 있는 버전을 사용한다. 하지만 해당 환경변수 값이 비어있는 상태에서 pyenv shell 명령어를 입력하면 "pyenv: no shell-specific version configured" 와 같은 에러 메세지가 발생한다.

 

 

그래서 PYENV_VERSION 값이 명시되어 있지 않다면 반드시 pyenv shell {VERSION} 으로 argument에 파이썬 버전을 명시해주어야 한다. 이렇게  명시된 파이썬 버전은 global 하게 적용되어 PYENV_VERSION 이 갖는 효과와 동일하게 된다. 이 말은 곧 특정 디렉토리에서 locally 하게 설정된 파이썬 버전이 다르더라도 pyenv shell 의 argument로 설정된 파이썬 버전을 사용하게 됨을 의미한다. 

 

그러면 위와 같이 PYENV_VERSION 값이나 pyenv shell의 argument로 특정 파이썬 버전을 명시한 것을 해제하려면 어떻게 해야할까? 가장 쉬운 방법은 그 셸을 종료하면 된다. 다른 방법으로는 아래 명령어를 수행해서 해제할 수 있다.

 

pyenv shell --unset

1.3.5 여러가지 파이썬 버전을 동시에 사용하기

마지막으로, 위에서 배운 pyenv shell, pyenv local, pyenv global 명령어들 모두에 적용되는 사항인데, 여러가지 파이썬 버전을 동시에 사용하는 방법에 대해 알아보자. 우선 여러가지 파이썬 버전을 사용하는 방법은 아래처럼 명시하면 된다.

 

pyenv shell 3.12.0 3.10.12 3.7.1
pyenv local 3.12.0 3.10.12 3.7.1
pyenv global 3.12.0 3.10.12 3.7.1

 

위처럼 버전 값을 나열할 수 있는데, 나열하는 순서에 따라 사용할 파이썬의 우선순위가 부여된다. 위와 같이 명령어를 입력했을 때, 가장 첫번째에 입력한 3.12.0 버전이 기본적으로 사용하는 파이썬 버전이다. 즉, python -V 이라는 명령어를 입력했을 때, 3.12.0 버전이 나온다는 것이다. 그러면 나머지 2, 3번째에 입력한 버전들은 어떻게 사용할까? 간단하다. 단지 python3.10.12 main.py 또는 python3.7.1 main.py 이런식으로 특정 버전을 명시해주어서 사용하면 된다.

1.4 pyenv로 가상환경 관리하기

1.4.1 가상환경 생성

그러면 이제 pyenv로 가상환경을 생성시켜보자. 명령어는 아래와 같다. 사용할 파이썬 특정 버전을 명시할 수 있다.

 

pyenv virtualenv {PYTHON VERSION} {ENV NAME}

 

위 명령어에서 -p 옵션도 줄 수 있는데, -p 옵션을 주게 되면 해당 가상환경으로 들어가게 되었을 때, 가상환경 생성 시 명시한 파이썬 버전이 아닌 다른 파이썬 버전들도 찾을 수 있다.

1.4.2 가상환경 활성화, 비활성화

다음은 생성한 가상환경을 활성화하고 비활성화하는 방법이다.

 

# 활성화
pyenv activate {ENV NAME} 
# 비활성화
pyenv deactivate

1.4.3 가상환경 삭제

마지막으로 가상환경을 삭제하는 방법이다.

 

pyenv uninstall {ENV NAME}

2. poetry 시작해보기

이번에는 가상환경이 아닌 파이썬에 설치되는 여러가지 라이브러리 패키지들을 관리하는 도구들 중 하나인 poetry에 대해 알아보자. 사실 poetry를 알아보면서 poetry가 등장하기 약 1년 전에 pipenv가 먼저 등장하긴 했었다는 것을 알 수 있었다. 개발 히스토리도 그렇게 차이는 나지 않기도 하는데, 파이썬 공식 사이트에는 pipenv를 권장하기도 한다. 그리고 또 pdm 이라는 것도 존재한다. pdm는 2020년에 최초로 등장했다. 이 3가지가 사실 비슷한 기능을 지원하는데, 기능에 대한 설명은 다음과 같다.

 

이 3가지 툴이 pip 과 같은 전통적인 패키지 도구랑 다른 점은 라이브러리 간의 dependency를 해결해준다는 것이다. 한 애플리케이션에 사용되는 여러가지 라이브러리들 간에 모든 버전들 간에 호환성이 맞는 것은 아니다. 일례로, A 패키지에서 2.0 버전을 사용한다고 했을 때, 동시에 사용하는 B 패키지의 모든 버전이 A의 2.0 버전과 호환이 맞지 않을 것이다. 앞서 언급한 3가지 툴은 이러한 호환성을 체크해주고, 만약 문제가 있다면 아예 설치가 되지 않게 해주어 패키지 의존성 충돌 문제를 사전에 예방해주는 기능을 지닌다.

 

이번 포스팅에서는 3개의 패키지 중 poetry에 대해서 간단하게 사용해보도록 하자.

2-1. poetry 설치하기

poetry는 brew를 통해서 편리하게 설치할 수 있다. 설치한 뒤, poetry --version 명령어로 잘 설치되었는지도 확인해보자.

 

brew install poetry

 

2-2. poetry를 사용하는 프로젝트 시작하기

poetry를 사용하는 프로젝트를 시작하면 기본적으로 pyproject.toml 이라는 파일이 생성된다. 우선 poetry를 시작하는 방법은 크게 2가지가 있다. 우선 이미 존재하는 디렉토리에 poetry를 시작하려고 한다면 아래 명령어를 실행해주자.

 

$ mkdir poetry-tutorial
$ cd poetry-tutorial
$ poetry init

 

그러면 아래 사진처럼 어떤 프로젝트인지 설명을 붙히거나 기본적으로 사용할 파이썬 버전 등을 선택할 수 있다. 여기서 기본적으로 사용할 파이썬 버전은 위에서 배운 pyenv 가상환경에 따라 달라질 수 있다.

 

 

다른 방법으로는 새로운 디렉토리를 생성해주면서 해당 디렉토리 안에 poetry를 시작할 수 있다. 단, 이 방법은 직전에서 알아본 방법과는 다르게 프로젝트 디렉토리 구조를 만들어 주기도 한다.

 

 

아래 명령어로 실행이 가능하다.

 

poetry new {PROJECT NAME}

 

2-3. pyenv + poetry 사용하기

pyenv 와 poetry를 함께 사용할 때, 각 도구의 역할은 다음과 같다.

 

  • pyenv + poetry : 파이썬 버전 관리는 pyenv가, 가상환경과 패키지는 poetry가 관리

이제 아래에서 실습해볼 내용의 상황은 다음과 같다. 글로벌하게 사용하고 있는 파이썬 버전이 poetry를 사용하는 프로젝트에서 사용할 파이썬 버전보다 클 경우이다. 즉 글로벌하게 사용하는 파이썬 버전이 3.12.0이고 poetry 프로젝트에서 사용할 파이썬 버전이 3.10.12일 경우이다. 

 

특이한 점은 반대인 경우 즉, 글로벌하게 사용하는 파이썬 버전이 3.10.12이고, poetry 프로젝트에서 사용할 파이썬 버전이 3.12.0이면 에러가 발생하지 않는다는 점이다.(이에 대한 이유는 잘 모르겠어서.. github에 질문해놓았다.)

(질문에 대한 답변을 받았고, 이유를 요약하면 높은 파이썬 버전은 그 이하 버전의 모든 파이썬 버전을 호환하기 때문이다. 즉, poetry에서 명시한 파이썬 버전이 더 높고, global 하게 명시한 파이썬 버전이 그보다 낮더라도, poetry에서 명시한 파이썬 버전이 global하게 명시한 낮은 버전의 파이썬의 모든 것들을 호환하기 때문이다)

 

우선 현재 사용하는 파이썬 버전은 아래와 같다.

 

 

이제 poetry를 사용할 프로젝트 디렉토리를 생성해서 해당 프로젝트로 이동한 뒤 poetry init 명령어를 실행해보자. 이 때, poetry에서는 3.10.12 버전을 사용할 것이다. 생성된 toml 파일 내용은 아래와 같다.

 

 

이제 poetry shell 명령어나 특정 패키지를 설치하는 poetry add 명령어를 수행하면 아래와 같은 에러가 발생한다.

 

The currently activated Python version 3.12.0 is not supported by the project (3.10.12). Trying to find and use a compatible version.
Poetry was unable to find a compatible version. If you have one, you can explicitly use it via the "env use" command.

 

여기서 우리는 에러 메세지에 나와있는 것처럼 poetry env use라는 명령어를 사용할 수 있다. 해당 명령의 인자에 사용할 파이썬 3.10.12 버전의 경로를 명시해주면 된다. 

 

 

위 사진처럼 파이썬 3.10.12 버전의 파이썬 파일 경로를 명시해주면 poetry가 virtualenv를 사용해서 가상환경을 생성해준다. 그리고 poetry shell 이라는 명령어를 사용하면 생성한 가상환경을 활성화하여 그곳으로 들어간다. 참고로 이 때, nested shell을 생성해주는데, neested shell을 생성하는 구체적인 이유는 공식문서에서 확인할 수 있다.

 

어쨌건 생성한 가상환경 내부로 들어가서 파이썬 버전을 출력해보면 우리가 원하는 3.10.12 버전이 출력되는 것을 볼 수 있다. 우리는 이제 이 환경에서 자유롭게 poetry에 추가로 설치할 패키지를 add 하면 된다.

 

만약 poetry shell로 가상환경을 활성화 하지 않은 채 poetry run 명령어를 활용해서 스크립트를 실행할 때만 가상환경으로 실행시킬 수도 있다. 현재 위 그림에서 마지막 터미널 프롬프트를 보면 (pyenv-poetry-py.3.10) 으로 표시되어 가상환경 속에 들어와 있는 것을 볼 수 있다. 이제 deactivate 명령어를 실행하여 가상환경을 우선 비활성화시켜보자.

 

 

그리고 파이썬 버전을 출력해보니 다시 파이썬 3.12.0 버전이 된 것을 볼 수 있다. 하지만 poetry run 명령어를 실행해서 파이썬 버전을 출력해보면 아래처럼 다시 3.10.12 버전이 출력되는 것을 볼 수 있다.

 

 

 

이렇게 가상환경이 비활성화된 상태일 때, poetry 환경 내에서 스크립트를 실행하려면 위처럼 poetry run 명령어를 실행하면 된다. 이렇게 poetry run 명령어를 매번 작성하기 귀찮거나 가상환경에 지속적으로 접속한 상태이고 싶다면 위에서 알려준 poetry shell 명령어를 입력해서 nested shell을 생성해 아예 그 가상환경에 지속적으로 접속한 상태를 만들면 된다.


이렇게 해서 pyenv, poetry가 각각 무엇인지, 그리고 이 두개를 함께 어떻게 사용해볼 수 있는지에 대해 알아보았다. 필자도 이제 막연하게 사용해온 conda에서 벗어나고자 앞으로도 pyenv를 계속적으로 사용해보려고 한다.

 

# Reference

- Poetry docs

- pyenv wiki docs

- Switching management in poetry (docs)

반응형