pipxのススメ

pypa.github.io

pipxという名前を聞いてまたpythonの新しいパッケージ管理のツールと思うかもしれないけれど、少しだけ用途が違う。これがほしい場合がある。

pipxは例えばpoetryやpipenvとはちょっと用途が違う。

pipxは日常生活のためのCLIコマンドのためのもので、pipenvやpoetryはアプリケーション開発のためのものといえば良いのだろうか?

例えば、python製のコマンドを環境を汚さず1にインストールして利用したいときにpipxは便利。httpieだとか。sphinxだとか。blackだとかflake8だとか2。 裏側では各コマンドごとのvenvを作ってくれてそのvenv内のscriptのsymlinkをいい感じに作成してくれる。

利用例はドキュメントのものを見れば事足りるがちょっとだけメモ。

環境を汚さずコマンドをインストールしたいとき

defaultでは $HOME/.local/bin 以下にコマンドが置かれる。

$ python -m pipx install jqfpy
$ which jqfpy
$HOME/.local/bin/jqfpy

どのような環境が作られているかは list で見れる。

$ python -m pipx list
venvs are in C:\Users\podhmo\.local\pipx\venvs
apps are exposed on your $PATH at C:\Users\podhmo\scoop\apps\python\3.9.5
   package flake8 3.9.2, Python 3.9.5
    - flake8.exe
   package jqfpy 0.6.2, Python 3.9.5
    - jqfpy.exe

あるコマンドの環境に依存するパッケージを追加したいとき

例えば、sphinxなどでpluginを使いたくなることがある。その環境下に余分に依存を追加したい。こういうときにはinjectを使う。

$ python -m pipx inject sphinx sphinx-<plugin>

windowsの場合

ここからはかなり個人的な環境の話になるが、windowsの場合にもちょっとだけ気をつけると便利に使えるようになる。

最近、というか今日家のmacが壊れたのでwindowsのPCを使い始めたのだけれど、パッケージの管理にscoopを使っている。

scoop.sh

これはこれで便利なのだけれど。これでインストールしたpythonといい感じに共有したい。ところで、このscoopはcurrentの部分にPATHが通るように設定してくれる。

$ scoop install python
$ which python
C:/Users/podhmo/scoop/apps/python/current/python.exe

ここでpipxをインストールしたとき --user をつけてインストールしたときにはcurrentではない場所にpipxが置かれる。もちろん、PATHを設定すれば良いことなのだけれど。めんどくさいので省略したい。幸いpipxは python -m pipx でも動くのでこちらを使う。

$ python -m pip install --user pipx
...
  WARNING: The script pipx.exe is installed in 'C:\Users\podhmo\AppData\Roaming\Python\Python39\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

# 無い
$ which pipx
# pythonからは呼べる
$ python -m pipx --version
0.16.3

同様に素直に pipx install でインストールすると $HOME/.local/bin に置かれてしまう。これには PIPX_BIN_DIR を指定してあげると良い(venvの位置も PIPX_HOME で変えれるが今回は気にしない)。

https://pypa.github.io/pipx/installation/#installation-options

The default binary location for pipx-installed apps is ~/.local/bin. This can be overridden with the environment variable PIPX_BIN_DIR.

PowerShellには不慣れだが以下の様な感じで設定できるようだ。

 $pydir = python -c 'import sys; import pathlib; print(pathlib.Path(sys.executable).parent)'
 $ENV:PIPX_BIN_DIR=$pydir

scoopで通っているpathに置かれる様になったので直接呼べる。

$ python -m pipx instal jqfpy
$ which jqfpy
C:/Users/podhmo/scoop/apps/python/current/jqfpy.exe
$ echo '{"foo": 1}' | jqfpy
{
    "foo": 1
}

  1. 環境を汚さないには2つの意味がある。一つはいわゆるpython環境を汚さないということ。もう一つはpyhtonはモジュールの持ち方がフラットなのでnodejsのように全体で同じパッケージの異なるバージョンに依存することができない。ここで環境を共有して同じ依存を含んだコマンドを2つインストールしてしまった場合に両者の依存が干渉してしまうことがある。これを避けるということ。

  2. 真面目なアプリケーション開発でpythonのバージョンと各種devツールのバージョンを揃えたい場合には、それぞれのプロジェクトごとのvenvにインストールするべきかもしれないけれど。

pip-chillのススメ

pypi.org

pip freeze で出力されるすべてをrequirements.txtに書く1のではなく、依存の一番外側のパッケージだけを出力したい事がある。そういうときにはpip-chillが便利。

実行例

例えば、fastapiを参考に以下の様なrequirements.txtを用意してみる。

requirements.txt

uvicorn
fastapi

空のvenvを作ってpip installしてみる

$ python -m venv venv
$ ./venv/bin/pip install -r requirements.txt

freeze

freezeの内容は以下

$ ./venv/bin/pip freeze
asgiref==3.3.4
click==8.0.1
colorama==0.4.4
fastapi==0.65.2
h11==0.12.0
pip-chill==1.0.1
pydantic==1.8.2
starlette==0.14.2
typing-extensions==3.10.0.0
uvicorn==0.14.0

pip-chill

pip-chillを使うと依存の一番外側だけを出力してくれる。

$ ./venv/bin/pip install pip-chill
$ ./venv/bin/pip-chill --no-chill
fastapi==0.65.2
uvicorn==0.14.0

versionも削れる

$ ./venv/bin/pip-chill --no-chll --no-version
fastapi
uvicorn

pip install fastapi[dev] した場合には以下の様に変わる

$ ./venv/bin/pip install fastapi[dev]
$ ./venv/bin/pip-chill --no-chill
asgiref==3.3.4
autoflake==1.4
bcrypt==3.2.0
colorama==0.4.4
cryptography==3.4.7
fastapi==0.65.2
flake8==3.9.2
graphene==2.1.8
passlib==1.7.4
python-dotenv==0.18.0
python-jose==3.3.0
pyyaml==5.4.1
uvicorn==0.13.4
watchgod==0.7
websockets==8.1

  1. あるいはrequirements.lock