プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

WSL2 に pyenv + venv 環境を作ってみた

WSL2 の Ubuntu にデフォルトで入っているバージョン以外の Python を試したくなったので、複数バージョンを使えるようにする方法を調べてみました。

どうも、 Python では環境を管理するためにいろんな方法があるようで、このあたりの記事に表の形でよくまとまっていました。

ちなみに、 pyenv および venv についての説明はこちらの記事がわかりやすかったです。

これらを読んでみたところ、 Python 自体のバージョンを切り替えるには、 pyenv を使うのがよさそうです。pyenv を使わない場合は、 OS 上に複数バージョンをインストールして、 alternative とかで自分で切り替える必要があるようです。

Ubuntu 22.04にPython3.xを複数インストールして切り替える方法(PPA・apt) - Qiita

で、 Python 自体は pyenv で切り替えることにしましたが、 Python だと pip とかでパッケージをいろいろとインストールするかと思います。 pyenv が入っている時に、 pip がどう管理されるかにもよるんですが、まあ、パッケージも管理しておいた方が無難そうですよね。こちらの管理には venv を使うことにしました。

ということで、以下では、手元の Ubuntu (WSL) で pyenv + venv 環境を構築した際のメモをまとめておきます。

ちなみに作業前の環境は

  • Ubuntu 22.02.1, (WLS)
  • Python 3.10.6

でした。

pyenv のインストール

ググると pyenv のインストール方法はたくさん見つかります。今回は下記を参考にインストールしてみました。

まず、 Github から clone します。

mor@DESKTOP-DE7IL4F:~$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

.bashrc を設定します。

mor@DESKTOP-DE7IL4F:~$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
mor@DESKTOP-DE7IL4F:~$ echo 'command -v pyenv > /dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
mor@DESKTOP-DE7IL4F:~$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc

.profile もあるけど、こちらにはなにも追記しませんでした。で、 .bashrc を再読み込み

mor@DESKTOP-DE7IL4F:~$ source ~/.bashrc

実行してみます。

mor@DESKTOP-DE7IL4F:~$ pyenv -v
pyenv 2.3.18-9-ge0084304

大丈夫そうですね。

実際に python をインストールする前に、ビルド環境を設定しておきます。必要なパッケージは下記に記載されていました。

Home · pyenv/pyenv Wiki · GitHub

mor@DESKTOP-DE7IL4F:~$ sudo apt update
mor@DESKTOP-DE7IL4F:~$ 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
(中略)
Failed to retrieve available kernel versions.

Failed to check for processor microcode upgrades.

No services need to be restarted.

No containers need to be restarted.

No user sessions are running outdated binaries.

No VM guests are running outdated hypervisor (qemu) binaries on this host.
mor@DESKTOP-DE7IL4F:~$

これで pyenv で python をインストールする準備ができました。では、早速やってみましょう。まずは、インストール可能なバージョンを確認します。

mor@DESKTOP-DE7IL4F:~$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
(中略)
  3.10.12
  3.11.0
  3.11-dev
  3.11.1
  3.11.2
  3.11.3
  3.11.4
  3.12.0b2
(中略)
  stackless-3.5.4
  stackless-3.7.5
mor@DESKTOP-DE7IL4F:~$

のようにでてきます。今回は 3.11系 の最新版をインストールします。

mor@DESKTOP-DE7IL4F:~$ pyenv install 3.11.4
Downloading Python-3.11.4.tar.xz...
-> https://www.python.org/ftp/python/3.11.4/Python-3.11.4.tar.xz
Installing Python-3.11.4...
Installed Python-3.11.4 to /home/mor/.pyenv/versions/3.11.4
mor@DESKTOP-DE7IL4F:~$

さきほどビルド環境を apt で入れてたので、うすうすは気づいていたのですが、 pyenv は、インストール時に python をソースコードとして取得して、ローカルでビルドを行うようです。なので、 install 時には若干時間がかかるときがあります。

無事にインストールができたら、インストール済みバージョンを確認します。

mor@DESKTOP-DE7IL4F:~$ pyenv versions
* system (set by /home/mor/.pyenv/version)
  3.11.4
mor@DESKTOP-DE7IL4F:~$

システムデフォルト(今回の環境だと 3.10.6)と pyenv でインストールした 3.11.4 が表示されてます。

現在の python のバージョンを表示すると

mor@DESKTOP-DE7IL4F:~$ pyenv version
system (set by /home/mor/.pyenv/version)
mor@DESKTOP-DE7IL4F:~$

と、システムデフォルトになっています。

では、プロジェクト単位で python のバージョンを切り替えたいと思います。

ある特定のディレクトリに移動して、利用する python のバージョンを変更します。

mor@DESKTOP-DE7IL4F:~/work/tmp$ pyenv local 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp$ pyenv version
3.11.4 (set by /home/mor/work/tmp/.python-version)
mor@DESKTOP-DE7IL4F:~/work/tmp$ python --version
Python 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp$

ちゃんと変わってますね。ちなみに、上記の状態で python3 を呼び出したら 3.10.6 を示していたのですが、再起動すれば問題なく指定バージョンを指すようになりました。

あと、 3.11.4 の Python の実体はどこにあるのか見てみると、

mor@DESKTOP-DE7IL4F:~/work/tmp$ python3 --version
Python 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp$ which python3
/home/mor/.pyenv/shims/python3
mor@DESKTOP-DE7IL4F:~/work/tmp$

~/.pyenv 以下にありました。

pip の振る舞いについて

pyenv をインストール後、 pip3 でインストールしたものを表示させてみます。まずは、 system を利用するフォルダの場合は、

mor@DESKTOP-DE7IL4F:~$ pyenv version
system (set by /home/mor/.pyenv/version)
mor@DESKTOP-DE7IL4F:~$ pip3 list -v
Package                Version         Location                                      Installer
---------------------- --------------- --------------------------------------------- ---------
attrs                  21.2.0          /usr/lib/python3/dist-packages
Automat                20.2.0          /usr/lib/python3/dist-packages
(後略)

がっつり、 /usr/lib/ 以下に入ってますね。前々から Python で遊んでるときに特に気にせずに pip でパッケージとか入れてましたからね。

次は、 pyenv で利用する Python のバージョンを切り替えて表示させてみます。

mor@DESKTOP-DE7IL4F:~/work/tmp$ python3 --version
Python 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp$ pip3 -v list
Package    Version Location                                                      Installer
---------- ------- ------------------------------------------------------------- ---------
pip        23.1.2  /home/mor/.pyenv/versions/3.11.4/lib/python3.11/site-packages pip
setuptools 65.5.0  /home/mor/.pyenv/versions/3.11.4/lib/python3.11/site-packages pip
mor@DESKTOP-DE7IL4F:~/work/tmp$

となっていました。

ということは、 pyenv で Python のバージョンを切り替えると、 .pyenv/versions/ の下にインストールされるっぽいですね。 そうすると、同じ python のバージョンを使う複数のプロジェクトが存在すると、それぞれでインストールしたパッケージが混在することになりそうですね。

せっかくなので、試してみます。上記の tmp のほかに tmp2 というディレクトリを作成し、こちらも 3.11.4 を使うようにします。

mor@DESKTOP-DE7IL4F:~/work/tmp2$ pyenv local 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp2$ python3 --version
Python 3.11.4
mor@DESKTOP-DE7IL4F:~/work/tmp2$ 

work/tmp ディレクトリで pip でパッケージをインストールしてみます。

mor@DESKTOP-DE7IL4F:~/work/tmp$ pip3 install xlrd
Collecting xlrd
  Using cached xlrd-2.0.1-py2.py3-none-any.whl (96 kB)
Installing collected packages: xlrd
Successfully installed xlrd-2.0.1
mor@DESKTOP-DE7IL4F:~/work/tmp$ pip3 list -v
Package    Version Location                                                      Installer
---------- ------- ------------------------------------------------------------- ---------
pip        23.1.2  /home/mor/.pyenv/versions/3.11.4/lib/python3.11/site-packages pip
setuptools 65.5.0  /home/mor/.pyenv/versions/3.11.4/lib/python3.11/site-packages pip
xlrd       2.0.1   /home/mor/.pyenv/versions/3.11.4/lib/python3.11/site-packages pip
mor@DESKTOP-DE7IL4F:~/work/tmp$ 

先ほどの推測通り .pyenv/versions/ の下に入ってますね。 で、これを work/tmp2 に移ってから見れるか確認します。

mor@DESKTOP-DE7IL4F:~/work/tmp$ cd ../tmp2/
mor@DESKTOP-DE7IL4F:~/work/tmp2$ pip3 list
Package    Version
---------- -------
pip        23.1.2
setuptools 65.5.0
xlrd       2.0.1
mor@DESKTOP-DE7IL4F:~/work/tmp2$

見えてますね。

ということで、やはり pyenv だけだと、複数のプロジェクトで使ったパッケージが混ざってしまいますね。

venv 環境の構築

ということで、仮想環境を構築するために venv を使ってみたいと思います。 venv は python 公式なので、なにもせずともそのまま使えます。下記などを参考に試してみました。

pyenvとvenvで仮想環境を構築する - Qiita

まずは仮想環境を作ります。

mor@DESKTOP-DE7IL4F:~/work/tmp$ python3 -m venv test_virtual

仮想環境用のフォルダが作られてました。

mor@DESKTOP-DE7IL4F:~/work/tmp$ ls -laF
合計 16
drwxr-xr-x 3 mor mor 4096  69 21:56 ./
drwxr-xr-x 9 mor mor 4096  69 21:49 ../
-rw-r--r-- 1 mor mor    7  69 21:49 .python-version
drwxr-xr-x 5 mor mor 4096  69 21:56 test_virtual/
mor@DESKTOP-DE7IL4F:~/work/tmp$

.python-version は pyenv で Python を切り替えた際に作られるファイルです。venv はディレクトリ単位で仮想環境を管理してるっぽいですね。

仮想環境を有効にしてみます。

mor@DESKTOP-DE7IL4F:~/work/tmp$ . test_virtual/bin/activate
(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$ 

プロンプトの頭に、仮想環境名が表示されてますね。

また、 python3 自体も venv 環境下で管理されているようです。

(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$ which python3
/home/mor/work/tmp/test_virtual/bin/python3
(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$

ちなみに、この状態では pip の保存先は

(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$ pip3 -v list
Package    Version Location                                                     Installer
---------- ------- ------------------------------------------------------------ ---------
pip        23.1.2  /home/mor/work/tmp/test_virtual/lib/python3.11/site-packages pip
setuptools 65.5.0  /home/mor/work/tmp/test_virtual/lib/python3.11/site-packages pip
(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$

となっていて、こちらも仮想環境ごとに用意されていることがわかります。

仮想環境を使うのをやめるなら、

(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$ deactivate
mor@DESKTOP-DE7IL4F:~/work/tmp$

だけでよいようです。これって、調べてみると、

(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$ echo $PATH
/home/mor/work/tmp/test_virtual/bin:/home/mor/.local/bin:/home/mor/bin:/home/mor/.pyenv/shims:/home/mor/.pyenv/bin:
(後略)
/mnt/c/Users/mor/bin:/snap/bin
(test_virtual) mor@DESKTOP-DE7IL4F:~/work/tmp$

のように PATH も変更されています。ということで、『(仮想環境名)/bin』 にパスが通るようになっているのでコマンド入れるだけでいいんですね。