みなさん pipenv を使ってますか? まだ pip ですか?
最近、pipenv を導入した際に必要だった作業を紹介します1。
pipenv とは何か?なぜ pipenv なのか?
pipenv
は pip
のラッパーで、RubyでいうBundlerです。pip単体でもライブラリの管理はできるのですが、pipenv
の方が色々便利です。
pip
と同様に Python Packaging Authority が管理しています。
setup.py や requirements.txt を削除
今回 pipenv 化したのは アプリケーション です。
PyPIに公開したりする必要はないので、setup.py
の中身は最小限を残して削除します。
setup(
name='hoge',
version='1.4.5',
packages=find_packages(exclude=['test']),
- python_requires='==3.6.3',
- install_requires=[
- 'cx_Oracle==5.3',
- 'pandas==0.23.0',
- 'PyYAML==3.12'
- ],
- extras_require={
- 'dev': [
- 'yapf==0.20.0',
- 'mypy==0.560'
- ]
package_data={'hoge': ['res/*']},
entry_points={
'console_scripts': [
'hoge = hoge.cli:main',
],
},
Pipfile の追加
Pipfile
を追加し、setup.py
から削除した内容を代わりに書き込みます。
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
hoge = {editable = true, path = "."} # setup.py を読み込むため
cx_Oracle = "==5.3"
pandas = "==0.23.0"
PyYAML = "==3.12" # 本来は "*" を指定するべき(後述)
[dev-packages]
yapf = "==0.20.0"
mypy = "==0.560"
[requires]
python_full_version = "3.6.3" # バージョンを厳密に指定
ちなみに、[requires]
で python_version = "3.6"
ではなく python_full_version = "3.6.3"
を指定しています。パッチバージョンの違いにより不具合が生じるリスクはないとも言えませんし、バージョンごとにPythonインタープリタを用意するのは難しくないので、python_full_version
を指定するのをオススメします。
デプロイスクリプトの変更
今までは、こんなシェルスクリプトでデプロイしていました。
# pipenv以前
mkdir "$INSTALL_DIR" # 所定のディレクトリを作成
pushd "$INSTALL_DIR"
# ソースコードをコピー
git -C "$REPO_DIR" archive --format=tar "$VERSION" | tar -xf -
# 仮想環境を作り、そこにインストール
"$PYTHON" -m venv .venv
.venv/bin/pip install .
popd > /dev/null
pip install
を pipenv install
に差し替えます。
# pipenv化
mkdir "$INSTALL_DIR" # 所定のディレクトリを作成
pushd "$INSTALL_DIR"
# ソースコードをコピー
git -C "$REPO_DIR" archive --format=tar "$VERSION" | tar -xf -
# pipenv で 仮想環境を作り、そこにインストール
export PIPENV_VENV_IN_PROJECT=1
"$PYTHON" -m pipenv install \
--python="$PYTHON" \
--deploy
popd > /dev/null
なお、pipenv install
にはいくつかオプションを指定しています。
本番環境へのデプロイではどれも必須でしょう。
--deploy をつける
--deploy
を付けると、Pipfile
とPipfile.lock
にズレがあるとき(pipenv sync
し忘れた時)に、エラーにします。
本番環境へのデプロイでは必ず--deploy
をつけましょう。
環境変数 PIPENV_VENV_IN_PROJECT
を定義する
pipenv
はデフォルト設定では所定のディレクトリにハッシュ値名の仮想環境を作ります(~/.local/share/virtualenvs/hoge-okggs9cf
)。
しかしこれだと、どの仮想環境がどのデプロイに対応するのか判りにくいため、例えば、ディスク容量が足りなくなって不要な仮想環境を削除したいときに困りそうです。
PIPENV_VENV_IN_PROJECT
が定義されていると、仮想環境がカレントディレクトリ下の./.venv
に作られるようになります。
--python
でインタープリタを指定する(pyenv
を使わない)
pipenv
は pyenv
を使っていると、自動的にインタープリタを選択してくれます。
しかし、うちの本番環境では pyenv
を使っていないので、--python
でインタープリタを直接指定しています。
ライブラリのアップデート
今回 pipenv を導入したツールでは、PyYAML==3.12
のようにライブラリのバージョンを厳密に指定していました。しかし、単に PyYAML==3.12
のように書くのは問題があります。
というのも:
a. 単に 3.12
でしか動作確認していないだけで、3.13
でも動くかもしれない(ので、できればアップデートするのが望ましい)
b. (バグや仕様変更により) 3.12
でしか動作しない。アップデートしてはいけない。
のどちらなのか判りません。
今回 pipenv を導入したツールの PyYAML
は前者だったので、Pipfile
を書き換えて動作確認しました。
# Pipfile
[packages]
cx_Oracle = "==5.3"
pandas = "==0.23.0"
- PyYAML = "==3.12'
+ PyYAML = "*"
一方、cx_Oracle や pandas は、このバージョンしか使えない事情があったので、バージョンを厳密に指定しています。
感想
実際の作業としては、特にハマり所はありませんでした
(Pipfile
の文法を覚えるのや、チームメンバーに説明するのは面倒でしたが)。
バージョンを厳密に管理できるメリットは大きいです。ぜひ pipenv の導入を。
-
なお、導入したのは内製のレポート生成ツールでした。顧客へのレポートも生成しているので、一応トラブルがあると困るものです。 ↩