LoginSignup
23
14

More than 3 years have passed since last update.

Pipenvを使っていたらハッシュエラーが出るようになった話

Last updated at Posted at 2019-11-28

これはなに

Pipenvを使っていたらある日謎のエラーが出るようになりました。

原因を突き止めるのに苦労したのでメモ的に書いていこうかと思った次第です。
最終的には解決したので、同じような症状で悩んでいて、対処法だけ知りたい方は解決までどうぞ。

Pipenvを使っていたらある日謎のエラーが出ていることに気づく

最初にこのエラーに気づいたのはCIで自動テストを設定しようと思ったときでした。
docker環境内で自動テストを実行するコードを書いていたのですが、docker内でpipenv syncpipenv installを実行する時に以下のエラーが出ていることに気づきました。

An error occurred while installing readme-renderer==24.0 --hash=sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f --hash=sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d! Will try again.
An error occurred while installing requests==2.22.0 --hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 --hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31 --hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 --hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31! Will try again.
An error occurred while installing requests-toolbelt==0.9.1 --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0! Will try again.
An error occurred while installing secretstorage==3.1.1 ; sys_platform == 'linux' --hash=sha256:20c797ae48a4419f66f8d28fc221623f11fc45b6828f96bdb1ad9990acb59f92 --hash=sha256:7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a! Will try again.
An error occurred while installing sphinx==2.2.1 --hash=sha256:31088dfb95359384b1005619827eaee3056243798c62724fd3fa4b84ee4d71bd --hash=sha256:52286a0b9d7caa31efee301ec4300dbdab23c3b05da1c9024b4e84896fb73d79! Will try again.
An error occurred while installing sphinx-git==11.0.0 --hash=sha256:6bf9d837de108c79fb7db585ebd590fd48f4d1f830b540420d0ca675f3b9f800! Will try again.
An error occurred while installing twine==3.1.0 --hash=sha256:1a87ae3f1e29a87a8ac174809bf0aa996085a0368fe500402196bda94b23aab3 --hash=sha256:ba8ba1b39987f1c22d9162f7dd3b4668388640e5f7158c15226624f88e464836! Will try again.

色々ためして、venv環境が無い状態でpipenv installpipenv syncを実行するとエラーが発生することがわかりました。
hashが出ているのでひとまずPipfile.lockも消してみてから、pipenv install`を実行したがそれでもエラーが出る。
この時確認した状況は以下の通りです。

  • venv環境、Pipfile.lockがなくても同様のエラーが出る。
  • 上記でエラーが出ているモジュールを別のPipfileでインストールしてもこのエラーは発生しない。
  • エラーは出ているがインストールは完了している。

さてさてこれはなんなんだ...

Pipfileを眺めてみる

venv環境もPipfile.lockも消してなお、エラーが出るのでPipfileに原因があるのはほぼ確定です。
このときのPipfileが以下になります。

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

[dev-packages]
flake8 = "*" 
autopep8 = "*" 
isort = "*" 
autoflake = "*" 
pytest = "*" 
pytest-cov = "*" 
qiitacli = {path = "."}
twine = "*" 
sphinx = "*" 
sphinx-git = "*" 
pypandoc = "*" 

[packages]
click = ">=7.0"
qiita_v2 = ">=0.2.1"

[requires]
python_version = "3" 

[scripts]
main = "python qiitacli/client.py"

僕の脳みそじゃどこがおかしいかわからないよ...

ログを見てみる

pipenv install時に-vオプションを付けて出力を眺めてみました。
思ったより出力が多くてびっくりしましたw

その中で原因と思われるログが出ていたのがこちら。

ERROR: In --require-hashes mode, all requirements must have their versions pinned with ==. These do not:
    tqdm>=4.14 from https://files.pythonhosted.org/packages/bb/62/6f823501b3bf2bac242bd3c320b592ad1516b3081d82c77c1d813f076856/tqdm-4.39.0-py2.py3-none-any.whl#sha256=5a1f3d58f3eb53264387394387fe23df469d2a3fab98c9e7f99d5c146c119873 (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))    readme-renderer>=21.0 from https://files.pythonhosted.org/packages/c3/7e/d1aae793900f36b097cbfcc5e70eef82b5b56423a6c52a36dce51fedd8f0/readme_renderer-24.0-py2.py3-none-any.whl#sha256=c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))
    requests-toolbelt!=0.9.0,>=0.8.0 from https://files.pythonhosted.org/packages/60/ef/7681134338fc097acef8d9b2f8abe0458e4d87559c689a8c306d0957ece5/requests_toolbelt-0.9.1-py2.py3-none-any.whl#sha256=380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))
    secretstorage; sys_platform == "linux" from https://files.pythonhosted.org/packages/82/59/cb226752e20d83598d7fdcabd7819570b0329a61db07cfbdd21b2ef546e3/SecretStorage-3.1.1-py3-none-any.whl#sha256=7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a (from keyring>=15.1->twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))
Exception information:
Traceback (most recent call last):
  File "/hoge/.venv/lib/python3.6/site-packages/pip/_internal/cli/base_command.py", line 153, in _main
    status = self.run(options, args)
  File "/hoge/.venv/lib/python3.6/site-packages/pip/_internal/commands/install.py", line 382, in run
    resolver.resolve(requirement_set)
  File "/hoge/.venv/lib/python3.6/site-packages/pip/_internal/legacy_resolve.py", line 208, in resolve
    raise hash_errors
pip._internal.exceptions.HashErrors: In --require-hashes mode, all requirements must have their versions pinned with ==. These do not:
    tqdm>=4.14 from https://files.pythonhosted.org/packages/bb/62/6f823501b3bf2bac242bd3c320b592ad1516b3081d82c77c1d813f076856/tqdm-4.39.0-py2.py3-none-any.whl#sha256=5a1f3d58f3eb53264387394387fe23df469d2a3fab98c9e7f99d5c146c119873 (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))    readme-renderer>=21.0 from https://files.pythonhosted.org/packages/c3/7e/d1aae793900f36b097cbfcc5e70eef82b5b56423a6c52a36dce51fedd8f0/readme_renderer-24.0-py2.py3-none-any.whl#sha256=c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))
    requests-toolbelt!=0.9.0,>=0.8.0 from https://files.pythonhosted.org/packages/60/ef/7681134338fc097acef8d9b2f8abe0458e4d87559c689a8c306d0957ece5/requests_toolbelt-0.9.1-py2.py3-none-any.whl#sha256=380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f (from twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))
    secretstorage; sys_platform == "linux" from https://files.pythonhosted.org/packages/82/59/cb226752e20d83598d7fdcabd7819570b0329a61db07cfbdd21b2ef546e3/SecretStorage-3.1.1-py3-none-any.whl#sha256=7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a (from keyring>=15.1->twine==3.1.0->-r /tmp/pipenv-pbslpsa_-requirements/pipenv-u629hk8s-requirement.txt (line 1))

内部でpip installする時に--require-hashesオプション付けてるんですね。
hash checking modeというらしい、このログ見るまで存在を知りませんでした。

In --require-hashes mode, all requirements must have their versions pinned with ==. These do not 要約するとhash checking modeの時はすべてのモジュールのバージョンを==で指定しなきゃだめよ!!ってことっぽいですね。(英語ワカラナイ)

そもそもエラーの出ていないモジュールもPipfileでバージョン指定してないし、謎は深まるばかり。

requirements.txtを眺めてみる

ログを見るにPipenvコマンドはrequirements.txt相当のファイルを/tmp配下に生成しては、pipコマンドに-rオプションを付けて実行しているよう。
それらのファイルの中身を実際に見てました。

方法としてはPipenv実行時にひたすらsudo cp -rf /tmp/pipenv* .を連打。絶対にもっといい方法があるはずだけれどひとまずこれで。

コピーしたファイルのなかの一つを見てみるとこんな感じ

twine==3.1.0 --hash=sha256:1a87ae3f1e29a87a8ac174809bf0aa996085a0368fe500402196bda94b23aab3 --hash=sha256:ba8ba1b39987f1c22d9162f7dd3b4668388640e5f7158c15226624f88e464836

ほー、モジュールひとつずつにハッシュ値を付けたrequirements.txtを生成して、-rオプションに渡しているんだ。

ハッシュ値を確認してみましたが、実際に公開されているファイルと同値でした。

試しにこのrequirements.txtファイルを使って手で作ったvenv環境にインストールしてみます。

$ echo -n ' twine==3.1.0 --hash=sha256:1a87ae3f1e29a87a8ac174809bf0aa996085a0368fe500402196bda94b23aab3 --hash=sha256:ba8ba1b39987f1c22d9162f7dd3b4668388640e5f7158c15226624f88e464836' > requirements.txt
$ python3 -m venv venv
$ ./venv/bin/pip install -r requirements.txt --require-hashes
Collecting twine==3.1.0
  Using cached https://files.pythonhosted.org/packages/74/45/1016cad7eb7cbda959a701d1dfa88b9118306677018ac3de224a6a6e7751/twine-3.1.0-py3-none-any.whl
Collecting readme-renderer>=21.0
Collecting requests-toolbelt!=0.9.0,>=0.8.0
Collecting tqdm>=4.14
Collecting requests>=2.20
Collecting keyring>=15.1
Collecting importlib-metadata; python_version < "3.8"
Requirement already satisfied: setuptools>=0.7.0 in ./venv/lib/python3.6/site-packages (from twine==3.1.0->-r requirements.txt (line 1)) (42.0.1)
Collecting pkginfo>=1.4.2
ERROR: In --require-hashes mode, all requirements must have their versions pinned with ==. These do not:
    readme-renderer>=21.0 from https://files.pythonhosted.org/packages/c3/7e/d1aae793900f36b097cbfcc5e70eef82b5b56423a6c52a36dce51fedd8f0/readme_renderer-24.0-py2.py3-none-any.whl#sha256=c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d (from twine==3.1.0->-r requirements.txt (line 1))
    requests-toolbelt!=0.9.0,>=0.8.0 from https://files.pythonhosted.org/packages/60/ef/7681134338fc097acef8d9b2f8abe0458e4d87559c689a8c306d0957ece5/requests_toolbelt-0.9.1-py2.py3-none-any.whl#sha256=380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f (from twine==3.1.0->-r requirements.txt (line 1))
    tqdm>=4.14 from https://files.pythonhosted.org/packages/bb/62/6f823501b3bf2bac242bd3c320b592ad1516b3081d82c77c1d813f076856/tqdm-4.39.0-py2.py3-none-any.whl#sha256=5a1f3d58f3eb53264387394387fe23df469d2a3fab98c9e7f99d5c146c119873 (from twine==3.1.0->-r requirements.txt (line 1))
    requests>=2.20 from https://files.pythonhosted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/requests-2.22.0-py2.py3-none-any.whl#sha256=9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31 (from twine==3.1.0->-r requirements.txt (line 1))
    keyring>=15.1 from https://files.pythonhosted.org/packages/b1/08/ad1ae7262c8146bee3be360cc766d0261037a90b44872b080a53aaed4e84/keyring-19.2.0-py2.py3-none-any.whl#sha256=f5bb20ea6c57c2360daf0c591931c9ea0d7660a8d9e32ca84d63273f131ea605 (from twine==3.1.0->-r requirements.txt (line 1))
    importlib-metadata; python_version < "3.8" from https://files.pythonhosted.org/packages/f6/d2/40b3fa882147719744e6aa50ac39cf7a22a913cbcba86a0371176c425a3b/importlib_metadata-0.23-py2.py3-none-any.whl#sha256=d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af (from twine==3.1.0->-r requirements.txt (line 1))
    pkginfo>=1.4.2 from https://files.pythonhosted.org/packages/e6/d5/451b913307b478c49eb29084916639dc53a88489b993530fed0a66bab8b9/pkginfo-1.5.0.1-py2.py3-none-any.whl#sha256=a6d9e40ca61ad3ebd0b72fbadd4fba16e4c0e4df0428c041e01e06eb6ee71f32 (from twine==3.1.0->-r requirements.txt (line 1))

お!再現したぞ!

でもエラーが出ているのはrequirements.txtに記述されてるモジュールとは別のモジュール...

このhash checking modeってのは依存パッケージもすべてバージョン指定で記述する必要があるんですね。
でもじゃあなぜ普通にpipenv installする時はエラーが出ないのか。

--no-depsとは

もうしばらくログを確認していると正常に動作している時はpipでインストールする時に--no-depsというオプションが付いていることを見つけました。

  • エラー時のログ
$ ['/hoge/.venv/bin/pip', 'install', '--verbose', '--upgrade', '-r', '/tmp/pipenv-9owwlzhi-requirements/pipenv-65yqxf03-requirement.txt', '-i', 'https://pypi.org/simple', '--require-hashes']
  • 正常時のログ
$ ['/hoge/.venv/bin/pip', 'install', '--verbose', '--upgrade', '--no-deps', '-r', '/tmp/pipenv-5dvxlnyt-requirements/pipenv-pvatvj5c-requirement.txt', '-i', 'https://pypi.org/simple', '--require-hashes']

おおおこれっぽい!

--no-depsDon't install package dependencies.つまり依存パッケージをインストールしないオプションですね。
なるほでこれならさっきのrequirements.txtでも正常に動作しそうです。

$ ./venv/bin/pip install -r requirements.txt --require-hashes --no-deps 
Collecting twine==3.1.0
  Using cached https://files.pythonhosted.org/packages/74/45/1016cad7eb7cbda959a701d1dfa88b9118306677018ac3de224a6a6e7751/twine-3.1.0-py3-none-any.whl
Installing collected packages: twine
Successfully installed twine-3.1.0

できた。

少しずつ原因がつかめてきました。

あと残るは謎は なぜ--no-depsオプションを付けてくれなかったのか だけですね。

最後の鍵はeditable

最後はPipenvのソースを読むしかありません。

pipenv installを実行した時に実際にpip install ...コマンドを実行している場所を見てみましょう。

実際にpipコマンドを実行している箇所はpipenv/core.py内のpip_installという関数でした。
呼び出される順番としてdo_install -> do_init -> do_install_dependencies -> batch_install -> pip_installとまあ色々有りましたが、、、
結論だけいうとbatch_install関数内の以下の箇所で--no-depsのオプションを付けるか否かのフラグが設定されていました。

        if not PIPENV_RESOLVE_VCS and is_artifact and not dep.editable:
            install_deps = True 
            no_deps = False

depってのはインストールするモジュールの情報が入ったクラスです。
PIPENV_RESOLVE_VCSじゃなくて、is_artifactで、モジュールがeditableじゃなくて、、、

さっぱりわからん

なんとなく「ソースからインストールするモジュールでeditableのフラグが付いていないもの」が--no-depsの付与に関係してそうですね。
pipenv install -hしたらこんなものがありました。

$ pipenv install -h
略
  -e, --editable TEXT      An editable python package URL or path, often to a
                           VCS repo.

あ、、、

解決

エラーの原因となったPipfileをもう一度見てみましょう。

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

[dev-packages]
flake8 = "*"
autopep8 = "*"
isort = "*"
autoflake = "*"
pytest = "*"
pytest-cov = "*"
qiitacli = {path = "."}
twine = "*"
sphinx = "*"
sphinx-git = "*"
pypandoc = "*"

[packages]
click = ">=7.0"
qiita_v2 = ">=0.2.1"

[requires]
python_version = "3"

[scripts]
main = "python qiitacli/client.py"

はい原因は

qiitacli = {path = "."}

こいつでしたね。

開発中のモジュールをローカルにインストールするときによくpipenv install .とかしてたんですがこれが問題でした。
正しくはpipenv install -e .こう。その結果できたPipfileがこう。

qiitacli = {editable = true,path = "."}

editableフラグが付いてますね。

この状態なら正常にインストールが完了しました。

まとめ

これ昔はちゃんと-eオプション付けて入れてたんですけど、オプションなくてもインストール出来ることに気がついてからはそのままインストールするようにしちゃってました。(多分)

ちなみに公式のドキュメントにもしっかり書いてありました。 https://pipenv-ja.readthedocs.io/ja/translate-ja/basics.html#editable-dependencies-e-g-e

せめて使ってるオプションの意味くらいは理解しようね。自分。

23
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
14