汚いvenv環境からきれいなrequirements.lockを作りたい

手元の環境がものすごく汚いことがある。例えば以下の様に複数のprojectの依存が混ざってしまった状態。

requirements.txt

# app1 の依存
flask
peewee
wtforms

# app2 の依存
pyramid
mako
sqlalchemy

# (後で使う)
pipdeptree

これをきれいに2つに分けて出力したい。通常は pip freeze でrequirements.lockを作るが手元の環境に入っているパッケージの全てが出力されてしまう。

そうではなく例えば↑の依存を

  • flask-requirements.lock (app1用)
  • pyramid-requirements.lock (app2用)

という形に分けたい。また上のrequierments.txtに載っているpackageだけのバージョンを固定してもそれら(e.g. flaskやpyramid)の再帰的な依存までは固定されないので嬉しくない。

ただしvenvを作り直して再インストールは面倒。

こういう気持ち。

(go mod tidy的なものが欲しい)

pipdeptree

幸いなことにpipdeptreeを使うと上手く行く。

pypi.org

# pip install pipdeptree
$ pipdeptree -h
  -f, --freeze          Print names so as to write freeze files

...
  -p PACKAGES, --packages PACKAGES
                        Comma separated list of select packages to show in the output. If
                        set, --all will be ignored.
  -e PACKAGES, --exclude PACKAGES
                        Comma separated list of select packages to exclude from the output.
                        If set, --all will be ignored.

-p で特定のパッケージのみに対する依存を調べてくれる。-fpip freeze で出力するのと同様の表現で出力できる。便利。

具体例

-p <Packages> の部分にトップレベルの依存を指定する

( ただし -f はインデントされた表現になったり、重複して出力されるのでsedやsortで整形する)

# app1
# flask,jinja2,peewee だけからなる依存を集める
$ pipdeptree -p flask,mako,sqlalchemy -f | sed 's/^ *//g' | sort -u | tee flask-requirements.lock

# app2
# pyramid,mako,sqlalchemy だけからなる依存を集める
$ pipdeptree -p pyramid,mako,sqlalchemy -f | sed 's/^ *//g' | sort -u | tee pyramid-requirements.lock

入力のファイルを分ける

個別にコマンドラインで指定するのが嫌なら以下の様にファイルに依存を書いて上げても良い。

pyramid.txt

pyramid
mako
sqlalchemy

trで変換する

$ pipdeptree -f -p "$(cat ./pyramid.txt | tr '\n' ',')" | tee pyramid-requirements.txt

不完全なfreezeが入力の場合

不完全なfreezeが入力の場合は editable installが存在する場合もある。こういうもの。

$ pip freeze | grep '^\-e'
-e git+git@github.com:podhmo/dictknife@daadc0824407bf7877d9bc755e07d62b0ee0b820#egg=dictknife
-e git+git@github.com:podhmo/handofcats@8bb2ee3d96d110ff73e16e15bf2fb56e4e7d7af3#egg=handofcats
-e git+git@github.com:podhmo/jqfpy@e33bdd91d8d724c1cafeccedee3b9e7f06b21d1e#egg=jqfpy

grep -v でよしなに取り除いたりしてください :bow:

gist

https://gist.github.com/podhmo/c6ec298da028950347013668ec0e46d2