Pipenv をやめて venv を使いだした話

Posted on 2020/10/11 in tech

tl;dr

仮想環境の作成

Python の開発には組み込みの venv で閉じた環境(仮想環境)を作成できる。

環境の自動化

direnv を入れればカレントディレクトに応じて activate/deactivate を自動化できる。
これは .envrc

layout python

を書けばいい。

Python バージョンを指定した仮想環境の作成

任意の Python バージョンを指定したい場合、pyenv を使う。
インストール済なら .envrc

layout python ~/.pyenv/versions/3.X.X/bin/python

のように Python のパスを末尾に書けば、3.X.X のバージョンで仮想環境が作成される。1

依存ライブラリの管理

依存ライブラリのバージョン固定には pip-tools を使う。
これは仮想環境ごとにインストールする。

$ pip install pip-tools

これにより、pip-compile, pip-sync コマンドが利用可能になる。

requirements ファイルを生成するためには、 依存ライブラリを requirements.in といったテンプレートファイルに

pelican
markdown

のように書いておき、

$ pip-compile requirements.in

すれば requirements.txt に依存ライブラリが出力される。

#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile requirements.in
#
blinker==1.4              # via pelican
docutils==0.16            # via pelican
feedgenerator==1.9.1      # via pelican
jinja2==2.11.2            # via pelican
markdown==3.3             # via -r -
markupsafe==1.1.1         # via jinja2
pelican==4.5.0            # via -r -
pygments==2.7.1           # via pelican
python-dateutil==2.8.1    # via pelican
pytz==2020.1              # via feedgenerator, pelican
six==1.15.0               # via feedgenerator, python-dateutil
unidecode==1.1.1          # via pelican

ハッシュチェックモード を利用したければ、--generate-hashes オプションを付与する。

$ pip-compile --generate-hashes requirements.in

出力にハッシュが追加されることがわかる。

blinker==1.4 \
    --hash=sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6 \
    # via pelican
docutils==0.16 \
    --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \
    --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \
    # via pelican
....

当然ながら、生成されたファイルを利用して pip install できる。

$ pip -r install requirements.txt

pip-sync コマンドは環境を prune にしたいときに使う。

$ pip-sync requirements.txt

これによって、requirements.txt に記載のライブラリで足りてないものがあればインストールされ、不要なものがあれば、すべて削除される。


2, 3 年前から Pipenv を使っていた。Python はメインの業務で使っているわけではないので、こんなものかと思っていたが、いまいち馴染まなかった。

npm をむりやり Python に持ち込んだ感じというか、ゴテゴテしてるなというか。

でも「今はこっちが主流なんだよな」と思っていた。virtualenv のスターに比べ、Pipenv のスター数は圧倒的2なわけだから。

だけれどもインストールが遅いとか3 docker イメージ化が簡単にできない4 とか騙し騙しやってる自分のことをいよいよ騙せなくなっていた。

「オフィシャルで推奨されるツール」だと思っていたら違った

そんなこんなでモヤモヤしていたら決定的な記事を見つけてしまった。

Pipenv: promises a lot, delivers very little | Chris Warrick

2018 年の記事ながら、今年(2020 年)にも更新されている。
記事タイトルの直訳が

「Pipenv: 多くのことを約束し、とても僅かなものをもたらした」

となるあたりからも察するになかなか辛辣である。

下記引用部分が、すべてを語っている。

“Pipenv — the officially recommended Python packaging tool from Python.org, free (as in freedom).”

Pipenv’s README used to have a version of the above line in their README for many months: it was added on 2017-08-31 and eventually disappeared on 2018-05-19. For a short while (2018-05-16), it was clarified (managing application dependencies, and PyPA instead of Python.org), and for about 15 minutes, the tagline called Pipenv the world’s worst or something along these lines (this coming from the maintainer).

(意訳)5

“Pipenv - Python.org から公式に推奨される Python パッケージツールで、フリー(そして自由)

Pipenv の README はかつてしばらくのバージョンにおいて、上記の言葉を README に含めていました: それは 2017-08-31 に追加され、最終的に 2018-05-19 で削除されました。僅かな期間(2018-05-16)、(アプリケーションの依存関係の管理や、Python.org に代わって PyPA がそれを行っていることが)明確化され、また約 15 分間のタグライン上で、Pipenv は 世界最悪 もしくはの言葉で呼称されました(これはメンテナ由来のものです)。

メンテナに 世界最悪 って書かれちゃうのってなんやねん。
上記の引用だとわかりにくいけれど、

something along these lines

の部分は 1 単語に 1 リンクがついていて、Pipenv ドキュメントにおける悲劇のコミットログをみることができる。

7e59630

Pipenv — the tool for managing application dependencies from PyPA __, free (as in freedom).

Pipenv - Python.org から公式に推奨される Python パッケージツールで、フリー(そして自由)

6d77e4a

Pipenv — the absolute worst available today for managing your Python application dependencies.

Pipenv - こんにち、Python アプリケーションの依存管理をするために利用できる絶対的最悪なもの

1c956d3

Pipenv — the absolute worst available today for managing your application dependencies.

Pipenv - こんにち、アプリケーションの依存管理をするために利用できる絶対的最悪なもの

(Python という括りが外されている)

e3c72e1

Pipenv — the world's worst Python application dependencies workflow tool™.

Pipenv - 世界最悪の Python アプリケーション依存管理ワークフローツール™

右肩にある TM とは、トレードマークのことである。

fe78628

Pipenv — the world's most opinionated Python application dependencies workflow tool™.

Pipenv - 世界でもっともこだわりのある Python アプリケーション依存管理ワークフローツール

「こだわりのある」(opinionated) にも皮肉が込められているのだろう。
記事中で触れられているのだが、これらのタグラインの変更は Reddit のやりとりに由来するものらしい。

Why is pipenv the recommended packaging tool by the community and PyPA? : Python

Python とパッケージ管理

Pipenv の気持ちはわかる。おそらくだが、Node.js の npm や PHP の composer みたいなパッケージ管理をイメージしたのだろう。

こう書くと敵をつくりそうだが、Python コミュニティは質が高いと感じる事が多い。 質が高い、という意味が何を指すかは人それぞれだろうが、少なくとも追加される機能は厳選され、スクリプト言語の手軽さ・多機能さを保ちつつシンプルであり続ける姿勢を勝手に感じている。 まぁ勘違いかもしれないが、少なくともいつも「いいな」とは思う。
個人的に Django が好きだが、Python という言語仕様以前に、Python 界で共有される思想ゆえの整然とした世界故に生まれたフレームワークだと思っている。

よって、徒に他の言語から同じ思想の仕組みを持ち込もうとしても、うまくいかないだろう。
大衆受けしているものがベストかはわからないし、Python に他言語の文化をほぼそのままの形に持ち込めるかというと、それも違うように思う。

venv: 標準の仮想環境

一度 virtualenv に戻ったけれど、どうやら venv というものが組み込み(stdlib)のライブラリ として Python 3.3 からから利用できるらしい。
Python 3.9 がリリースされたばかり7 だが、どんだけ取り残されてたんだ。。。

venv は virtualenv のサブセットらしい。 言い換えれば少なからず、virtualenv の方が認められたということだろう。違いについては、我らが Stack Overflow が参考になった。

python - What is the difference between venv, pyvenv, pyenv, virtualenv, virtualenvwrapper, pipenv, etc? - Stack Overflow

ベストアンサー の回答者は virtualenv 推しのようだけれど、個人的には venv で十分である。バージョン切り替えなんぞは、必要になったときだけ pyenv 等その他のツールを使えばよい。
venv が virtualenv のサブセット である、ということ一つとっても、Python コミュニティかくありや、と思わずにいられない。それは 1 つのことをうまくやろうとする UNIX 哲学 に通じるものであるし、そうあるべきものだと思う。


記事執筆中に、direnv が仮想環境の作成に virtualenv を利用している、と wiki に書いてあった ので、 そんなことあるんかいな、と思ったら、issue が立っていた

そしてよくよく読んでみると、direnv v2.21.0 以降から venv を優先して使うコードが 2019/08/04 にマージされている
1 年以上 wiki が古い内容のままだったということである。直そうよ…

と文句を言っても仕方ないので、直しておいた。正直英語に自信がないので、変なところあったらそっと直してほしいです。


  1. 事前に pyenv install 3.X.X のように任意の Python バージョンをインストールしておく必要がある。詳しくはREADME を参照されたし。 

  2. 2020/10/08 現在、virtualenv のスター数 3.7k に対し Pipenv のスター数は 21k とある 

  3. pipenv install is very slow · Issue #356 · pypa/pipenv, Lock updating is very slow · Issue #1914 · pypa/pipenv 

  4. Generate requirements.txt from Pipfile.lock · Issue #3493 · pypa/pipenv 

  5. 意訳頑張ったけど自己流の解釈してるので、明らかに間違いな場合コメントいただけるとありがたい 

  6. 商標 - Wikipedia 

  7. Changelog — Python 3.9.0 documentation