Closed4

Python のクリーンな環境ベストプラクティス

ピン留めされたアイテム
まちゅけんまちゅけん
$ source .venv/bin/activate

これをやり忘れて

$ pip install 何かのパッケージ

これをすると環境が壊れる or 汚れるので面倒です。 何かしらのパッケージ群が ~/.local/ にインストールされてしまいます。 特に実行可能なものが ~/.local/bin/に入ってしまうのはかなり嫌なので避けたいです。

そうするとグローバルな pip っていらなくね?と思うようになってきました。 venv をアクティベートしてから初めて pip が使えるようになるのが環境をクリーンに保つための正しいプロセスではないでしょうか?

なのでこのスクラップではグローバルな pip がないクリーンな Python 環境を検討してみます。 システムは WSL Ubuntu 22.04 をベースに考えます。 macOS は分かりません。

TL;DR

  1. システムのパッケージマネージャーで python3-pip をインストールするのはやめよう
  2. グローバルなツール系 CLI アプリは pipx でインストールしよう
  3. pipxpipx.pyz でインストールしよう
  4. 複数バージョンの Python を入れる時も pip をシステムグローバルにインストールしないように注意しよう。 ソースビルドする時は --with-ensurepip=no で pip のブートストラップは回避できます
まちゅけんまちゅけん

システム Python に pip をインストールしない

Linux 系のシステムには多くの場合 Python インタプリタはデフォルトでインストールされています。

WSL Ubuntu 22.04
$ python3 -V
Python 3.10.12

しかし pip は入っていないことが多いです。 pip コマンドがないというよりも pip というモジュールが Python の中に存在していません。

WSL Ubuntu 22.04
$ pip
bash: pip: command not found
$ python3 -m pip
/usr/bin/python3: No module named pip

この状態であれば、良い状態です。 追加でシステムの pip をインストールしないでおきましょう

APT 系 (Ubuntu など) でも DNF 系 (Fedora) でも大体の場合 python3-pip というパッケージ名で別で配布されていると思います。 環境構築時点で python3-pip をインストールしてしまっているのなら削除してしまいましょう。

WSL Ubuntu 22.04
$ sudo apt remove python3-pip
まちゅけんまちゅけん

pipx

pipx の必要性

Python で開発しているならプロジェクト管理に Poetry やコードのフォーマットに Ruff を使うことがあると思います。 それらのコマンドラインツール類は PyPI で配布されており pipx がベストプラクティスです。

https://pipx.pypa.io/stable/

ツール類は Python コード内で使う訳じゃないので、ユーザーグローバル環境内に 1 つあればいいです。 でもツールをグローバルにインストールすると、そのツールが依存しているパッケージまでもがグローバル環境にインストールされてしまいます。 「ツールはコマンドとして使えるけど、環境は別にしてくれる」それが pipx の役目です。

では pipx をインストールする方法を検討してみましょう。

pip で pipx をインストールする

グローバルな pip は違法です 🚨

システムで pipx をインストールする

Ubuntu 22.04 の場合は APT で pipx をインストールできます。

WSL Ubuntu 22.04
$ apt info pipx
Package: pipx
Version: 1.0.0-1

... しかし pipx のバージョンがかなり古いです 😨
pipx 1.0.0 は現在から 2 年以上前のバージョン [1] です。 私は 1.4.2 でサポートされた PEP 723 に関する機能 [2] を利用したいのですが、Ubuntu 22.04 が提供している pipx では利用不可のようです。

zipapp を pipx で実行する

pipx が配布している zipapp [3] を利用します。 スタンドアロンで pipx を実行できます。

WSL Ubuntu 22.04
$ wget https://github.com/pypa/pipx/releases/latest/download/pipx.pyz
$ python3 pipx.pyz -h
usage: pipx.pyz [-h] [--quiet] [--verbose] [--global] [--version]
                {install,uninject,inject,upgrade,upgrade-all,uninstall,uninstall-all,reinstall,reinstall-all,list,interpreter,run,runpip,ensurepath,environment,completions}
                ...

pipx in pipx

zipapp のスタンドアロンな pipx を使って pipx をインストールします。

WSL Ubuntu 22.04
$ python3 pipx.pyz install pipx
...
$ pipx list
...
   package pipx 1.5.0, installed using Python 3.10.12
    - pipx

これで pipx により pipx をインストール できました。 pipx.pyz 自体は不要なので削除してもいいでしょう。

これのメリットは pipx upgrade-all で pipx 自体も最新版にアップデートできることです。 しかしドキュメントページをよくみると pipx 側としてはこれは not recommended としているようです。

https://github.com/pypa/pipx/blob/f59b30d49231242ee8cf011c5439998ecb60b98c/README.md#L30-L33

pipx uninstall-allpipx reinstall-all などで pipx を破壊してしまう可能性があるからということです。 なので pip で pipx をインストールしましょうと書いてあります。 しかし私はこのデメリットよりグローバルに pip をインストールするデメリットの方が遥かに大きいと思っています。 そのような事象があることに注意しつつ pipx-in-pipx を利用するのがベストではないでしょうか。

もし気になるようであれば pipx-in-pipx はやめておきましょう。 先ほどの pipx.pyz を削除せずに実行ファイルにするのが回避手段です。

WSL Ubuntu 22.04
$ chmod +x pipx.pyz
$ mv pipx.pyz ~/.local/bin/pipx
$ pipx -h
usage: pipx [-h] [--quiet] [--verbose] [--global] [--version]
            {install,uninject,inject,upgrade,upgrade-all,uninstall,uninstall-all,reinstall,reinstall-all,list,interpreter,run,runpip,ensurepath,environment,completions}
            ...

ただしこの場合は pipx 自体のアップデートだけがちょっと面倒になりそうです。

脚注
  1. https://pypi.org/project/pipx/1.0.0/ ↩︎

  2. https://pipx.pypa.io/stable/changelog/#142 ↩︎

  3. https://pipx.pypa.io/stable/installation/#using-pipx-without-installing-via-zipapp ↩︎

まちゅけんまちゅけん

Multiple Python versions

私の場合はライブラリ開発で複数バージョンの Python が必要です。 pip 抜きで複数バージョンの Python を利用する方法を検討します。

Homebrew

https://docs.brew.sh/Homebrew-and-Python

Homebrew を利用するとビルドなしで複数バージョンの Python バイナリが手に入ります。 しかし試したところ brew install python だと pip もグローバルにインストールされてしまいました。 その回避方法は不明なので使えません。

deadsnakes PPA

https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa

deadsnakes PPA は Ubuntu 用の 3rd party なリポジトリです。 メインストリームの Python バージョン以外 (Ubuntu 22.04 なら Python3.10 以外) のバイナリを提供してくれます。 メインストリームと同様に python3.x-pip をインストールしなければ pip はグローバルになりません。

WSL Ubuntu 22.04
$ sudo add-apt-repository -P deadsnakes
$ sudo apt install python3.8 python3.9 python3.11 python3.12

ただしこれは 3rd party によるビルドなので最新バージョンの配布に時差あるかもしれません。 また仕様上の問題ですがメインストリームの Python 3.10 は PPA から配布できないので Python 3.10 のみマイナーが古い場合があります。

Source build

公式からソースをダウンロードして自前でビルドします。 一次情報源なので、リリースされたと同時に最新バージョンを利用することもできます。

https://www.python.org/downloads/source/

依存関係などのインストールやビルド時間などは若干面倒です。

WSL Ubuntu 22.04
$ sudo add-apt-repository -s
$ sudo apt build-dep python3.10
$ wget https://www.python.org/ftp/python/3.yy.zz/Python-3.yy.zz.tgz
$ tar -xf Python-3.yy.zz.tgz
$ cd Python-3.yy.zz
$ ./configure --prefix="$HOME/.local/" --with-ensurepip=no
$ make
$ make altinstall

./configure--with-ensurepip=no を指定することで pip がブートストラップされません 🪄

このスクラップは1ヶ月前にクローズされました