pyenvによる仮想Python環境をAWS Cloud9上で構築する

AWS Cloud9上でpyenvによる仮想Python環境を構築して作業するディレクトリごとに異なるPythonバージョンを利用する場合の手順を確認したのでご紹介します。
2020.03.18

こんにちは、CX事業本部の若槻です。

AWS Cloud9上でpyenvによる仮想Python環境を構築して作業するディレクトリごとに異なるPythonバージョンを利用する場合の手順を確認したのでご紹介します。

  • 記事前半の確認してみたでは手順を確認した際の検証内容を記載しています。
  • 検証の結果をまとめた手順をすぐに見たい方は記事後半のまとめへどうぞ。

確認してみた

環境の初期設定

pyenvを公式リポジトリからgitクローンします。

$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

クローンしたpyenvが実行できることを確認します。

$ ~/.pyenv/bin/pyenv --version
pyenv 1.2.17-1-g89786b90

pyenvコマンドへパスを通しておきます。

$ export PATH="$HOME/.pyenv/bin:$PATH"

パス指定なしでpyenvを実行できるようになりました。

$ pyenv --version
pyenv 1.2.15-1-g49bf5952

pyenv initによりpyenv globalpyenv local実行時にpythonの実行パスの差し替えをできるようにします。

$ eval "$(pyenv init -)"

※深くは調べられていませんが、pyenv initの実行により内部では以下の処理が行われているようです。

$ echo "$(pyenv init -)"
export PATH="/home/ec2-user/.pyenv/shims:${PATH}"
export PYENV_SHELL=bash
source '/home/ec2-user/.pyenv/libexec/../completions/pyenv.bash'
command pyenv rehash 2>/dev/null
pyenv() {
  local command
  command="${1:-}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "$(pyenv "sh-$command" "$@")";;
  *)
    command pyenv "$command" "$@";;
  esac
}

pyenvでPythonバージョンを切り替える

pyenvの初期設定ができたので、実際にPythonバージョンを切り替えてみます。

現在の既定のPythonバージョンは3.6.10です。

$ python --version
3.6.10

pyenvでインストールできるPythonバージョンを確認してみます。結果は省略していますが、2.X.Xや3.X.Xのほかにもいろいろ利用できるようです。

$ pyenv install -l
Available versions:
  2.1.3
  2.2.3
  …
  (省略)
  …
  3.8.0
  3.8-dev
  3.9-dev
  …
  (省略)
  …
  stackless-3.4.7
  stackless-3.5.4

確認した中でpyenvで使用したいPythonバージョンを指定してインストールします。今回は3.8.0を指定しました。

$ pyenv install 3.8.0

インストールしたPythonバージョンがpyenvのバージョン一覧に追加されました。

$ pyenv versions
* system (set by /home/ec2-user/.pyenv/version)
  3.8.0

pyenv globalで使用したいPythonバージョンに切り替えます。

$ pyenv global 3.8.0

pyenv上は3.8.0に切り替わりました。

$ pyenv versions
  system
* 3.8.0 (set by /home/ec2-user/.pyenv/version)

しかし実際のPythonバージョンを確認すると3.6.10から変わっていません。

$ python --version
3.6.10

それもそのはずで、Cloud9ではpythonコマンドのAliasが既定で/usr/bin/python36であるため、この指定を削除する必要がありました。

$ which python
alias python='python36'
        /usr/bin/python36

この指定は~/.bashrc内のalias python=python36部分で既定で設定されているので、本部分をコメントアウトなどして削除します。

$ cat ~/.bashrc
# .bashrc

export PATH=$PATH:$HOME/.local/bin:$HOME/bin

# load nvm
export NVM_DIR="$HOME/.nvm"
[ "$BASH_VERSION" ] && npm() { 
    # hack: avoid slow npm sanity check in nvm
    if [ "$*" == "config get prefix" ]; then which node | sed "s/bin\/node//"; 
    else $(which npm) "$@"; fi 
}
# [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
rvm_silence_path_mismatch_check_flag=1 # prevent rvm complaints that nvm is first in PATH
unset npm # end hack


# User specific aliases and functions
alias python=python36

(省略)

既定のAliasの指定を削除したら、bashを再起動して変更を反映します。

$ exec $SHELL -l

pythonコマンドのAliasがpyenvに変わりました。

$ which python
~/.pyenv/shims/python

Pythonバージョンも3.8.0に切り替わりました。

$ python --version
Python 3.8.0

pyenv global systemにより既定のPythonバージョンに戻すこともできます。

$ pyenv global system
$ pyenv versions
* system (set by /home/ec2-user/.pyenv/version)
  3.8.0

戻りました。(既定のAliasの指定を削除したことにより既定で実行されるバージョンは2系となっています)

$ python --version
Python 2.7.16

ディレクトリごとに異なるPythonバージョンを利用したい

ここまでpyenv globalによりPythonバージョンを切り替える方法を確認してきましたが、実際の開発においては、同じ環境で異なるPythonバージョンを同時に作業したい場合があります。

例えば下記のような同じ階層にあるdir1およびdir2ディレクトリからなる環境で、dir1内ではPython3.8.0、dir2内ではPython3.9-dev、という風にディレクトリごとに異なるバージョンを利用したいとします。

/home/ec2-user/environment/
| -- dir1  ←Python3.8.0
| -- dir2  ←Python3.9-dev

このような場合は、pyenv globalではなくpyenv localコマンドを使用してバージョンを指定した方が便利です。

pyenv globalとpyenv localの検証

pyenv globalの場合

pyenvで既定のPythonバージョンが選択されている状態(3.8.0と3.9-devはインストール済み)で、

$ cd ~/environment
$ python global system
$ pyenv versions
* system (set by /home/ec2-user/.pyenv/version)
  3.8.0
  3.9-dev

dir1内でバージョンをpyenv globalにより3.8.0に切り替えます。

$ cd ~/environment/dir1
$ pyenv global 3.8.0
$ python --version
3.8.0

dir2内のPythonバージョンを確認すると、こちらも3.8.0となっていました。念の為bashを別プロセスで起動したとしても同じ結果となります。

$ cd ~/environment/dir2
$ python --version
3.8.0

Sets a local application-specific Python version by writing the version name to a .python-version file in the current directory.

pyenv localの場合

次に、Pythonバージョンを既定に戻した状態で、dir1内でバージョンをpyenv localにより3.8.0に切り替えてみます。

$ pyenv global system
$ cd ~/environment/dir1
$ pyenv local 3.8.0
$ python --version
3.8.0

またdir2内のバージョンをpyenv localにより3.9-devに切り替えます。

$ cd ~/environment/dir2
$ pyenv local 3.9-dev
$ python --version
Python 3.9.0a4+

dir1の方をもう一度確認すると3.8.0のままバージョンは保たれています。

$ cd ~/environment/dir1
$ python --version
Python 3.8.0

dir1dir2の上位のディレクトリも既定のバージョンのまま保たれています。

$ cd ~/environment
$ python --version
Python 2.7.16

Sets the global version of Python to be used in all shells by writing the version name to the ~/.pyenv/version file.

以上の検証の結果からも、ディレクトリごとに異なるPythonバージョンを使い分けたい場合は、それぞれのディレクトリでpyenv localコマンドによりバージョンを指定するのが良いということが分かりました。

まとめ

ここまでの検証で確認した結果をまとめると以下のような手順となりました。

pyenv環境の初期設定

  • pyenvをgitクローンします。
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
  • 必要な設定がbash起動毎に行われるように~/.bash_profileに記述します。
$ echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
  • ~/.bashrc内のalias python=python36部分をコメントアウトします。
  • ここまでの設定をすぐに反映する場合はbashを再起動します。
$ exec $SHELL -l

ディレクトリごとの設定

  • 現在のpyenv環境で利用可能なPythonバージョンを確認します。
$ pyenv versions
  • 利用したいPythonバージョンがない場合はインストールします。
$ pyenv install <利用したいバージョン>
  • ディレクトリに移動し、pyenv localで利用したいPythonバージョンを有効化します。
$ cd <dir>
$ pyenv local <利用したいバージョン>

おわりに

今まで環境を構築するごとにコマンドの意味をあまり理解せず手順に沿って機械的に打っていた節がありましたが、今回の検証により理解を深めることができました。

参考