普段はいつもvenvを使って環境構築するんだけど、OSアップグレードしてPythonバージョンが更新されると、venv作成時のPythonバージョンと差異が発生して環境がおかしくなってしまうので、Python自体をインストールするpyenvを試してみた。
venvが OS標準の 使用中のPythonインタプリタを流用して(pip
でインストールしたりする)外部パッケージ等をシステムから分離するのに対して、pyenvはPythonそのものをユーザーディレクトリ以下へインストールするため、ディストリビューションのパッケージで用意されていないバージョンのPythonも簡単に利用できる。また、OSアップグレードに伴うPythonバージョンアップの影響を受けない。その反面セキュリティfixなどはdnf
やapt
などを使ったディストリビューションの管理外なので自分でメンテする必要があり、ストレージ容量もその分必要。
(追記)全体的に「venv or pyenv」って感じで書いてしまったけど、併用するのがセオリーっぽい。最後にまとめを追記。
環境
zaki@ubuntu:~$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.6 LTS"
zaki@ubuntu:~$ python3 --version Python 3.8.10 zaki@ubuntu:~$ which python3 /usr/bin/python3
22.04でも同様
pyenvセットアップ
pyenvのインストール
Linuxの場合は使用するユーザーでスクリプト実行してインストールする。
curl https://pyenv.run | bash
.bashrc更新と再読み込み
cat <<'__EOL__' >> $HOME/.bashrc export PYENV_ROOT="$HOME/.pyenv" command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" __EOL__ . $HOME/.bashrc
これでpyenv
を実行できる。
zaki@ubuntu:~$ pyenv --version pyenv 2.3.17
依存パッケージのインストール
pyenvでPythonをインストールする際に必要なパッケージを入れる。
Ubuntuであれば以下の通り。
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev curl \ libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
pyenvでPythonインストール
pyenvの準備ができたので、pyenvを使ってPythonをインストールする。
インストールできるPythonのリスト
古いのを含めて結構ある。ActivePythonやAnacondaなども選択可能。以下は一例。
zaki@ubuntu:~$ pyenv install -l Available versions: 2.1.3 2.2.3 2.3.7 2.4.0 [...] 2.7.17 2.7.18 3.0.1 3.1.0 [...] 3.11.3 3.12.0a7 3.12-dev [...]
Pythonインストール
リストで確認できた、例えば3.11.3
をインストールするには以下を実行する。
pyenv install 3.11.3
実行ログにどこへインストールされるか確認できる。(覚えておく必要は特にない)
zaki@ubuntu:~$ pyenv install 3.11.3 Downloading Python-3.11.3.tar.xz... -> https://www.python.org/ftp/python/3.11.3/Python-3.11.3.tar.xz Installing Python-3.11.3... Installed Python-3.11.3 to /home/zaki/.pyenv/versions/3.11.3 zaki@ubuntu:~$
インタプリタの切り替え
OS標準のPythonやpyenvでインストールしたPythonなど複数のインタプリタからどれをpython
として使用するかの設定を行う。
zaki@ubuntu:~$ pyenv global 3.11.3 zaki@ubuntu:~$ python --version Python 3.11.3 zaki@ubuntu:~$ which python /home/zaki/.pyenv/shims/python
切替可能なバージョン一覧
zaki@ubuntu:~$ pyenv versions system * 3.11.3 (set by /home/zaki/.pyenv/version)
venvとの容量比較
作ったばかりの状態のvenvと、pyenvで3.11.3をインストールしたばかりのディレクトリの状態。
zaki@ubuntu:~$ du -sh .pyenv/ venv/ 309M .pyenv/ 19M venv/
(おまけ) OSアップグレードした場合
ここまでの検証環境がUbuntu 22.04でなく20.04を使ったのはこれをまとめるため。笑
前述の環境をdo-release-upgrade
で22.04へアップグレードを行い、venvで作った環境とpyenvで作った環境を比較するとこの通り。(それぞれ事前にpip install ansible
でAnsibleをインストールしている)
ubuntu@ubuntu:~$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=22.04 DISTRIB_CODENAME=jammy DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"
pyenvで入れたPython 3.11.3の場合
zaki@ubuntu:~$ python --version Python 3.11.3 zaki@ubuntu:~$ which ansible /home/zaki/.pyenv/shims/ansible zaki@ubuntu:~$ ansible --version ERROR: libffi.so.7: cannot open shared object file: No such file or directory
おや?OSアップグレードで依存ライブラリが無くなったとかかな?
sudo apt-get install libffi7
でインストールして再実行。
zaki@ubuntu:~$ ansible --version ansible [core 2.14.5] config file = None configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/.pyenv/versions/3.11.3/lib/python3.11/site-packages/ansible ansible collection location = /home/zaki/.ansible/collections:/usr/share/ansible/collections executable location = /home/zaki/.pyenv/versions/3.11.3/bin/ansible python version = 3.11.3 (main, Apr 29 2023, 08:25:24) [GCC 9.4.0] (/home/zaki/.pyenv/versions/3.11.3/bin/python3.11) jinja version = 3.1.2 libyaml = True
venvの環境の場合
venv作成時はPython 3.8.10だったが、OSアップグレードでPython 3.10.6に更新されている、という状況。
(python38) zaki@ubuntu:~$ python --version Python 3.10.6 (python38) zaki@ubuntu:~$ which ansible /home/zaki/venv/python38/bin/ansible (python38) zaki@ubuntu:~$ ansible --version Traceback (most recent call last): File "/home/zaki/venv/python38/bin/ansible", line 5, in <module> from ansible.cli.adhoc import main ModuleNotFoundError: No module named 'ansible'
この状態になるとpip freeze
も同様のエラーで使えないので再構築のやり方がわからない。。
(追記) まとめ
venvの場合でもrequirements.txt
をメンテしていればOSアップグレードしても環境の作り直しは簡単なので、細かいPythonバージョンまで要件がなければ使いやすい方を選択すれば良いかな?
Pythonバージョンに指定があるならpyenvを使って環境構築すると良さそう。
(追記) 「OS標準のPythonでvenv作るとアップグレード時に環境が壊れる」がスタート地点だったので「pyenv便利じゃん?」という感じでしたが、記事アップしたらコメント複数いただいて、環境構築としては併用して「pyenvでインストールしたPythonでvenv作る」のがバージョン含めた環境の分離・切換えがやりやすくて良さそうです。
開発環境作るときはpyenvとvenvを併用するかなー #知らんけど
— (っ’ヮ’c) < ★しっぽ (@ryosms) 2023年4月30日
Pythonのバージョンはpyenvで管理して
— nikkie にっきー (@ftnext) 2023年4月30日
開発ごとに必要なライブラリはvenv
というのは私もよくやります〜👍
Pythonのバージョンが同じでも、プロジェクトによってライブラリのバージョンを分けることができます
このあたり他のツールもあるのですが、サクッと使うならこちらが私はオススメです