MacOS Python3 개발을 위한 Pyenv와 Autoenv 구성 방법

Python 은 버전관리가 필요합니다!
활용도가 높은 Python

파이썬은 이곳 저곳 정말 다양한 프로젝트에서 많이 사용 되어지고 있다.

그러다보니 Python 버전도 EoL된 2.x 버전 부터 Python 3.x 까지 프로젝트에 따라 사용되어야 하는 버전도 다르고, 라이브러리 의존성에 의해서 파이썬 버전을 강요 당하는 일도 빈번하다.

때문에 [ Python버전 , Python라이브러리 ] 에 따라 격리된 환경에서 사용해야 하는 것이 이젠 거의 필수적인 상황이다.

요구되는 파이썬 환경(Environment)에 따라서 조금이라도 편하게 사용하고자 몸부림치면서 가장 즐겨 사용하고 있는 방법을 정리 해보도록 하겠다.

pyenv multi version management
Pyenv multi version project

 

Pyenv 파이썬 가상환경 사용을 위해 필요한 것들

단순하게 보자면 Pyenv는 원하는 Python버전을 쉽게 설치할 수 있는 도구로 생각할 수 있다. 그래서 파이썬을 격리된 환경으로 실행시켜주는데 몇가지를 더 필요로 하게 되는 것.

  • pyenv : 파이썬 버전을 쉽게 설치할 수 있도록 해준다. 필요한 파이썬 버전을 설치할때의 복잡함을 한방에 해결해주는 너무나 고마운 도구다. 
  • pyenv-virtualenv : 이전에도 virtualenv, venv등 파이썬 가상화를 통해 실행환경들을 격리해 라이브러리를 분리 사용하려고 했던 시도들이 있었는데 pyenv-virtualenv는 pyenv에 플러그인되어 파이썬환경을 가상화 시켜준다. (pip를 통해 라이브러리를 설치를 하면 각각의 환경마다 별도의 위치에 라이브러리가 설치 된다.)
  • autoenv : 디렉터리를 이동할때 .env로 설정된 스크립트를 실행한다.(프로젝트 폴더로 이동만 하면 된다) 폴더에 존재하는 ".env" 파일에 기록된 내용을 실행하는것 뿐이지만 이것만으로도 천국을 경험하게 해준다.

대략 위와 같이 필요한 파이썬 관리 도구에 대해서 이해를 해두고 시작하면 조금 덜 헷갈릴 것이다. 그럼 이 3가지를 설치하고 설정까지 완료 해보자.

 

1. Mac에서의 설치. (pyenv, pyenv-virtualenv, autoenv)

우선 Xcode 커맨드라인 툴과 brew를 설치하고 넘어가자.

## 맥에서는 Xcode Command Line Tools 설치가 필요하다.
> sudo xcode-select --install

## Homebrew 패키지 관리자를 설치 한다.
> /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Homebrew로 파이썬 버전지옥에서 벗어나게 해줄 pyenv 식구들을 설치 한다.

## Homebrew 를 통해 간단하게 설치를할 수 있다.
> brew install python-build
> brew install pyenv pyenv-virtualenv autoenv

 

2. Python shell 환경 구성.

zsh을 사용하는 경우 home폴더의 '~/.zshrc'에 쉘환경 설정을 한다. bash를 사용한다면 '~/.bashrc'에 설정하도록 한다.

## pyenv .zshrc configure
> echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
> echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
> echo 'eval "$(pyenv init --path)"' >> ~/.zshrc
> echo 'eval "$(pyenv init -)"' >> ~/.zshrc

> ## autoenv .zshrc configure
> echo 'export AUTOENV_ASSUME_YES=True' >> ~/.zshrc
> echo "source $(brew --prefix autoenv)/activate.sh" >> ~/.zshrc

대부분 Pyenv 환경 설정을 여기까지만 하게 되는데, 요즘들어 pip로 패키지를 설치할때 대괄호 ' [ '를 사용하면

'zsh: no matches found: uvicorn[standard]' 같은 에러가 발생한다. 이유는 zsh 에서 대괄호를 globbing(패턴인식) 문자로 인식하고 있기 때문이다. python과 pip를 실행할때는 대괄호를 패턴문자로 인식하지 않도록 예외처리를 하자.

## 파이썬을 실행할때 Globing이 동작하지 않도록 쉘을 설정한다.
> echo 'alias python="noglob python3"' >> ~/.zshrc
> echo 'alias python3="noglob python3"' >> ~/.zshrc
> echo 'alias pip="noglob pip3"' >> ~/.zshrc
> echo 'alias pip3="noglob pip3"' >> ~/.zshrc

 

Pyenv를 잘 사용해보자

pyenv 사용방법은 그다지 어렵지 않다. 평소 파이썬 가상환경을 사용하지 않았다면 2가지 정도를 잘 이해하고 넘어간다면 이전과 크게 다르지 않게 사용할 수 있다는 것을 이해할 수 있다.

  • pyenv : 우선적으로 $PYENV_VERSION 환경변수로 파이썬 환경을 불러온다(우선순위가 1번이다). $PYENV_VERSION 환경변수가 없을경우 폴더에 있는 '.python-version'에 네이밍된 파이썬 환경을 사용한다(우선순위가 2번이다). 이를 이용해 Shell, Local, Global과 같이 단계적 우선순위로 사용할 파이썬 버전을 지정할 수 있다. 사용중인 파이썬 환경은 Shell에서 'pyenv version' 으로 확인 할 수 있다.
    • Global : 홈 디렉토리에 있는 '~/.pyenv/version' 을 생성/이용해 전역적으로 지정된 파이썬 환경을 사용하도록 한다.
    • Local : 현재 디렉토리에 있는 '.python-version'을 생성/이용해 지역적으로 사용할 파이썬 환경을 설정 한다.
    • Shell : 디렉터리와는 관련 없이 'PYENV_VERSION' 환경변수를 설정하고 pyenv가 해당 버전을 사용하도록 한다. 사용하는 shell 이 종료될때까지 설정한 파이썬 환경을 유지 한다.(우선순위가 가장 높다)
    • 예전 virtualenv에서 사용하던 방식을(activate, deactivate) 사용할 수도 있지만 위 3가지 범위와 혼용하는 것을 추천하지 않는다.
  • autoenv : Shell에서 폴더를 이동할때마다 폴더에 있는 '.env' 를 실행한다. (pyenv와는 직접적으로 연관이 없다) 
    • .env 내에 'pyenv local test-project'라고 되어 있다면 'test-project'라는 파이썬 가상환경을 자동으로 불러 올것이다.
    • 'pyenv local test-project'가 실행되면 해당 폴더에 .python-version이 생성된다.

 

1. Pyenv 를 사용하는 방법은 간단하다.

파이썬 가상환경의 Base가 될 파이썬 3.11.3 버전을 pyenv로 설치 해보자.

## pyenv로 현재 설치된 파이썬 버전 리스트를 확인해본다. '*'로 사용중인 버전에 표시가 된다.
> pyenv versions
* system

## pyenv로 설치 할 수 있는 파이썬 버전이 너무 많다. 3.11 버전만 출력해보자.
> pyenv install -l|grep '3.11'
  3.11-dev
  3.11.1
  3.11.2
  3.11.3
  ...
  
## 3.11.3 버전을 설치 한다.
> pyenv install 3.11.3
    python-build: use openssl@1.1 from homebrew
    python-build: use readline from homebrew
    Downloading Python-3.11.3.tar.xz...
    -> https://www.python.org/ftp/python/3.11.2/Python-3.11.3.tar.xz
    Installing Python-3.11.3...
    python-build: use readline from homebrew
    python-build: use zlib from xcode sdk
    Installed Python-3.11.3 to /Users/name/.pyenv/versions/3.11.3

 

1-1. Global 로 Pyenv 버전을 설정하는 방법

설치된 파이썬 3.11.3버전을 Base로 Global(전역) 로 사용할 가상환경을 만들어 보자. 

## 설치된 파이썬 버전 리스트를 확인해보자.
> pyenv versions
* system
  3.11.3


## 3.11.3을 base로 virtual 환경을 구성한다. 
> pyenv virtualenv 3.11.3 base

## 설치된 파이썬 버전 리스트를 확인해보자.
> pyenv versions
* system
  3.11.3
  3.11.3/envs/base
  base


## 만들어진 base를 Global로 설정한다.
> pyenv global base

## 현재 사용중인 파이썬 버전 리스트를 확인해보자. '*'로 사용중인 버전에 표시가 된다.
> pyenv versions
  system
  3.11.3
  3.11.3/envs/base
* base --> /Users/name/.pyenv/versions/3.11.3/envs/base (set by /Users/name/.pyenv/version)

 

1-2. Local 로 Pyenv 버전을 설정하는 방법

프로젝트 폴더를 만들어 Local(지역적) 로만 사용할 가상환경을 만들어 보자. 설정된 디렉터리 하위로는 local로 설정된 파이썬 가상환경을 사용하게 된다.

## 프로젝트 폴더 생성.
> mkdir ~/projectA
> cd ~/projectA

## 현재 폴더에서 사용중인 파이썬 환경을 확인한다. (아직 local설정이 없어 base를 불러온다.)
> pyenv version
base (set by /Users/name/.pyenv/version)

## 가상환경으로 사용할 projectA 환경을 생성해보자.
> pyenv virtualenv base projectA

## 지금까지 생성된 pyenv 환경을 확인해본다.
> pyenv versions
  system
  3.11.3
  3.11.3/envs/base
  3.11.3/envs/projectA
* base --> /Users/name/.pyenv/versions/3.11.3/envs/base (set by /Users/name/.pyenv/version)
  projectA


## 현재 폴더에서 사용할 projectA 환경을 pyenv local로 설정하고 내용을 확인한다.
> pyenv local projectA

> ls -la
total 8
drwxr-xr-x    3 name  staff    96 11  2 14:21 .
drwxr-xr-x@ 194 name  staff  6208 11  2 14:21 ..
-rw-r--r--    1 name  staff     9 11  2 14:21 .python-version

> cat .python-version
projectA

## pyenv 로 현재 사용중인 버전을 확인할 수 있다. .python-version에 설정된 환경임을 알수있다.
> pyenv version
projectA (set by /Users/name/projectA/.python-version)

 

1-3. Shell 로 Pyenv버전을 설정하는 방법

디렉터리에 설정된 .python-version과는 상관 없이 PYENV_VERSION을 이용해 사용중인 쉘이 종료 될때까지 지정된 파이썬 가상환경을 유지 한다. (또는 'unset PYENV_VERSION' 으로 날려줘야 한다.)

## projectA 폴더로 이동시 pyenv local로 설정된 projectA환경을 자동으로 불러온다.
> cd ~/projectA
> pyenv version
projectA (set by /Users/name/projectA/.python-version)
    
## projectA폴더에 있지만 base 환경을 사용해야할 수 있다.
> pyenv shell base
> pyenv version
base (set by PYENV_VERSION environment variable)

set by 로 현재 파이썬 환경이 지정된 위치를 설명해주는 것을 확인할 수 있다.

## pyenv shell 로 불러온 환경은 shell을 종료할때까지 유지 된다.
> echo $PYENV_VERSION
base

> pyenv version
base (set by PYENV_VERSION environment variable)

## 또는 unset으로 PYENV_VERSION을 해제 해버리면 global또는 local 환경을 불러온다.
> unset PYENV_VERSION
> pyenv version
projectA (set by /Users/name/projectA/.python-version)

 

2. Autoenv로 폴더에 진입할 때 환경구성을 한번에 끝내자.

Pyenv로 프로젝트마다 격리된 파이썬 가상환경 구성을할 수 있지만 뭔가 아쉽지 않은가?

그래서 autoenv를 함께 사용해 프로젝트 폴더에 진입시 프로젝트 환경을 한번에 구성할 수 있도록 하기 위해 autoenv를 사용한다.

## projectA폴더에 진입시 autoenv로 환경설정을 하도록 하자.(cat의 이스케이프 문자 주의)
> cd ~/projectA
> cat <<EOF >.env
export PYENV_VERSION="projectA"
export MY_STORE_DIR="/tmp/devel_dir"
pyenv local \$PYENV_VERSION
echo "####################################"
echo "# \`date\`"
echo "# Woking Dir: \$PWD"
echo "# MY_STORE_DIR = \$MY_STORE_DIR"
echo "# Python Env: \`pyenv version\`"
echo "####################################"
EOF

쉘에서 위와 같이 입력되면 .env 파일이 projectA폴더에 아래의 내용으로 생성된다.

이스케이프 문자를 제외한 스크립트 내용
이스케이프 문자를 제외한 스크립트 내용

 

이제 projectA폴더에 진입하게 되면 아래와 같이 출력되며 python 가상 환경은 물론 프로젝트에 필요한 스크립트가 자동실행된다.

apply autoenv script
폴더에 진입시 autoenv를 통해 출력된다.

 

이렇게 autoenv '.env'에 projectA에 필요한 설정을 명시해 프로젝트 폴더에 진입과 동시에 개인적인 환경변수 설정과, 파이썬 가상환경 까지 스크립트로 실행해 조금 더 부주의(?)로부터 벗어날 수 있었다.

 

마치며

다만 PyenvAutoenv로 구성된 설정은 .python-version과 .env파일에 저장되어 사용되는데 이러한 설정은 프로젝트의 형상관리에 포함되지 않도록 하는 것이 좋다. (개인적인 설정이 프로젝트에 영향을 주어선 안된다.)

때문에 git으로 형상관리를 한다면 .gitignore 에서 .python-version과 .env를 형상관리 하지 않도록 처리 하는것이 바람직하다.

 

 

참고자료

https://github.com/pyenv/pyenv

https://github.com/pyenv/pyenv-virtualenv

https://github.com/hyperupcall/autoenv