Help us understand the problem. What is going on with this article?

Pipenvことはじめ

ずっと気になりつつ手を出せていなかったPipenvをちゃんと試してみました。

pipenvのインストール・セットアップ

まずはインストールから

# python3 環境で試してみたいため
pip3 install pipenv

インストール後、作業ディレクトリに移動

# 使用するバージョンを厳密に指定する
pipenv --python 3.7.2

# 上記以外にも下記のようにアバウトな指定も可能
# Python 3を使う場合
# pipenv --three  
# Python 2を使う場合
# pipenv --two  

これでcurrentにPipfileができる。
cat Pipfileで中身を見てみる

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]

[requires]
python_version = "3.7"

pipenvを用いたライブラリのインストール

ためしにbeautifulsoup4requestspipenvを使ってインストールしてみる。

$pipenv install beautifulsoup4 requests
Installing beautifulsoup4…
Adding beautifulsoup4 to Pipfile's [packages]…
✔ Installation Succeeded
Installing requests…
Adding requests to Pipfile's [packages]…
✔ Installation Succeeded
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
✔ Success!
Updated Pipfile.lock (b65c9c)!
Installing dependencies from Pipfile.lock (b65c9c)…
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 7/7 — 00:00:01
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

cat Pipfileで再度Pipfileの中身を見てみる。

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
beautifulsoup4 = "*"
requests = "*"

[requires]
python_version = "3.7"

packagesの中に追記されているのが分かる。
ちなみにバージョンを指定しないでインストールすると*になるよう。
ただ、インストールしたバージョンについてはPipfile.lockなるものが作られて、こちらで管理されるよう。
npmでいうpackage-lock.json
yarnでいうyarn.lock
bundlerでいうGemfile.lockのようなものですね。

package.jsonでいうdevDependenciesの仕組みもあって、例えば開発時にのみflake8を使いたいってときは--devをつけて実行すれば良い。

$pipenv install --dev flake8
Installing flake8…
Adding flake8 to Pipfile's [dev-packages]…
✔ Installation Succeeded
Pipfile.lock (cbc640) out of date, updating to (b65c9c)…
Locking [dev-packages] dependencies…
✔ Success!
Locking [packages] dependencies…
✔ Success!
Updated Pipfile.lock (cbc640)!
Installing dependencies from Pipfile.lock (cbc640)…
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 12/12 — 0

Pipfileにもdev-packagesとして依存関係が追加されている。

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
flake8 = "*"

[packages]
beautifulsoup4 = "*"
requests = "*"

[requires]
python_version = "3.7"

pipenv環境で依存ライブラリのインストール

使う場面としては、gitcloneしてきたものがpipenvを使っている場合などに使用。
Pipfile.lockの依存関係を見て、必要なライブラリをインストールしてくれる。

$pipenv install

npmでいうnpm installと同じもの。

requirements.txt で管理しているプロジェクトにPipenvを導入する場合

例えば下記のように requirements.txt で管理されているプロジェクトがあったとする。

$cat requirements.txt
beautifulsoup4==4.8.1
requests==2.22.0

pip installの場合は下記のように実施して依存ライブラリをインストールすることになるが、

pip install -r requirements.txt

pipenvを導入する場合は、上に書いた通りのコマンド(下記を参照)を実施すれば、勝手に依存ライブラリを認識してPipfileを作成してくれる。

pipenv --python 3.7.2

上のコマンドを叩いた際に、下記のようなログも一緒に流れて、Pipfileに変換してくれたことが分かる。

requirements.txt found, instead of Pipfile! Converting…
✔ Success!
Warning: Your Pipfile now contains pinned versions, if your requirements.txt did.
We recommend updating your Pipfile to specify the "*" version, instead.

実際に出力された Pipfile は下記の通り。

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
beautifulsoup4 = "==4.8.1"
requests = "==2.22.0"

[requires]
python_version = "3.7"

簡単にpipenvへの管理に移行できるのはとても良い。

pipenv環境での実行手順(shell)

ちなみにこの状態でpython3を実行して下記のようにインストールしたpackageを読み込もうとするとエラーになる。

$python3
Python 3.7.2 (default, Feb 11 2019, 09:42:34)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'requests'

npmとかだと、そのまま読み込めるところだけど、pipenvはそうは行かないよう。
上に貼り付けたログにも出ていたが、pipenv shellをすると、pipenvで作った環境内でshellを起動できるようだ。

# shell起動
$pipenv shell
Launching subshell in virtual environment…
 . /Users/username/.local/share/virtualenvs/dirname-85OFZKXi/bin/activate
~/dirname : $ . /Users/username/.local/share/virtualenvs/dirname-85OFZKXi/bin/activate

# 仮想環境がactivateされた状態となる
(dirname) ~/dirname : $python3
Python 3.7.2 (default, Feb 11 2019, 09:42:34)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> exit()

# 仮想環境から抜けるときはdeactivate
(dirname) ~/dirname : $deactivate

# 追記: 次回pipenv shell実行時にエラーが出るのでサブシェルも終了させる
~/dirname : $exit

サブシェルの終了について下記に追記しています。
pipenv shellをしても実行できないとき

pipenv環境での実行手順(ファイル実行)

試しにこんなスクリプト(sample.py)を書いてみました。
無慈悲なコードですね。

import requests
print(requests)

これも当然ながらpython3 sample.pyと実行するとエラーになります。

$python3 sample.py
Traceback (most recent call last):
  File "sample.py", line 1, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

pipenv run python3 sample.pyで実行するようです。

$pipenv run python3 sample.py
<module 'requests' from '{省略}'>

独自のコマンドを定義する(scripts)

ちなみにpipenv run sample.pyと実行してみたら下記のようなエラーが出てきた。

$pipenv run sample.py
Error: the command sample.py could not be found within PATH or Pipfile's [scripts].

https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#custom-script-shortcuts

どうやら独自のコマンド定義ができるよう。
(package.json内に書くscriptsみたいなやつ)

Pipfileに下記を追記する

[scripts]
sample = "python3 sample.py"

後は実行すればOK

$pipenv run sample
<module 'requests' from '{省略}'>

独自のコマンドに引数を渡す(scripts)

ちなみに定義したコマンドには引数も渡せるよう。

テストのためのスクリプト

import sys
args = sys.argv
print(args)

pipfileで下記のように定義

[scripts]
argvtest = "python3 argvtest.py"

引数を付けて実行してみると、ちゃんと引数を渡してくれている

$pipenv run argvtest AAAAAAA BBBBBBBBBB CCCCCCCCCCCCCCC
['argvtest.py', 'AAAAAAA', 'BBBBBBBBBB', 'CCCCCCCCCCCCCCC']

requirements.txtに書き出す

pipenv lock -rを実行すると、依存関係にあるパッケージがrequirements.txt形式で吐き出される。

$pipenv lock -r
-i https://pypi.org/simple
beautifulsoup4==4.7.1
certifi==2018.11.29
chardet==3.0.4
idna==2.8
requests==2.21.0
soupsieve==1.7.3
urllib3==1.24.1

ちなみにpipenv lock -r -dを実行すると--devでインストールしたパッケージのみが表示される。

$pipenv lock -r -d
-i https://pypi.org/simple
entrypoints==0.3
flake8==3.7.5
mccabe==0.6.1
pycodestyle==2.5.0
pyflakes==2.1.0`

例えば開発依存も含めた状態でrequirements.txtをエクスポートする場合は

pipenv lock -r > requirements.txt
pipenv lock -r -d >> requirements.txt

と打てばよいのかと思ったけど、そもそもpipenvのやり方で環境構築すればいいわけだし、
使用用途してあるのは、開発依存は除外した状態でrequirements.txtを作成するぐらいなのか
(ここらへん、実際どうなんでしょう?)

セキュリティの脆弱性の検知

下記コマンドで既知のセキュリティの脆弱性が無いか依存関係グラフを走査してくれるよう。

https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#detection-of-security-vulnerabilities

$pipenv check
Checking PEP 508 requirements…
Passed!
Checking installed package safety…
All good!

インストールしたパッケージをエディターで開く

コードリーディングしたい方にとっては便利かも
下記のコマンドを打つと、設定されているエディターでパッケージのディレクトリを開いてくれます。
(私の場合はvimが起動してディレクトリが開かれる感じ)

pipenv open requests

https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#open-a-module-in-your-editor

環境変数:TODO

疲れたので、これは後で調べようと思います。
ドキュメントはここに書かれているようですね。

https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#injecting-credentials-into-pipfiles-via-environment-variables

pipenv shellをしても実行できないとき

pipenv shellをしてもShell for UNKNOWN_VIRTUAL_ENVIRONMENT already activated.というメッセージが出てきて実行できないとき

pipenv shellをすると下のようなエラーが出て、shellが実行できないときがあります。
(実際にはpipenv shelldeactivateで終了させたあとに出てくるよう)

$pipenv shell
Shell for UNKNOWN_VIRTUAL_ENVIRONMENT already activated.
No action taken to avoid nested environments.

調べてみるとこのissueにたどり着きました。
pipenv shell, then deactivate should display warning #736

どうやらpipenv shellは仮想環境でサブシェルを起動しているので、一度exitでサブシェル自体を終了させないとこのようなエラーが出てしまうということらしい。

たしかにpipenv shellって打つと下のようなメッセージが出てきていましたね。

Launching subshell in virtual environment…

個人的に混乱ポイントでしたので、備忘録がてら追記しました。

pipenv shellで仮想環境を立ち上げたときは、最後にexitでサブシェル自体も終了させるのをお忘れなきよう。

感想

npmみたいに管理できるようになったのは嬉しいです。
特に今まではテストやフォーマット関連のライブラリも一緒くたに入れることになっていたので、それによる気持ち悪さがdev-packagesで解消できていたり、独自のコマンドも定義できるようになったので、開発もよりやりやすくなりそう。
ひとまず今後はPipenvを基本使うようにしてみようと思います。
(どちらかというとPython触る機会自体は少ない自分ですが...😂)

参照資料

公式ドキュメント(日本語版)
https://pipenv-ja.readthedocs.io/ja/translate-ja/index.html
https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html

github
https://github.com/pypa/pipenv

shinshin86
エンジニアになる前は作曲を行っていましたが、サウンドプログラミングには疎いです。 JSを触っていることが多いです。
https://github.com/shinshin86
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away