[python]pyenvがバージョンを切り替える仕組みを理解する

カテゴリ: python | タグ:

pythonではpyenvというツールを使うことで、1台のPCに複数バージョンのpython環境を共存させることができます。

pyenvは非常に便利なツールなのですが、仕組みがわかっていないと思った通りにバージョン切り替えを行えなかったりトラブルを生んでしまうことがあります。そこで、今回はpyenvの仕組みを確認してみました。

環境の確認

作業を始める前に、現在の環境を確認しておきます。
OSはAmazonLinuxになっていますが、実際はvagrant上でmvbcoding/awslinuxのboxを実行しています。

$ python --version
Python 2.7.12

$ which python
/usr/bin/python

$ more /etc/system-release
Amazon Linux AMI release 2017.03

pyenvのインストール

まずは、pyenvをインストールします。pyenvはgitからcloneするだけでインストールできます。

sudo yum install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel -y

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

pyenv自体がインストールできたか確認をかねて、pyenvのバージョンを確認します。本来ならここで~/.pyenv/binにPATHを通すところですが、今回は仕組みを把握するためにあえてPATHの設定を行わずに作業を進めます。

$ ~/.pyenv/bin/pyenv --version
pyenv 1.2.4

pyenvをオプションなしで実行すると、pyenvのヘルプが表示されます。

$ ~/.pyenv/bin/pyenv
pyenv 1.2.4
Usage: pyenv <command> [<args>]

Some useful pyenv commands are:
   commands    List all available pyenv commands
   local       Set or show the local application-specific Python version
   global      Set or show the global Python version
   shell       Set or show the shell-specific Python version
   install     Install a Python version using python-build
   uninstall   Uninstall a specific Python version
   rehash      Rehash pyenv shims (run this after installing executables)
   version     Show the current Python version and its origin
   versions    List all Python versions available to pyenv
   which       Display the full path to an executable
   whence      List all Python versions that contain the given executable

See `pyenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/pyenv/pyenv#readme

  pyenv install -lでインストール可能なpythonのバージョン一覧を確認します。背選択肢は非常に多くあり、python2系、3系の選択だけでなくanacondaなどもインストールすることができることが確認できます。

$ ~/.pyenv/bin/pyenv install -l

Available versions:
  2.1.3
  2.2.3
  ...
  2.7.14
  2.7.15
  3.0.1
  3.1
  3.1.1
  ...
  3.6.4
  3.6.5
  3.7.0b3
  3.7-dev
  3.8-dev
  activepython-2.7.14
  activepython-3.5.4
  activepython-3.6.0
  anaconda-1.4.0
  anaconda-1.5.0
  ...
  stackless-3.4.2
  stackless-3.4.7
  stackless-3.5.4

他のバージョンのpythonをインストールしてみる

pyenv installコマンドで複数のバージョンのpythonをインストールしてみます。
今回は、動作確認を兼ねてPython3系と2系の最新版だった3.6.5と2.7.15をインストールしてみました。

$ ~/.pyenv/bin/pyenv install 3.6.5
Downloading Python-3.6.5.tar.xz...
-> https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz
Installing Python-3.6.5...
Installed Python-3.6.5 to /home/vagrant/.pyenv/versions/3.6.5

$ /home/vagrant/.pyenv/bin/pyenv install 2.7.15
Downloading Python-2.7.15.tar.xz...
-> https://www.python.org/ftp/python/2.7.15/Python-2.7.15.tar.xz
Installing Python-2.7.15...
Installed Python-2.7.15 to /home/vagrant/.pyenv/versions/2.7.15

インストールしたpythonの環境は.pyenv/versionsに展開されています。lsコマンドでインストールできたかを確認できます。

$ ls ~/.pyenv/versions/
2.7.15/ 3.6.5/

インストールしたバージョンにpythonを切り替えてみる

pyenv installを実行しただけでは、pythonのバージョンは切り替わりません

$ which python
/usr/bin/python

$ python --version
Python 2.7.12

pyenvが管理しているバージョンはversionsで確認できます。「*」がついた行が現在の環境です。

$ ~/.pyenv/bin/pyenv versions
* system (set by /home/vagrant/.pyenv/version)
  3.6.5
  2.7.15

pyenv globalコマンドで、バージョンを切り替えてみます。
オプションにglobalとあるので、システム全体の設定が切り替わりそうに見えますが、実際は実行しているユーザの環境のみに影響を与えます。

$ ~/.pyenv/bin/pyenv global 3.6.5

$ ~/.pyenv/bin/pyenv versions
  system (set by /home/vagrant/.pyenv/version)
* 3.6.5
  2.7.15

これによってpythonのバージョンが変わるかと思ったら、まだ変わりません。

$ which python
/usr/bin/python

$ python --version
Python 2.7.12

ここで初めてパスを通します。

echo 'export PYENV_ROOT="$HOME/.pyenv"
echo 'export PATH="$PYENV_ROOT/bin:$PATH"

パスを通したことによって、pyenvコマンドはパス指定なしで実行できるようになりました

$ which pyenv
~/.pyenv/bin/pyenv

$ pyenv --version
pyenv 1.2.4

ですが、pythonのバージョンはまだ変わっていません

$ which python
/usr/bin/python

$ python --version
Python 2.7.12

次に、下記のコマンドを実行してみます。

$ eval "$(pyenv init -)"

するとpythonのバージョンが切り替わりました。

$ python --version
Python 3.6.5

実行されているpythonコマンドのパスもpyenv initによって変更されています。

[vagrant@localhost ~]$ which python
~/.pyenv/shims/python

以上の実験で、pyenv initコマンドによってpythonの実行パスが差し替えられることがわかりました。

仕組みとしてはeval "$(pyenv init -)"で環境変数PATHに.pyenv/shimsを追加し、pyenv globalpyenv localで該当バージョンのpythonを.pyenv/shimsにコピーしているようです。

pyenv initが行なっていることを確認する

pyenv initが内部で何を行なっているかは、$(pyenv init -)の結果をechoすることで確認できます。

$ echo "$(pyenv init -)"
export PATH="/home/vagrant/.pyenv/shims:${PATH}"
export PYENV_SHELL=bash
source '/home/vagrant/.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 localコマンドでpythonのバージョンを2.7.15に切り替えてみます。

$ pyenv local 2.7.15

pyenv versionsコマンドでバージョンが切り替わったのを確認します。

$ pyenv versions
  system
* 2.7.15 (set by /home/vagrant/.pyenv/shims/.python-version)
  3.6.5

再度バージョンを確認すると2.7.15に切り替わったことがわかります。pythonの実行パスは~/.pyenv/shims/のままです。

$ python --version
Python 2.7.15

$ which python
~/.pyenv/shims/python

簡単にpyenvを使えるようにしておく

最後に、次回以降もpyenvを簡単に使えるよう、自動で環境変数をセットするように.bash_profileを変更しておきます。.bash_profileの内容はLinuxログインするたびに実行されるので、毎回export, evalコマンドを実行しなくてもよくなります。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
こちらもおススメ

コメントを残す

メールアドレスが公開されることはありません。