PyInstallerとは
PyInstallerは、作成したPythonスクリプト(.py)を実行ファイル(.exe)に変換することができる優れものツールです。実際に私が経験した実用例としては、
『共同研究先(Python環境無し)で、Pythonで作製した自動解析ツールを使用したい』
という、楽したい願望を叶えるための優秀なツールでした。本記事では、PyInstallerを使用したい、けどエラーを吐いてしまって、、、どうすればいいの、、、、と路頭に迷っている人に助け船を出すことを目的としています。PyInstallerの使い方は、実際に私が参考にした以下の記事らを見てみてください。
ここでは、実際に私がハマった3つのエラーをひとつずつ、どうやって回避したのかについて説明していきます。エラーの原因等について、そこをはっきりさせることが目的ではなく、あくまでPyInstallerを使用してexeファイルを生成することが目的なので、エラーの原因等については深く考察しません。詳しく知りたければ英語でggってください。
ハマった3つのエラー
- そもそもPyInstallerがインストールできない
- exeファイル実行時にexec関数が動かない(
ModuleNotFoundError: No mudule named 'pkg_resources.py2_warm'. [8352] Failed to execute script pyi_rth_pkgres
) - よくわからん(
qt.qpa.plugin: Could not find the Qt platform plugin "windows" in "". This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
)
環境
Windows 10
Anaconda3 4.8.2
Python 3.6.5
PyInstaller 3.6
1.『そもそもPyInstallerがインストールできない』問題
これは非常に苦労しました。結論から言いますと、解決しませんでした。このエラーにはまっている人たちで、解決している人をほとんど見かけていません。かなり脱出するのが困難な沼です。
インストールするコマンド
pip install pyinstaller
(こっちがレコメンドされています、でも最終的にinstallするときに使用したのはconda install pyinstaller
でした、どっちがいいかは試してみてください、もしanacondaで環境構築をしているのであれば、後者がおすすめです)
どんなエラーが発生したのか?
この時のエラー内容をメモっていなくて、、、、ざっくり覚えているのが、『setuptools』がかなり悪い動きをした、ということです(satisfies the requirement setuptools
といったような感じの内容)
打開策
最終的に、インストールができています現在進行形nowです。さて、どうやったのでしょう。
- 1st try: anacondaのupdate
GitHubでも深く話されていたりします(調べるとホイホイ出てきます)、その中でも、このエラーを回避するためにはconda update
が有効だという旨の投稿を目撃しました、updateしましたがダメでした(update使用にも、すでに入っているsetuptoolsがanacondaと深く結びついていて、setuptoolsを切り離してupdate等を実施することができない) - 2nd try: wheelとsetuptoolsのインストール
これはどちらの記事に書かれていたのか忘れてしまいましたが、満足するsetuptoolsがないのならいれてやれ、ということでやってみたやつ。何の成果も得られませんでしたァァァアア!!! - Final try: conda create new_env
はい。これがインストールできないエラーを回避するに至った、最終奥義でした。
何をしたかって、新しく仮想環境を立ち上げたんです。立ち上げた先で、conda install pyinstaller
しました。
(詳しく話すと、当面はPyInstallerをインストールすることは諦めていました。あがいたってエラー回避できないし、仕事進まないし。その場その場で、バッチファイルで対応していました。業務を進めていく中、全然関係ないところでseabornのupdateが必要になりました。しかしところがどっこい、updateできないんですね。環境が汚すぎて。汚いっていうのは、pipとcondaが入り混じっているのです。環境としては崩壊してますね。
そこで、condaだけで環境を構築し直そう(dockerはwindowsだとまだ面倒くさそうなので止めた)と仮想環境を新たに立ち上げましたconda create --name makeexe python==3.6
。この段階では、pip install pyinstaller
は成功しませんでした。もしかしたら、Anaconda環境にpipでpyinstallerは入れられないのかもしれません。最低限必要なパッケージをインストールしました(conda install numpy pandas seaborn matplotlib tqdm opencv pillow
)。その後、ふと思い立ってpyinstallerをconda経由でインストールconda install pyinstaller
してみたところ、スッと入ったのです。嗚呼、いとをかし。)
結局何が問題だった?
詳細は分かりませんが、Anaconda環境にpip経由で入れることがそもそもの間違いだったのかなと思います。結果論ですが。conda環境にpipを混ぜるな、環境破壊禁止ってことですね。身をもって痛感しました。可能な限り、インストールしたいライブラリがcondaでできるかどうか、ちゃんと確認しましょう。できるのなら、そっちでやりましょう。その方が無難です。
2.『exeファイル実行時にexec関数が動かない』問題
PyInstaller実行コマンド
まず、PyInstallerのインストールには成功し、実行することもできました。PyInstallerを適用したい(exeファイル化したい)ディレクトリに移動した後に、以下のコマンドでexeファイル化を実行します(--onefile
で、モジュールらを一つのexeファイルにまとめる;出力ファイルがexeファイルのみになる)。
$ cd ~~~ # main.pyが置いてあるディレクトリに移動
$ pyinstaller main.py --onefile
このときのディレクトリの構成は以下のようになっています。Pyinstallerを実行することで、新たにbuild
とdist
の2つのディレクトリが生成され、dist/main.exe
と実行ファイルが生成されています。これをWクリックすることで、main.pyのプログラムが実行されます。まぁ、エラーを吐くんですけどね。ハハッ
./
|
|- main.py (作成したプログラム)
|- config.json (main.pyで読み込むconfigファイル)
|- main.spec(pyinstallerで作成されたもの)
|- main.exe(pyinstallerでdistディレクトリ内に作成されたもの、コードの都合上configと同じディレクトリ上に設置)
|- dist/
| |- main.exe
|
|- build/
|- main/
|- ~~~
どんなエラーが発生したか?
生成したmain.exe
を実行すると、以下のようなエラーを吐きました。
Traceback (most recent call last):
File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module>
File "C:\ProgramData\Anaconda3\envs\(venv you made)\lib\site-packages\PyInstaller\loader\pyimod03_iimporters,py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\pkg_resources\__init__.py", line 86, in <module>
ModuleNotFoundError: No mudule named 'pkg_resources.py2_warm'
[8352] Failed to execute script pyi_rth_pkgres
exec
が実行できません、実行するために必要なpkg_resources.py2_warm
が無いって喚いてます。
解決策
こちらを参考に、PyInstaller実行時に生成されたmain.spec
ファイル内のhiddenimports
に、ModuleNotFoundError
と言われたモジュールを書き加える。
- hiddenimports=[],
+ hiddenimports=['pkg_resources.py2_warn'],
そして、このspecファイルを使用して再度PyInstallerでexeファイルを作成します(このとき、先ほど生成されたファイル群はspecファイル以外は捨てちゃって問題ないです、ってか捨てましょう、エラーとか上書きどうするだとかの問題の種になります)。以下のコマンドで実行します。
pyinstaller main.spec --onefile
これで、execモジュールに関するエラーは吐かなくなります。
3.『よくわからんけど吐いた問題』問題
先ほどのmain.spec
ファイルを使用する方法で、execモジュールに関するエラーは回避できました。しかし、実行していると、まだエラーを吐きました。どんなエラーだったのか、見てみましょう。ちなみにボクは、語彙が無さ過ぎるのでこれを『よくわからんエラー』を呼称しています。うーん、わかりやすい。
どんなエラーが発生したか?
C:\ProgramData\Anaconda3\envs\(venv you made)\lib\site-packages\PyInstaller\loader\pyimod03_iimporters,py:623:MatplotlibDeprecationWarning:
THEMATPLOTLIBDATA environment variable was deprecated in Matplotlib 3.1 and will be removed in 3.3.
exec(bytecode, module.__dict__)
2020/03/27 10:29:55 - complete to load config.json (ここからはプログラム内での意図的な出力)
~(中略)~
2020/03/27 10:30:14 - success affine transforming.
qt.qpa.plugin: Could not find the Qt platform plugin "windows" in ""
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
最初のメッセージは、同じくexecによるものです、hiddenimport
に設定し対処済みなのでスルーでおk。
次は、プログラムの進捗状況をアナウンスするための物だからおk(プログラム内で意図的に吐かせているメッセージです)。Affine変換まで実施した辺りで、qt.qpa.plugin
に関する新たなエラーが発生。プラットフォームがインストールできませんだとかなんだとか。何が起こってるのかよくわかりません。
解決策
stackoverflowに寄せられていた質問の回答にあったのが、一部抜粋すると、
There seem to be two solutions, the first one worked fine for me:
- copy platform directory to directory of your executable. You'll find the platform directory at a location like
c:\Users\<username>\envs\<environmentname>\Library\plugins\platforms
or- Upgrade to a newer version of pyqt: conda install -c anaconda pyqt
Use the second option with care: Do not try to use pip for pyqt installation if you have a conda environment,
this might break your conda installation: https://github.com/ContinuumIO/anaconda-issues/issues/1970
と、
I had an issue where my python code worked fine, but the compiled .exe file would provide the
"could not find or load the Qt platform plugin windows" problem.
I fixed the problem by copying the
~PyQt5\Qt\plugins\platforms
folder from the program's directory,
generated by using pyinstaller --onedir main.py, to the folder holding the .exe file.It seems that in my case the only way "helping" my program detect the required .dlls was having the platforms folder next to the main.exe.
Pasting the platforms folder to the program's directory after using pyinstaller --onefile main.py also makes the program work.
です。さすがstackoverflowですね。解決したいことに対する答えがもう出ている。素晴らしい。
まず、お手頃に試せそうなものとして、pyqt
のインストールをしてみました。コマンドは、
conda install -c anaconda pyqt
だがしかし改善せず。どうしたstackoverflow。こんなもんか?と詰める隙も与えてくれません、次のアイデアは既に描かれているのです、あぁ、stackoverflowには勝てない。
で、そのもう一つの手法としておすすめされている、platformディレクトリのコピーを行いました。platformは、「C:\ProgramData\Anaconda3\envs(venv you made)\Library\plugins\platforms」にあります(自分の場合、人によって違うかも、stackoverflowでの回答内でもまた違うパスでしたね)。
このplatforms
ディレクトリを、実行したいexeファイルと同じディレクトリにコピーします。
つまり、最終的にこんなフォルダ構成になります⇓
./
|
|- main.py (作成したプログラム)
|- config.json (main.pyで読み込むconfigファイル)
|- main.spec(pyinstallerで作成され、hiddeninportsに'pkg_resources.py2_warn'を追加したもの)
|- main.exe(pyinstallerでdistディレクトリ内に作成されたもの、コードの都合上configと同じディレクトリ上に設置)
|- platforms/(コピーしてここに貼り付ける)
| |
| |- qdirect2d.dll
| |- qminimal.dll
| |- qoffscreen.dll
| |- qwebgl.dll
| |- qwindows.dll
|- dist/
| |- main.exe
|
|- build/
|- main/
|- ~~~
この状態でexeファイルを実行(リビルドの必要は無いはず)すると、最後まで正常にexeファイルが実行されます!!!!
もしexeファイルがエラー吐いたら、再度ビルドしなおしてみてください。
終わりに
PyInstallerを使用したいのにエラーが発生する、いろんなエラーが発生すると思います。それらのエラーをまとめてくれている記事ってないんですよね。よく分からず振り回されました。で、結局根本的な打開策がconda install
の使用だったって。よくわかりませんね。
でも、PyInstallerは有用です。世の中にはネットから切り離されているためPythonはもちろん、プログラム言語をinstallできないPC(も脳みそも)存在するので。しかし、これの欠点としては生成されるexeファイルが非常に重いことですかね。少なくとも、スクリプトと違ってメールで気楽に送ることはできません。
まだまだいろいろなエラーがあると思います。ぜひ、この記事を利用してください。コメント欄に書いてくだされば、そのエラーの対処法もまたこの記事に追加します。PyInstallerエラー対策マニュアルをみんなで作りたいですね。
よんでいただきありがとうございました。ばいばいっ