Pipenvの進んだ使い方

https://farm4.staticflickr.com/3672/33231486560_bff4124c9a_k_d.jpg

このドキュメントではPipenvのより輝かしい進んだ機能を対象としています。

☤ 注意書き

  • Pipfile にある依存パッケージのwheelは $ pipenv lock では捕捉されません。
  • There are some known issues with using private indexes, related to hashing. We’re actively working to solve this problem. You may have great luck with this, however.
  • インストールはできる限り決定論的になるようになっています — 問題が出た場合には --sequential フラグを使ってより決定論的に振る舞うようにしてください。

☤ パッケージの一覧を指定する

特定のパッケージ一覧で特定のパッケージをインストールしたい場合は、次のように指定できます:

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

[[source]]
url = "http://pypi.home.kennethreitz.org/simple"
verify_ssl = false
name = "home"

[dev-packages]

[packages]
requests = {version="*", index="home"}
maya = {version="*", index="pypi"}
records = "*"

めっちゃ高機能。

☤ Using a PyPI Mirror

If you’d like to override the default PyPI index urls with the url for a PyPI mirror, you can use the following:

$ pipenv install --pypi-mirror <mirror_url>

$ pipenv update --pypi-mirror <mirror_url>

$ pipenv sync --pypi-mirror <mirror_url>

$ pipenv lock --pypi-mirror <mirror_url>

$ pipenv uninstall --pypi-mirror <mirror_url>

Alternatively, you can set the PIPENV_PYPI_MIRROR environment variable.

☤ 環境変数でPipfileにクレデンシャルを差し込む

Pipenvは (定義されていれば) Pipfileにある環境変数を展開します。 この機能はプライベートのPyPIで認証する必要がある場合に非常に便利です:

[[source]]
url = "https://$USERNAME:${PASSWORD}@mypypi.example.com/simple"
verify_ssl = true
name = "pypi"

幸運なことに、Pipenvは環境変数を展開する 前に Pipfileのハッシュを取ります (そしてありがたいことに、ロックファイルからインストールするときは、再び環境変数が置き換えられます。そのため秘匿情報をコミットする必要は無いのです! やったー!)

☤ 基本的な事項の指定

ある特定のパッケージをあるシステムだけにインストールしたい場合は、 PEP 508 指示子 を使って実現できます。

これが、 Windowsシステムだけに pywinusb をインストールする Pipfile の例です:

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

[packages]
requests = "*"
pywinusb = {version = "*", sys_platform = "== 'win32'"}

ほら、見て!

これがもっと複雑な例です:

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

[packages]
unittest2 = {version = ">=1.0,<3.0", markers="python_version < '2.7.9' or (python_version >= '3.0' and python_version < '3.4')"}

魔法です。純粋な、混じり気の無い魔法です。

☤ システム環境への依存関係のデプロイ

--system フラグを使って、Pipfileの内容にあるものを親システムにイストールするようPipenvに指示できます:

$ pipenv install --system

これはDockerコンテナやデプロイのインフラで役に立ちます (例えば、Herokuで使われています)。

それと --deploy フラグもデプロイで役に立ちます:

$ pipenv install --system --deploy

このフラグを立てると、 Pipfile.lock が古くなっている場合に、 Pipfile.lock を新しく生成するのではなくビルドが失敗します。

☤ PipenvとCPython以外のPythonディストリビューション

To use Pipenv with a third-party Python distribution (e.g. Anaconda), you simply provide the path to the Python binary:

$ pipenv install --python=/path/to/python

AnacondaはCondaでパッケージを管理しています。 CondaでインストールしたPythonのパッケージを再利用するには、 --site-packages フラグを使ってください:

$ pipenv --python=/path/to/python --site-packages

requirements.txt の生成

PipfilePipfile.lockrequirements.txt に非常に簡単に変換でき、追加機能や素敵な機能など既に実装された機能全ての恩恵を受けられます。

この Pipfile から:

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

[packages]
requests = {version="*"}

requirements.txt を生成しましょう:

$ pipenv lock -r
chardet==3.0.4
requests==2.18.4
certifi==2017.7.27.1
idna==2.6
urllib3==1.22

開発用の依存関係だけの requirements.txt を生成したいと思った場合は、それも可能です! 次の Pipfile を用意しましょう:

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

[dev-packages]
pytest = {version="*"}

requirements.txt を生成しましょう:

$ pipenv lock -r --dev
py==1.4.34
pytest==3.2.3

めっちゃ高機能。

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

Pipenv は safety パッケージを含んでいて、既知のセキュリティの脆弱性が無いか依存関係グラフを走査するのに使われます。

例:

$ cat Pipfile
[packages]
django = "==1.10.1"

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

33075: django >=1.10,<1.10.3 resolved (1.10.1 installed)!
Django before 1.8.x before 1.8.16, 1.9.x before 1.9.11, and 1.10.x before 1.10.3, when settings.DEBUG is True, allow remote attackers to conduct DNS rebinding attacks by leveraging failure to validate the HTTP Host header against settings.ALLOWED_HOSTS.

33076: django >=1.10,<1.10.3 resolved (1.10.1 installed)!
Django 1.8.x before 1.8.16, 1.9.x before 1.9.11, and 1.10.x before 1.10.3 use a hardcoded password for a temporary database user created when running tests with an Oracle database, which makes it easier for remote attackers to obtain access to the database server by leveraging failure to manually specify a password in the database settings TEST dictionary.

33300: django >=1.10,<1.10.7 resolved (1.10.1 installed)!
CVE-2017-7233: Open redirect and possible XSS attack via user-supplied numeric redirect URLs
============================================================================================

Django relies on user input in some cases  (e.g.
:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
to redirect the user to an "on success" URL. The security check for these
redirects (namely ``django.utils.http.is_safe_url()``) considered some numeric
URLs (e.g. ``http:999999999``) "safe" when they shouldn't be.

Also, if a developer relies on ``is_safe_url()`` to provide safe redirect
targets and puts such a URL into a link, they could suffer from an XSS attack.

CVE-2017-7234: Open redirect vulnerability in ``django.views.static.serve()``
=============================================================================

A maliciously crafted URL to a Django site using the
:func:`~django.views.static.serve` view could redirect to any other domain. The
view no longer does any redirects as they don't provide any known, useful
functionality.

Note, however, that this view has always carried a warning that it is not
hardened for production use and should be used only as a development aid.

✨🍰✨

注釈

In order to enable this functionality while maintaining its permissive copyright license, pipenv embeds an API client key for the backend Safety API operated by pyup.io rather than including a full copy of the CC-BY-NC-SA licensed Safety-DB database. This embedded client key is shared across all pipenv check users, and hence will be subject to API access throttling based on overall usage rather than individual client usage.

☤ コミュニティとの連係

Pipenvと連係する様々なプロダクトに加え、コミュニティがメンテナンスしている多種多様のプラグインや拡張があり、様々なエディタやIDEで使えます:

対応中:

  • Sublime Text (エディタ連係)
  • PyCharm (エディタ連係)
  • 未だその姿を見せていない来たるべきGoogle Cloudプロダクト (クラウドホスティング)

☤ エディタでモジュールを開く

Pipenvを使うと $ pipenv open コマンドで、(自分で書いたコードベースを含め) インストールされているどんなPythonモジュールも開けます:

$ pipenv install -e git+https://github.com/kennethreitz/background.git#egg=background
Installing -e git+https://github.com/kennethreitz/background.git#egg=background…
...
Updated Pipfile.lock!

$ pipenv open background
Opening '/Users/kennethreitz/.local/share/virtualenvs/hmm-mGOawwm_/src/background/background.py' in your EDITOR.

この機能のおかげで、GitHubまで見に行かなくても、今使っているコードを手軽に読めるようになります。

注釈

この機能では標準の EDITOR 環境変数が使われます。 例えばVS Codeを使っている場合は、 export EDITOR=code とします (macOSの場合は、最初に PATH に上 コマンドをインストール します)。

☤ Pythonの自動インストール

pyenv のインストールと設定が済んでいて、必要とするバージョンのPythonがまだ利用できる状態になっていない場合、Pipenvは自動でそのバージョンのPythonをインストールしたいかどうかを尋ねます。

これは非常に高度な機能で、自慢の機能です:

$ cat Pipfile
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]

[packages]
requests = "*"

[requires]
python_version = "3.6"

$ pipenv install
Warning: Python 3.6 was not found on your system…
Would you like us to install latest CPython 3.6 with pyenv? [Y/n]: y
Installing CPython 3.6.2 with pyenv (this may take a few minutes)…
...
Making Python installation global…
Creating a virtualenv for this project…
Using /Users/kennethreitz/.pyenv/shims/python3 to create virtualenv…
...
No package provided, installing all dependencies.
...
Installing dependencies from Pipfile.lock…
🐍   ❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒❒ 5/5 — 00:00:03
To activate this project's virtualenv, run the following:
 $ pipenv shell

Pipenv は PEP 508 が規定する python_full_versionpython_version の両方に従います。

💫✨🍰✨💫

.env の自動読み込み

プロジェクトに .env ファイルが存在する場合は、 $ pipenv shell および $ pipenv run は自動で読み込みます:

$ cat .env
HELLO=WORLD⏎

$ pipenv run python
Loading .env environment variables…
Python 2.7.13 (default, Jul 18 2017, 09:17:00)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ['HELLO']
'WORLD'

この機能は、本番環境の証明書をコードベースから避けておくのに非常に便利です。 .env ファイルをソースコード管理にコミットするのはお薦めしません!

.env が別のパスに置いてあったり、別のファイル名の場合は、 PIPENV_DOTENV_LOCATION 環境変数を設定します:

$ PIPENV_DOTENV_LOCATION=/path/to/.env pipenv shell

Pipenvが .env ファイルを読み込まないようにするには、 PIPENV_DONT_LOAD_ENV 環境変数を設定します:

$ PIPENV_DONT_LOAD_ENV=1 pipenv shell

☤ 独自のスクリプトショートカット

Pipenvでは scripts セクションに独自のショートカットが設定できます。 pipenv run はこの設定を自動的に読み込み、置き換えるべきコマンドを探し出します。 Pipfile が次のようになっているとすると:

[scripts]
printfoo = "python -c \"print('foo')\""

ターミナルで次のように打ち込んで実行できます:

$ pipenv run printfoo
foo

☤ 環境変数のサポート

Pipenvでは、値の中で環境変数が使えます。 次の例を見てください:

[[source]]
url = "https://${PYPI_USERNAME}:${PYPI_PASSWORD}@my_private_repo.example.com/simple"
verify_ssl = true
name = "pypi"

[dev-packages]

[packages]
requests = {version="*", index="home"}
maya = {version="*", index="pypi"}
records = "*"

環境変数は ${MY_ENVAR}$MY_ENVAR のように指定します。 Windowsでは、 ${MY_ENVAR}$MY_ENVAR に加えて %MY_ENVAR% もサポートされています。

☤ 環境変数による設定

Pipenvには、シェル環境変数で有効にできるオプションが少しだけあります。 オプションを有効にするには、シェルでその変数を作成すればpipevnが見付けてくれます。

pipenv.environments.PIPENV_CACHE_DIR = '/home/docs/.cache/pipenv'

Location for Pipenv to store it’s package cache.

Default is to use appdir’s user cache directory.

pipenv.environments.PIPENV_COLORBLIND = False

If set, disable terminal colors.

Some people don’t like colors in their terminals, for some reason. Default is to show colors.

pipenv.environments.PIPENV_DEFAULT_PYTHON_VERSION = None

Use this Python version when creating new virtual environments by default.

This can be set to a version string, e.g. 3.6, or a path. Default is to use whatever Python Pipenv is installed under (i.e. sys.executable). Command line flags (e.g. --python, --three, and --two) are prioritized over this configuration.

pipenv.environments.PIPENV_DONT_LOAD_ENV = False

If set, Pipenv does not load the .env file.

Default is to load .env for run and shell commands.

pipenv.environments.PIPENV_DONT_USE_PYENV = False

If set, Pipenv does not attempt to install Python with pyenv.

Default is to install Python automatically via pyenv when needed, if possible.

pipenv.environments.PIPENV_DOTENV_LOCATION = None

If set, Pipenv loads the .env file at the specified location.

Default is to load .env from the project root, if found.

pipenv.environments.PIPENV_EMULATOR = ''

If set, the terminal emulator’s name for pipenv shell to use.

Default is to detect emulators automatically. This should be set if your emulator, e.g. Cmder, cannot be detected correctly.

pipenv.environments.PIPENV_HIDE_EMOJIS = False

Disable emojis in output.

Default is to show emojis. This is automatically set on Windows.

pipenv.environments.PIPENV_IGNORE_VIRTUALENVS = False

If set, Pipenv will always assign a virtual environment for this project.

By default, Pipenv tries to detect whether it is run inside a virtual environment, and reuses it if possible. This is usually the desired behavior, and enables the user to use any user-built environments with Pipenv.

pipenv.environments.PIPENV_INSTALL_TIMEOUT = 900

Max number of seconds to wait for package installation.

Defaults to 900 (15 minutes), a very long arbitrary time.

pipenv.environments.PIPENV_MAX_DEPTH = 4

Maximum number of directories to recursively search for a Pipfile.

Default is 3. See also PIPENV_NO_INHERIT.

pipenv.environments.PIPENV_MAX_RETRIES = 0

Specify how many retries Pipenv should attempt for network requests.

Default is 0. Aautomatically set to 1 on CI environments for robust testing.

pipenv.environments.PIPENV_MAX_ROUNDS = 16

Tells Pipenv how many rounds of resolving to do for Pip-Tools.

Default is 16, an arbitrary number that works most of the time.

pipenv.environments.PIPENV_MAX_SUBPROCESS = 16

How many subprocesses should Pipenv use when installing.

Default is 16, an arbitrary number that seems to work.

pipenv.environments.PIPENV_NOSPIN = False

If set, disable terminal spinner.

This can make the logs cleaner. Automatically set on Windows, and in CI environments.

pipenv.environments.PIPENV_NO_INHERIT = False

Tell Pipenv not to inherit parent directories.

This is useful for deployment to avoid using the wrong current directory. Overwrites PIPENV_MAX_DEPTH.

pipenv.environments.PIPENV_PIPFILE = None

If set, this specifies a custom Pipfile location.

When running pipenv from a location other than the same directory where the Pipfile is located, instruct pipenv to find the Pipfile in the location specified by this environment variable.

Default is to find Pipfile automatically in the current and parent directories. See also PIPENV_MAX_DEPTH.

pipenv.environments.PIPENV_PYPI_MIRROR = None

If set, tells pipenv to override PyPI index urls with a mirror.

Default is to not mirror PyPI, i.e. use the real one, pypi.org. The --pypi-mirror command line flag overwrites this.

pipenv.environments.PIPENV_SHELL = None

An absolute path to the preferred shell for pipenv shell.

Default is to detect automatically what shell is currently in use.

pipenv.environments.PIPENV_SHELL_FANCY = False

If set, always use fancy mode when invoking pipenv shell.

Default is to use the compatibility shell if possible.

pipenv.environments.PIPENV_TIMEOUT = 120

Max number of seconds Pipenv will wait for virtualenv creation to complete.

Default is 120 seconds, an arbitrary number that seems to work.

pipenv.environments.PIPENV_VENV_IN_PROJECT = False

If set, creates .venv in your project directory.

Default is to create new virtual environments in a global location.

pipenv.environments.PIPENV_YES = False

If set, Pipenv automatically assumes 「yes」 at all prompts.

Default is to prompt the user for an answer if the current command line session if interactive.

これらの環境変数をプロジェクトごとの設定にしたい場合は、それを実現するために素敵な direnv を利用するのをお薦めします。

さらにカスタマイズする必要がある場合は、 pip自身も環境変数をサポートしている ことに着目してください。

例えば、次のようにできます:

$ PIP_INSTALL_OPTION="-- -DCMAKE_BUILD_TYPE=Release" pipenv install -e .

☤ 仮想環境の独自の配置場所

Pipenv automatically honors the WORKON_HOME environment variable, if you have it set — so you can tell pipenv to store your virtual environments wherever you want, e.g.:

export WORKON_HOME=~/.venvs

さらに、 PIPENV_VENV_IN_PROJECT 環境変数を設定することで、 project/.venv にある仮想環境をPipenvに使わせることができます。

☤ プロジェクトのテスト

Pipenvは Requests のようなプロジェクトで開発用の依存関係の宣言とテストスイートの実行に使われています。

現時点では Travis-CItox の両方で上手くデプロイのテストを行えています。

Travis CI

Travis CIの設定例は Requests にあります。 このプロジェクトではMakefileによく使う関数を init コマンドや tests コマンドとして定義してあります。 以下が .travis.yml の本質的なところを抜き出したものです:

language: python
python:
    - "2.6"
    - "2.7"
    - "3.3"
    - "3.4"
    - "3.5"
    - "3.6"
    - "3.7-dev"

# command to install dependencies
install: "make"

# command to run tests
script:
    - make test

そして対応するMakefileは以下の通りです:

init:
    pip install pipenv
    pipenv install --dev

test:
    pipenv run py.test tests

ToX自動化プロジェクト

または、 tox.ini を次のようにローカル環境でのテストと外部環境でのテストの両方に対して設定できます:

[tox]
envlist = flake8-py3, py26, py27, py33, py34, py35, py36, pypy

[testenv]
deps = pipenv
commands=
    pipenv install --dev
    pipenv run py.test tests

[testenv:flake8-py3]
basepython = python3.4
commands=
    pipenv install --dev
    pipenv run flake8 --version
    pipenv run flake8 setup.py docs project test

Pipenvは自動的に tox が提供する仮想環境を使います。 pipenv install --dev が例えば pytest をインストールしたならば、インストールされたコマンド py.test は与えられた仮想環境に入っていて、 pipenv run py.test tests としなくても py.test tests と直接呼び出せます。

テストを実行するたびにうっかりlockファイルを編集してしまわないように、 pipenv install--ignore-pipfile を付けたいと思うかもしれません。 これをするとPipenvが Pipfile への変更を無視してしまうのと、(もっと重要なこととして) 現在の環境を Pipfile.lock に追加するのを防ぎます。 これが重要な点なのは、今いる環境 (すなわちtoxが用意した仮想環境) は通常は (望ましいもしくは望しくないことに) 現時点のプロジェクトと、 toxdeps に設定されている追加の依存関係を含んでいるためです。 最初に用意される環境に対しては、この方法ではなく skip_install = True をtox.iniに追加することで無効化できます。

この方法はlockファイルの更新に関しての明示的な指定が必要であり、おそらくこれがどのケースにおいても良い案です。

サードパーティのプラグイン tox-pipenv も、toxにPipenvを連係させるのに使えます。

☤ シェルの補完

fishで補完を有効にするには、次のコマンドを設定ファイルに追加してください:

eval (pipenv --completion)

また、bashやzshでは次のコマンドを設定ファイルに追加してください:

eval "$(pipenv --completion)"

魔法のシェル補完が使えるようになりました!

✨🍰✨

☤ プラットフォームが提供するPythonコンポーネントを使っての作業

オペレーティングシステムのインターフェースに使われているプラットフォーム固有のPythonは、システムのパッケージマネージャからしか利用できず、従って pip を使った仮想環境へのインストールには使えないのが合理的に考えて普通です。 このようなケースでは、システムの site-packages ディレクトリにアクセスできる仮想環境を作ります:

$ pipenv --three --site-packages

pip でインストールできるコンポーネントが本当に仮想環境にインストールされ、システムのパッケージはPythonレベルでの依存関係解決に一切現れないインターフェースのために使われることを保証するために、 PIP_IGNORE_INSTALLED 設定を使いましょう:

$ PIP_IGNORE_INSTALLED=1 pipenv install --dev

☤ Pipfile vs setup.py

アプリケーションライブラリ の間には、微妙だが非常に重要な違いがあります。 これはPythonコミュニティでよく起こる混乱の元になっています。

ライブラリは、再利用可能な機能を他のライブラリやアプリケーション (ここでは両方を包括する用語として プロジェクト を使います) に提供します。 ライブラリは、自身を起点とする依存関係である他のライブラリと共に協調して動作する必要があります。 ライブラリは 抽象的な依存関係 を定義します。 プロジェクトに含まれる別々のライブラリのそれぞれを起点とする依存関係どうしで、バージョンの衝突が起きないようにライブラリは絶対に依存パッケージのバージョンを固定するべきではありません。 ある特定の機能や修正やバグに依存している場合には、バージョンの下限や (滅多に無いですが) 上限を指定することもあります。 ライブラリの依存関係は setup.py では install_requires で指定します。

ライブラリは究極的には、とある アプリケーション で使われるためのものです。 アプリケーションはそれとは違って、通常は他のプロジェクトから依存されることはありません。 アプリケーションは、ある特定の環境に配置され、依存関係やさらにその先の依存関係全ての正確なバージョンが具体的であるようになっています。 この処理をより簡単にすることが、現在Pipenvの最も重要な目標です。

まとめると次のようになります:

  • ライブラリは、 setup.pyinstall_requires抽象的な依存関係 を定義します。 厳密にどのバージョンをインストールし、どこから依存パッケージを取得するかの判断は、あなたが決めることではありません!
  • アプリケーションは、 Pipfile依存関係とそれをどこから取得するか を定義し、Pipfileを使って Pipfile.lock にある 具体的な依存関係 たちを更新します。 Pipfile.lockは、プロジェクトがきちんと動くことが分かっている特定の冪等な環境を定義します。 Pipfile.lock は正しさの源泉です。 Pipfile はそのlockファイルを作るのに便利なもので、実際に使う依存関係の正確なバージョンについて、曖昧なままにしておけます。 Pipenvは、きちんと動作する衝突の起きない依存関係のバージョン指定を定義する助けになります。他のツールではこの作業は非常にうんざりするものになります。
  • もちろん、 Pipfile とPipenvはライブラリの開発者にも便利なもので、開発環境やテスト環境を定義するのに使えます。
  • そして当り前ですが、ライブラリとアプリケーションの区別が明確でないプロジェクトもあります。 その場合は、Pipenvおよび Pipfile と一緒に install_requires を使ってください。

次のようにもできます:

$ pipenv install -e .

このコマンドでは、 setup.py で宣言されている依存関係を全てロックするようにPipenvに指示しています。

☤ Pipenvのキャッシュの場所を変更する

環境変数 PIPENV_CACHE_DIR を好きな場所に設定することで、デフォルトと異なるキャッシュの場所を使うようPipenvに強制できます。 これは PIP_CACHE_DIR を別のディレクトリに変更しているのと同じ状況で役に立ちます。

☤ Pythonのデフォルトバージョンを変更する

デフォルトでは、Pipenvはプロジェクトの初期化にpython3のどれかのバージョンを使います。 --three フラグもしくは --two フラグを付けてプロジェクトを始める他に、 --three--two を付けていないときには PIPENV_DEFAULT_PYTHON_VERSION を使ってプロジェクトを始めるときにどのバージョンを使うかを指定できます。