PEP668エラー回避のヒント:pipxの活用

最近のUbuntuRaspberryPiを使用しているとpipコマンドでライブラリのインストールをするときにPEP668のエラーが出てきます。 以下は最新のRaspberryPi OSであるDebian GNU/Linux 12 (bookworm)pipコマンドを使用してnumpyを インストールしてみた結果になります。

$ pip install numpy
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.

エラーメッセージはaptコマンドを使用したインストールとpipコマンドでインストールがバッティングするのでvenvを使用してねというメッセージになります。最近のPythonのライブラリ関係はライブラリとしての使用はもちろんなのですが、エントリーポイントのような形で単体で動くコマンドのような役割を持ったものも多く存在しています。そのため、pipコマンドでのインストールでは仮想環境であるvenvを使用したほうが環境の混濁にならないのでいいですよ~という警告になります。もちろん、このあたりの回避方法はオプションスイッチの指定であったり、設定ファイルなどを使用すれば回避可能です。

【参考】

blog.jp.square-enix.com

ですが、その他の方法として、pipxという方法もあるようです。先程のpipコマンドを実行時には表示されていませんでしたが、以前は以下の表示がありました。pipxを使用するのが簡単ですよってことのようです。

 If you wish to install a non-Debian packaged Python application,
 it may be easiest to use pipx install xyz, which will manage a
 virtual environment for you. Make sure you have pipx installed.

【参考】

peps.python.org

自分はpipxの存在については初耳でもあったので、ちょっと調べてみました。

pipxとは?

pipxとはそのアプリケーションだけのための仮想環境を自動的に作成してくれるものになります。

github.com

仮想環境をいちいち作成し、実行時に切り替えるというのは手間がかかるので、その場合にはpipxを使用して、コマンド実行時(Pythonライブラリのエントリーポイントからの実行時)に自動で環境を有効化して実行するということなので、作成と切り替えの手間不要になります。

pipxのインストール

pipxのインストールは以下の通りです。最後のpipx ensurepathを実行すると、pipxで導入されたコマンドが格納されるパスが作成されます。

$ sudo apt update
$ sudo apt install pipx
$ pipx ensurepath

実行すると以下の様に表示されます。今回はpiユーザーで実行しているので/home/pi/.local/binが作成されます。

$ pipx ensurepath
Success! Added /home/pi/.local/bin to the PATH environment variable.

Consider adding shell completions for pipx. Run 'pipx completions' for instructions.

You will need to open a new terminal or re-login for the PATH changes to take effect.

Otherwise pipx is ready to go! ✨ 🌟 ✨

これでインストールは完了です。

pipxでライブラリを導入してみる

公式のGitHubにもある通りcowsayで実験を行ってみようと思います。このライブラリをインストールするとcowsayというエントリーポイント(長いので以降コマンドとします)が使用できるようになります。

$ pipx install cowsay
$ pipx install cowsay
  installed package cowsay 6.1, installed using Python 3.11.2
  These apps are now globally available
    - cowsay
done! ✨ 🌟 ✨

環境変数である~/.bashrc内のPATHには追加されているのですが、もしpipxコマンドのインストール後に./bashrcの再読み込みを行っていない場合には、一度以下のように実行しておきましょう。

$ source ~/.bashrc

以降は、cowsayを以下の様に実行できます。

$ cowsay -t hello!
  ______
| hello! |
  ======
      \
       \
         ^__^
         (oo)\_______
         (__)\       )\/\
             ||----w |
             ||        ||

インストールされたコマンドは~/.local/binにインストールされているので以下のようにも実行可能です。

$ .local/bin/cowsay -t hello!
  ______
| hello! |
  ======
      \
       \
         ^__^
         (oo)\_______
         (__)\       )\/\
             ||----w |
             ||        ||

インストールしたコマンド一覧を確認する

pipxコマンドを使用してインストールされたもののリストは以下の様に表示することができます。

$ pipx list
$ pipx list
venvs are in /home/pi/.local/pipx/venvs
apps are exposed on your $PATH at /home/pi/.local/bin
   package cowsay 6.1, installed using Python 3.11.2
    - cowsay

コマンドのアンインストールを行う

インストールされたコマンドのアンインストールを行う場合には、以下の様に実行します。アンインストールするとパスからも、listからも削除されます。

$ pipx uninstall cowsay

実行時にインストールして実行を行う(インストールは行わない)

pipxでは、事前にインストールを行っていなかった場合でも、実行時にインストールして実行し、インストールの痕跡をのこさないということも可能です。

$ pipx run cowsay -t mooo
  ____
| mooo |
  ====
    \
     \
       ^__^
       (oo)\_______
       (__)\       )\/\
           ||----w |
           ||         ||

終わりに

開発する場合にはvenvなどの仮想環境を使用し、コマンドとして使用できるものに関してはpipxを使用することで、最近のLinuxディストリビューションで割と厄介に思えたPEP668のエラーも回避できますし、環境の混乱が少なくなる気がしてきました。

例えば、pypisearchなどのコマンドを使用する場合には以下の様にも動作させることができます。以下の例ではpypiにneofetchがあるかを検索しています。

$ pipx run pypisearch neofetch

今後は積極的に使用したい機能ですね。

/* -----codeの行番号----- */