旧システムvenvで作成された仮想環境中のプロジェクトをpyenvで動作させる手順

はじめに

少し前にシステムをUbuntu 20.04からUbuntu 22.04へ移行しました。
新システムに移行にあたり、Pythonのバージョンが3.8から3.10へ変化しました。

このとき旧システムのpython仮想環境(venv)で作成されたプロフェクトフォルダをアクティベートしようとすると、新システムのPythonが起動されてしまいます。
ROOT/bin/python3がシステムPythonへのシンボリックリンクになっているからです。(ROOTはプロジェクトのルートパス)
旧システムのvenv仮想環境のpythonバージョンが合っていないと、この仮想環境を使用できません。

ではどうするかというと、pyenvで旧システムのPythonをエミュレートするか、GNOME BoxesUbuntu 20.04環境を作成し、その中でプロフェクトフォルダを動作させるか、になります。

そしてここでは、pyenvを使って旧システムのプロジェクトを動作させることを目指します。

しかし単純にpyenvpython仮想環境(venv)のPythonバージョンに合わせたPythonをインストールするだけでは旧システムのvenv環境が動作してくれません。
結論から先に書くと、ROOT/bin/python3, ROOT/bin/pythonのシンボリックリンクをpyenv由来のシンボリックリンクに置き換える必要があります。

この記事では備忘録を兼ね、ステップバイステップでこの手順を記録します。

環境

$ inxi -Sxxx --filter
System:
  Kernel: 6.5.0-41-generic x86_64 bits: 64 compiler: N/A Desktop: GNOME 42.9
    tk: GTK 3.24.33 wm: gnome-shell dm: GDM3 42.0
    Distro: Ubuntu 22.04.4 LTS (Jammy Jellyfish)

pyenvインストール

pyenv公式
https://github.com/pyenv/pyenv

依存関係のインストール

ビルドに必要なパッケージは事前にインストールしておきます。

Suggested build environment
https://github.com/pyenv/pyenv/wiki#suggested-build-environment

sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl git \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

pyenv本体のインストール

Automatic installer
https://github.com/pyenv/pyenv?tab=readme-ov-file#automatic-installer

curl https://pyenv.run | bash

.profile, .bash_profile, .bashrcへ追加記述

上記それぞれのファイルに以下を記述します。

Set up your shell environment for Pyenv
https://github.com/pyenv/pyenv?tab=readme-ov-file#set-up-your-shell-environment-for-pyenv

記述後はsourceコマンドで強制読み込みをするか、再ログインします。
わたしの場合、sourceコマンドで不具合が出ました。再ログインのほうが(理由はわかりませんが)確実かもしれません。

.profile

# pyenv初期化
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

.bash_profile

# pyenv初期化
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

.bashrc

# pyenvの設定
# pyenvの設定
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

補足

これらのファイルは再インストール時、バックアップファイルから自動的にコピーされるようにしています。
詳しくは以下をご参照ください。

  • システム再インストールを楽にする手順: 専用BashScriptのすすめ
    https://zenn.dev/ykesamaru/articles/1ab1297354d3c2

pyenv動作確認

$ pyenv --version
pyenv 2.4.7

任意バージョンのPython導入

Usage
https://github.com/pyenv/pyenv?tab=readme-ov-file#usage

インストール可能なバージョンリストの取得

$ pyenv install --list > python_list.txt
Available versions:
  2.1.3
  2.2.3
  2.3.7
(中略)
  stackless-3.4-dev
  stackless-3.4.2
  stackless-3.4.7
  stackless-3.5.4
  stackless-3.7.5

824種類の形式・バージョンがありました。

インストールするべきバージョンの確認

venvですでに仮想環境が作成されている状態なのですが、pyenvでこれに適合したバージョンのPythonをインストールするときは、マイクロバージョンまで一致したバージョンである必要があります。

例えば3.8系の最終バージョンは3.8.19ですが、旧システムのvenvで作成した仮想環境は3.8.10です。
もしpyenv3.8.19をインストールしてもvenv仮想環境と適合しないためプロジェクトを動作させることはできません。
旧システムのvenv仮想環境のマイクロバージョンを調べるには、以下のファイルをロードします。

$ cat ~/bin/FACE01/pyenv.cfg
home = /usr/bin
include-system-site-packages = false
version = 3.8.10

これで3.8.10であることが確認できます。

バージョンを指定してpyenv Pythonをインストール

マイクロバージョンが3.8.10と判明したのでこれをインストールします。

$ pyenv install 3.8.10
# コケたのでコンパイラフラグを指定してビルド
$ CFLAGS="-O2" pyenv install 3.8.10
# それでもコケたのでビルドフラグも追加
$ CFLAGS="-O2" CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" pyenv install 3.8.10
Downloading Python-3.8.10.tar.xz...
-> https://www.python.org/ftp/python/3.8.10/Python-3.8.10.tar.xz
Installing Python-3.8.10...
patching file Misc/NEWS.d/next/Build/2021-10-11-16-27-38.bpo-45405.iSfdW5.rst
patching file configure
patching file configure.ac
Installed Python-3.8.10 to /home/user/.pyenv/versions/3.8.10

上記の例ではコンパイラフラグとビルドフラグを設定してようやくビルドできました。
これは完全に環境に依存します。この作業は何度も行ったことがありますが、通常pyenv install *version*で失敗したことはありませんでした。
コケたときのログ(`/tmp/ディレクトリ以下)をみて判断してください。

インストール確認

python 3.8.10をローカルに指定
$ pyenv local 3.8.10

# バージョンを確認
$ python --version
Python 3.8.10

3.8.10がインストールされました。

仮想環境アクティベート

仮想環境はすでにvenvで作成済みです。
ですので仮想環境のルートディレクトリに移動して、アクティベートします。
このとき、pyenvlocalで指定して起動します。

$ cd ~/bin/FACE01
$ pyenv local 3.8.10
$ source bin/activate

先述の通り、このようにするとシステムPython(ver.3.10系)が立ち上がってしまいます。
これを回避するため、以下に続く作業を行います。

仮想環境中のpython3リンクを変更

ROOT/bin/ディレクトリには、システムPythonへのリンクが存在します。

. bin/activateを行うと、このリンクをたどってシステムPythonが起動してしまうため、これらのシンボリックリンクを変更します。

user@user:~/bin/FACE01/bin$ cd /home/user/bin/FACE01/bin  # プロジェクトのルートパス
# 一応バックアップをとっておく
user@user:~/bin/FACE01/bin$ mkdir python3.10系
user@user:~/bin/FACE01/bin$ mv python3 python3.10系/
user@user:~/bin/FACE01/bin$ mv python python3.10系/
# pyenvからシンボリックリンクを貼る
user@user:~/bin/FACE01/bin$ ln -s /home/user/.pyenv/versions/3.8.10/bin/python3 python3
user@user:~/bin/FACE01/bin$ ln -s /home/user/.pyenv/versions/3.8.10/bin/python python

仮想環境をアクティベートしてPythonのバージョンを確認します。

user@user:~/bin/FACE01$ . bin/activate
(FACE01) user@user:~/bin/FACE01$ python
Python 3.8.10 (default, Jul 12 2024, 08:29:07) 
[GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

これで旧システムのvenvで作成された仮想環境を再び使用することができます。

参考文献