雑記: Pipfile に指定したパッケージの依存パッケージがプラットフォームに依存するとき→

→プラットフォームによって要不要が分かれる依存パッケージは明示的に Pipfile に記述しなければ Pipfile.lock にそれが必要だという情報が欠ける。
なお、逆に元々プラットフォームによってインストールしたいことを明示しているパッケージに依存パッケージがあるとき、依存パッケージについても明示的にプラットフォームを指定しなければどのプラットフォームでもインストールされてしまう(python - Pipenv: dependencies of platform specific packages are installed unconditionally? - Stack Overflow)。まとめると、pipenv さんはインストールしたパッケージを Pipfile.lock に記録するときに、2次以降の依存パッケージについては「インストールしなかったけど他のプラットフォームでは要るな」「インストールしたけど他のプラットフォームでは要らないな」ということを判断して記録するようなことはしないので、Pipfile に明示的に指示する必要がある。


あなたは Linux 機で以下のような Pipfile を記述したとします。「pytest 6.2.5 をインストールしてほしい」という指示になると思います。


[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [packages] pytest = "==6.2.5" [requires] python_version = "3.7"

pipenv install を実行すると指示通りにパッケージがインストールされ、Pipfile.lock が生成されると思います。

$ pipenv install
...
Pipfile.lock not found, creating...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
✔ Success!
Updated Pipfile.lock (a597d0)!
Installing dependencies from Pipfile.lock (a597d0)...
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 11/11 — 00:00:02
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.


{ "_meta": { "hash": { "sha256": "d92376de7296ef8b5b19eb67f0a5316d5c92c4584ead88466ef1005ae6a597d0" }, "pipfile-spec": 6, ...

あなたはインストールされた pytest で実行したかったテストを実行します。

import datetime
import pytest

@pytest.mark.parametrize('date, expected', [
    ('2021-01-01', 'Friday'),
    ('2021-10-01', 'Friday'),
    ('1988-02-06', 'Saturday'),
])
def test_youbi(date, expected):
    dt = datetime.datetime.strptime(date, '%Y-%m-%d')
    assert dt.strftime('%A') == expected
$ pipenv run pytest
...
collected 3 items
test_hoge.py ...                                                                [100%]
================================== 3 passed in 0.02s ==================================

そしてあなたはこの Pipfile, Pipfile.lock, test_hoge.py をリポジトリにコミットします。

後日あなたはそのリポジトリWindows 機からチェックアウトします。そして pipenv install を実行して環境をインストールし、テストを実行します。すると失敗することがわかります。

$ pipenv install
...
Installing dependencies from Pipfile.lock (a597d0)…
  ================================ 11/11 - 00:00:11
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

$ pipenv run pytest
...
ModuleNotFoundError: No module named 'atomicwrites'

atomicwrites なるパッケージがないと怒られていますが、Pipfile.lock の中身をみても Linux 機でそんなパッケージがインストールされた記録はないので pipenv さんがインストールしなかったのも道理だと思います。ではなぜ Windows 機では atomicwrites がないという怒られが発生したのだろうかと思って pytest 6.2.5 のリポジトリをみると、doc/en/changelog.rst に以下の記述を発見します。atomicwrites は pytest 5.3.0 以降 Windows でしか利用されていないというのです。

  • #6148 atomicwrites is now only used on Windows, fixing a performance regression with assertion rewriting on Unix.

また、setup.cfg をみると atomicwrites の他に colorama も Windows だけで必要とされることがわかります。

    atomicwrites>=1.0;sys_platform=="win32"
    colorama;sys_platform=="win32"

試しに Windows 機で Pipfile.lock を削除して pipenv install を実行してみます。すると先ほどまで「11/11」と表示されていたパッケージの個数が「13/13」となり、如何にもパッケージが2つ増えたようにみえます。

$ pipenv install
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Success!
Updated Pipfile.lock (a597d0)!
Installing dependencies from Pipfile.lock (a597d0)…
  ================================ 13/13 - 00:00:10
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

実際、Pipfile.lock をみると atomicwrites と colorama がインストールされています。そして pipenv run pytest は成功します。


... "default": { "atomicwrites": { "hashes": ... , "markers": "sys_platform == 'win32'", "version": "==1.4.0" }, "colorama": { "hashes": ... , "markers": "sys_platform == 'win32'", "version": "==0.4.4" }, ...

なのでひとまずこの Windows 機で生成した Pipfile.lock をコミットすれば Linux 機でも Windows 機でもテストは上手くいきます。"markers": "sys_platform == 'win32'" とあるので、Linux 機で改めて環境構築したときに atomicwrites と colorama がインストールされることはありません。

$ pipenv --rm
$ pipenv install
...
Ignoring atomicwrites: markers 'sys_platform == "win32"' don't match your environment
Ignoring colorama: markers 'sys_platform == "win32"' don't match your environment
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 13/13 — 00:00:01
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.


しかし、これでは Linux 機で Pipfile を更新したときに pipenv さんが「Pipfile の指示が新しくなっとるから改めてパッケージをインストールやな…おっ atomicwrites と colorama は Linux 環境では要らんな!」となってまた Pipfile.lock から2パッケージが欠けてしまう恐れがあります。これを防ぐには Pipfile に明示的に以下を記述することが考えられると思います。


[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [packages] pytest = "==6.2.5" atomicwrites = {version = ">=1.0", sys_platform = "== 'win32'"} colorama = {version = "*", sys_platform = "== 'win32'"} [requires] python_version = "3.7"

こうすると Linux 機で Pipfile の指示を実行したときでも、Pipfile.lock に「Windows ではこれが要るんだってよ」という情報は書き出されます。そしてその Pipfile.lock を Windows 機にチェックアウトしてインストールすると Windows で必要なパッケージが適切にインストールされます。