記事の内容
Mac及びWindows10で、Pyinstallerを使ってPythonコードから生成した実行ファイルを動かしたら、ModuleNotFoundErrorが発生しました。それを回避した時の記録です。
手順
以下のように、Pyinstallerを使ってPythonコードから実行ファイルを生成しました。pipenvを使用しています。
pipenv run pyinstaller foo.py --onefile
実行ファイルがdistディレクトリ配下に生成されましたので、以下のように動かしました。
./dist/foo
実行時エラーが発生しました。
Macでのエラーメッセージ:
Traceback (most recent call last):
File "site-packages/PyInstaller/loader/rthooks/pyi_rth_pkgres.py", line 13, in <module>
File "/Users/username/.local/share/virtualenvs/foo_project-dA2KfCBr/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages/pkg_resources/__init__.py", line 86, in <module>
ModuleNotFoundError: No module named 'pkg_resources.py2_warn'
[5125] Failed to execute script pyi_rth_pkgres
Windowsでのエラーメッセージ:
Traceback (most recent call last):
File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module>
File "c:\users\username\.virtualenvs\foo_project-uuzswlzx\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\pkg_resources\__init__.py", line 86, in <module>
ModuleNotFoundError: No module named 'pkg_resources.py2_warn'
[14256] Failed to execute script pyi_rth_pkgres
対処方法です。
まず、最初にpyinstallerを動かしたときに.specファイルも生成されていますので、それをテキストエディタで編集します。
ModuleNotFoundErrorと言われてしまったモジュールを、以下のようにhiddenimportsに書き加えます。
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['foo.py'],
pathex=['/Users/username/PycharmProjects/n/foo_project'],
binaries=[],
datas=[],
- hiddenimports=[],
+ hiddenimports=['pkg_resources.py2_warn'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='foo',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )
以下のように、編集した.specファイルを使用して再びpyinstallerを起動します。
pipenv run pyinstaller foo.spec --onefile
実行ファイルが生成されましたので、以下のように動かしたら、うまく動きました。
./dist/foo
エラーメッセージの意味(想像)
エラーメッセージ内に、以下の内容が含まれていました。
exec(bytecode, module.__dict__)
私の想像ですが、pyinstallerが生成した実行ファイルでは、人がpipenv installでインストールしたモジュールが、exec関数が動かすコードに引き継がれないのだと思います。
exec関数が動かすコード用に、モジュールを.specファイルのhiddenimportsに指定しておく必要があるのでしょう。