実践投入!pipenv!

概要

ということで、やっていきましょうpipenv

前回の以下の記事ではPipenvのインストールとPython3.7.1環境の作成を行いました。
今回はもうちょっと真面目にPipenvを使ってみます。 www.kimoton.com

何のためのpipenv

一言でいえば、pipenvは、pip と virtualenv を統合するためのツールです。
加えて、requirements.txtではできなかった、最小限の依存関係の宣言と直前にテストした依存関係の組み合わせを区別して管理できます。
公式では「人間のための Python 開発ワークフロー」なんて言っちゃってます。

今までは
pip → pythonのライブラリ管理
virtualenv → 仮想環境の管理

という住み分けだったのですが、環境作ってその中でpip使うのであれば管理を統一しちゃおうということですね。

Pipenvの使い方

Pipenvはbundler、composer、npm、cargo、yarn等、ほかの言語で使用されているパッケージの仕組みをpythonに移植したものです。

Pipenvでは、手動でパッケージのインストールおよびアンインストールを行うのと同じようにPipfileに対してパッケージの追加および削除を行うのに加え、自動でプロジェクト用の仮想環境を作成し管理します。
またPipfileに対応するPipfile.lockを生成し、これを利用しビルドが常に同じ結果になるようにしています。

インストール

pip経由でインストールできます。
--userオプションにより、ユーザーディレクトリ以下にインストールするのが良いでしょう。

$ pip install pipenv --user

pipenvは、pyenvと組み合わせることで、pyenvでインストールしたpythonを使用して仮想環境を作成するといったことが可能になります。 この辺を見て、是非インストールしましょう。

やっておきたい設定諸々

仮想環境の作成ディレクトリの変更

デフォルトでは/home/{ユーザー名}/.local/share/virtualenvs/に保存されます。
venvを愛用していた自分にとっては、プロジェクトディレクトリ以下に保存される方が慣れているので、 .bashrc.zshrcなどに以下を追加します。

export PIPENV_VENV_IN_PROJECT=true 

fish の場合は以下。

set -gx PIPENV_VENV_IN_PROJECT true 

シェルでのコマンド補完

.bashrc.zshrcなどに以下を追加します。

eval "$(pipenv --completion)"

fish の場合は以下。

eval (pipenv --completion)

仮想環境の作成

仮想環境の作成は以下のコマンドで行います。

$ pipenv install --python 3.5.5

このコマンドは Pipfile が無ければ作成します。 既に存在していた場合は、引数で与えたパッケージが追加されるよう自動的に Pipfile を編集します。

pipenv installの挙動

pipenv installコマンドは、Pipfileを更新し、Pipenvの仮想環境を作成する際に使います。
挙動としては、以下のようになります。

  1. Pipfileが存在するか確認し、ない場合は作成します。
  2. .venvが存在するか確認し、ない場合はvirtualenvを使用して仮想環境を作成します(./.venv)。
  3. 指定したpythonのバージョンがシステム内に存在するか確認し、存在しない場合はpyenvを使用してインストールを行うか聞かれます。
  4. 2の結果指定したpythonのバージョンがシステム内に存在した場合は、そのpythonを仮想環境内にインストールします。

この工程を終えた暁には、プロジェクトディレクトリに以下のファイルが作成されているはずです。

  • .venv ディレクトリ(指定したpythonがインストールされたvirtualenv 環境)
  • Pipfile ファイル(Pipenv の設定ファイル、TOML 形式)
  • Pipfile.lock ファイル(Pipenv のロックファイル、JSON 形式)

具体的に見ていきましょう。

指定したpythonのバージョンがシステム内に存在しない場合

pyenvを使用してインストールを行うか聞かれます。

pipenv install --python 3.5.5
Warning: Python 3.5.5 was not found on your system...
Would you like us to install CPython 3.5.5 with pyenv? [Y/n]: Y

Yを入力すると、pyenv環境のインストールとその環境を用いた仮想環境の構築(./.venv)が行われます。

指定したpythonのバージョンがシステム内に存在した場合

システム内のpythonを使用して仮想環境の構築が行われます。

$ pipenv --python 3.5.5
Creating a virtualenv for this project...
Pipfile: /home/kimoton/Pipfile
Using /home/kimoton/.pyenv/versions/3.5.5/bin/python (3.5.5) to create virtualenv...
⠸ Creating virtual environment...Using base prefix '/home/kimoton/.pyenv/versions/3.5.5'
New python executable in /home/kimoton/.venv/bin/python
Installing setuptools, pip, wheel...
done.
Running virtualenv with interpreter /home/kimoton/.pyenv/versions/3.5.5/bin/python
✔ Successfully created virtual environment!
Virtualenv location: /home/kimoton/.venv
Creating a Pipfile for this project...

パッケージの追加

パッケージの追加も同じコマンドで行います。

$ pipenv install <package>

このコマンドは Pipfile が無ければ作成します。
既に存在していた場合は、引数で与えたパッケージが追加されるように Pipfile を編集します。

Pipfileに記載されているパッケージをインストールする際は

$ pipenv install

とします。

開発環境のみで使用するパッケージのインストール
-dを使用することで、引数で与えたパッケージが開発環境でのみ追加されるようにPipfile を編集します。

$ pipenv install -d flake8 mypy

開発環境のパッケージを含めて、Pipfileに記載されているパッケージをインストールする際は

$ pipenv install -d

とします。

仮想環境のactivate

仮想環境のシェルを起動するには、以下のコマンドを使用します。

$ pipenv shell

これを行うと、実行ディレクトリに存在する仮想環境でシェルを起動することができます。

仮想環境を使用したアプリケーションの実行

プロジェクトごとにアプリの起動方法が異なることがほとんどかと思います。 そんな時に便利なのがpipenv runコマンドです。 これを使用すると、仮想環境内で実行するコマンドを以下のようにPipfileに登録しておけば、

[scripts]
start = "python app.py"

定義したコマンドを以下のように呼び出すことができます。

pipenv run start

これは、npmでいうpackage.json のscriptsに該当します。

インストール済みパッケージのアップデート

アップデートの際は、pipenv updateコマンドを使用します。

まず、インストール済みのパッケージのうち、古いパッケージが存在しないか、以下のコマンドで確認します。

$ pipenv update --outdated 
✔ Success!
Package 'jedi' out-of-date: '==0.13.1' installed, '==0.13.2' available.
Package 'Pygments' out-of-date: '==2.3.0' installed, '==2.3.1' available.

今回はipython 内部で使用されているjediPygmentsが古くなっているようです。
これらのパッケージをアップデートするには、

$ pipenv update

とします。 個々のパッケージごとに、

$ pipenv update jedi

とすることもできます。

全てのパッケージが最新版になっていると、

$ pipenv update --outdated
✔ Success!
All packages are up to date!

と表示されます。

仮想環境の削除

$ rm -rf .venv

としてもよいですが、以下のコマンドによりpipenv経由でも仮想環境を削除することができます。

$ pipenv --rm

requirements.txtの出力

$ pipenv lock -r

とすると、requirements.txtを作成することができます。

逆に、Pipfileを作成する場合は、以下のようなコマンドで行います。

$ pipenv install -r path/to/requirements.txt

バージョン管理について

一般的には、 Pipfile と Pipfile.lock の両方をバージョン管理するようにします。
複数バージョンのPythonを対象とする場合は、 Pipfile.lock はバージョン管理に含めないのが良いとされています。

Gitを使用している場合、以下のようにPipfile、Pipfile.lock、.gitignoreをプロジェクトの開始時にcommitしてしまうのが良いでしょう。

$ curl -o .gitignore https://www.gitignore.io/api/python,virtualenv
$ git init
$ git add Pipfile Pipfile.lock .gitignore
$ git commit -m "Initial Commit"

依存関係の可視化

pipenv graph

を使用すれば、インストール済みのモジュールがどういう依存関係になっているか、わかりやすいグラフを表示してくれます。

こんな感じ。
f:id:kimoppy126:20181219083345p:plain

どのパッケージにどのモジュールが含まれているのか一目でわかります。

--reverseを付ければ、逆に各モジュールがどのパッケージで使用されているかを確認することができます。

ソースコードの参照

$ pipenv open {参照したいモジュール名}

を使用すれば、インストール済みのパッケージに含まれるソースコードを見ることができます。 例えばscrapyのソースコードを観たい際は以下のように

$ pipenv open scrapy

GitHubまで見に行く必要がありません。

ライブラリとアプリケーション

ライブラリとアプリケーションはよく混同されがちなので、ここで改めて整理します。
なぜならpipenvではこれらを明確に分けて考えているからです。

ライブラリ

  • アプリケーションや他ライブラリで使用される、再利用可能な機能を提供する。
  • 抽象的な依存関係を定義する。
  • 依存パッケージのバージョンを固定するべきではない。
  • setup.py の install_requiresで定義する。

アプリケーション

  • 再利用は考慮されない。
  • バージョンを含めた具体的な動作環境、依存関係を定義する。
  • 依存パッケージのバージョンは、柔軟性を持たせたうえで、固定化するべき。
  • Pipfileに依存関係とそれをどこから取得するかを定義し、Pipfileを使ってPipfile.lockにある具体的な依存関係を更新する。

PipfileとPipenvは基本的にアプリケーションにおいて使用されることを考慮されていますが、
ライブラリの開発者にとっても便利であり、開発環境やテスト環境の定義に利用できます。

setup.pyに記載されたライブラリのインストールは下記コマンドで行います。

$ pipenv install -e .

これを使用すれば、setup.pyに記載しライブラリを構築しつつその環境でテストするといったことが可能になります。

参考

Pipenvの進んだ使い方 — pipenv 2018.11.27.dev0 ドキュメント