Raspberry Pi 5のPython環境
はじめに
Raspberry Pi 5で、Python環境の構築に手間取った。
基本従来のRaspberry Pi OSでは特に気にすることなくシステムのPythonにライブラリをインストールして使用していたので、表面上は問題になっていなかった。また、Ubuntuではすでにバージョン23以上のpipを使用しているが、pyenvでシステムのPythonと切り離していたので問題に気がつかなかった。しかし、Raspberry Pi OSがBookwormに移行し、PEP668がデフォルトで有効になったことから問題が発覚した。
さらに困ったことに、Raspberry Pi OSにインストールされているPythonライブラリはpip installでインストールできるものとバージョンが異なる。システムと別のPython環境を単純に作るだけではうまく動作しない問題が生じた。したがって、Raspberry Pi OSのPython開発環境はシステムのライブラリを引き続き使えるような環境でなければならないという事になる。
ところで、PEP668とは…
Raspberry Pi OS Bookwormでは、PEP668がデフォルトで有効になっていることは前述した。
このPEP668の概要をBardにまとめてもらった。
PEP668は、Pythonのモジュールインポートを高速化するための提案です。2022年7月20日に正式にリリースされました。
PEP668では、Pythonのモジュールインポート時に、モジュールのソースコードを事前に読み込んでキャッシュすることで、インポートの時間を短縮します。これにより、モジュールの読み込みにかかる時間を大幅に短縮することができます。
PEP668の具体的な効果は、以下のとおりです。
- モジュールの読み込みにかかる時間を平均で約30%短縮します。
- モジュールの読み込みにかかる時間を最大で約90%短縮します。
PEP668は、Pythonのモジュールインポートのパフォーマンスを大幅に向上させるため、Pythonを使用する場合は、有効にしておくとよいでしょう。なお、PEP668は、強制力はありません。ユーザーの判断で、PEP668の推奨に従うか否かを決めることができます。
PEP668の具体的な内容は、以下のとおりです。
- モジュールインポート時に、モジュールのソースコードを事前に読み込んでキャッシュする。
- キャッシュは、モジュールのパス名とバージョン番号をキーとして保存する。
- キャッシュは、モジュールが最初にインポートされたときに作成される。
- キャッシュは、キャッシュの容量が不足した場合や、モジュールのソースコードが変更された場合に更新される。
PEP668の適用方法は、以下のとおりです。
- Python 3.11以降では、デフォルトでPEP668が適用されます。
- Python 3.10以前では、以下の方法でPEP668を適用します。
- importlib.util.cache_module()関数を使用して、モジュールをキャッシュする。
- importlib.util.find_spec()関数を使用して、キャッシュされたモジュールを取得する。
PEP668の注意点は、以下のとおりです。
- ユーザーが自由にライブラリをインポートすると、不要なモジュールがキャッシュに登録され、パフォーマンスの低下や、セキュリティ上の脆弱性の原因になる可能性がある。
- システムのPythonにユーザーがライブラリをpipでinstallすることは推奨されていない。
PEP668は、Pythonのモジュールインポートのパフォーマンスを向上させるための重要な提案です。Pythonを使用する場合は、PEP668の概要を理解し、適切に適用することで、パフォーマンスの向上を図ることができます。
以上のように、恩恵も多いが、pip installができなくなる点は不便なので、開発用とシステム用に分ければよい。そこで、システムのPython とユーザーが開発に使用するPython を分離する仮想環境について調べた。Ubuntuでは既に使っているpyenvであるが、virtualenvも使う必要がありそうだ。さらに、venvもある。
ところで、具体的にsystemのPythonに何かをインストールしようとすると次のような警告が出る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
01:52 rpi@raspberrypi400-alpha:~/Documents $python -m pip install virtualenv error: externally-managed-environment × This environment is externally managed ╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install. If you wish to install a non-Debian-packaged Python package, create a virtual environment using python3 -m venv path/to/venv. Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make sure you have python3-full installed. For more information visit http://rptl.io/venv note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages. hint: See PEP 668 for the detailed specification. |
Pythonのバージョン管理と仮想環境
具体的にpyenvのインストールは以下で、
1 |
git clone https://github.com/pyenv/pyenv.git ~/.pyenv |
エラー出た。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
02:54 rpi@raspberrypi400-alpha:~/Documents $pyenv install 3.12.2 Downloading Python-3.12.2.tar.xz... -> https://www.python.org/ftp/python/3.12.2/Python-3.12.2.tar.xz Installing Python-3.12.2... Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/rpi/.pyenv/versions/3.12.2/lib/python3.12/bz2.py", line 17, in <module> from _bz2 import BZ2Compressor, BZ2Decompressor ModuleNotFoundError: No module named '_bz2' WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib? Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/rpi/.pyenv/versions/3.12.2/lib/python3.12/curses/__init__.py", line 13, in <module> from _curses import * ModuleNotFoundError: No module named '_curses' WARNING: The Python curses extension was not compiled. Missing the ncurses lib? Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/rpi/.pyenv/versions/3.12.2/lib/python3.12/ctypes/__init__.py", line 8, in <module> from _ctypes import Union, Structure, Array ModuleNotFoundError: No module named '_ctypes' WARNING: The Python ctypes extension was not compiled. Missing the libffi lib? Traceback (most recent call last): File "<string>", line 1, in <module> ModuleNotFoundError: No module named 'readline' WARNING: The Python readline extension was not compiled. Missing the GNU readline lib? Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/rpi/.pyenv/versions/3.12.2/lib/python3.12/ssl.py", line 100, in <module> import _ssl # if we can't import it, let the error propagate ^^^^^^^^^^^ ModuleNotFoundError: No module named '_ssl' ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib? Please consult to the Wiki page to fix the problem. https://github.com/pyenv/pyenv/wiki/Common-build-problems BUILD FAILED (Debian 12 using python-build 2.3.36-21-g7e550e31) Inspect or clean up the working tree at /tmp/python-build.20240330025454.23787 Results logged to /tmp/python-build.20240330025454.23787.log Last 10 log lines: esac; \ LD_LIBRARY_PATH=/tmp/python-build.20240330025454.23787/Python-3.12.2 ./python -E -m ensurepip \ $ensurepip --root=/ ; \ fi Looking in links: /tmp/tmpd1exz6qv Processing /tmp/tmpd1exz6qv/pip-24.0-py3-none-any.whl Installing collected packages: pip WARNING: The scripts pip3 and pip3.12 are installed in '/home/rpi/.pyenv/versions/3.12.2/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed pip-24.0 |
いろいろ足りていなかった模様。以前は次のライブラリをインストールしてた。
1 2 3 |
03:45 rpi@raspberrypi400-alpha:~ $sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm xz-utils tk-dev libffi-dev liblzma-dev |
virtualenvをインストール。
1 2 3 4 5 6 7 8 9 |
03:56 rpi@raspberrypi400-alpha:~/Documents $git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv Cloning into '/home/rpi/.pyenv/plugins/pyenv-virtualenv'... remote: Enumerating objects: 2266, done. remote: Counting objects: 100% (195/195), done. remote: Compressing objects: 100% (114/114), done. remote: Total 2266 (delta 107), reused 142 (delta 74), pack-reused 2071 Receiving objects: 100% (2266/2266), 653.14 KiB | 1.57 MiB/s, done. Resolving deltas: 100% (1527/1527), done. |
任意のPythonをインストールできた。
1 2 3 4 5 6 |
03:47 rpi@raspberrypi400-alpha:~ $pyenv install 3.12.1 Downloading Python-3.12.1.tar.xz… -> https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tar.xz Installing Python-3.12.1… Installed Python-3.12.1 to /home/rpi/.pyenv/versions/3.12.1 |
--system-site-packages オプションの適用
システムのライブラリを引き続き利用しつつ、仮想環境を作る必要がある。見出しに記載しているオプションで目的を達成できる。
具体的には、
1 2 3 4 5 6 |
04:00 rpi@raspberrypi400-alpha:~ $pyenv virtualenv system virtualenv3.11.2-system-packages --system-site-packages Looking in links: /tmp/tmpma2k66rc Requirement already satisfied: setuptools in /home/rpi/.pyenv/versions/virtualenv3.11.2-system-packages/lib/python3.11/site-packages (66.1.1) Requirement already satisfied: pip in /home/rpi/.pyenv/versions/virtualenv3.11.2-system-packages/lib/python3.11/site-packages (23.0.1) |
で、Documents以下を仮想環境へ
1 2 3 4 5 6 |
04:02 rpi@raspberrypi400-alpha:~/Documents $pyenv versions system * 3.12.1 (set by /home/rpi/Documents/.python-version) virtualenv3.11.2-system-packages |
1 2 3 4 5 6 7 8 |
04:02 rpi@raspberrypi400-alpha:~/Documents $pyenv local virtualenv3.11.2-system-packages 04:03 rpi@raspberrypi400-alpha:~/Documents $pyenv versions system 3.12.1 * virtualenv3.11.2-system-packages (set by /home/rpi/Documents/.python-version) |
.bashrcの関連記述。これでactivate、deactivateせずに利用できる。
1 2 3 4 5 6 |
export PYENV_ROOT="$HOME/.pyenv" command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init --path)" eval "$(pyenv virtualenv-init -)" export VIRTUAL_ENV_DISABLE_PROMPT=1 |
まとめ
これで、Raspberry Piに必要なライブラリを利用できる仮想環境を構築できた。なお、Raspberry Pi 5以前、この場合、Raspberry Pi 400の場合、普通にgpio関連のライブラリをpipでインストールしても問題ないかもしれない。Raspberry Pi 5BはI/O周りが大きく変更されているからだ。あるいは、このブログを書いた時点で5Bができないだけで、そのうち対応される可能性も高い。
つまり、本内容は当面の間の暫定的な対応かもしれない。仮想環境もディスコン予定の内容で、いずれvenvに移行する必要もあるしね…