matplotlib
python3
PyInstaller
sklearn

Pyinstaller によるPython 3.6スクリプトのexeファイル化

サマリ

  • Sklearn, matplotlib等を利用したPythonスクリプトを Pyinstallerでexeファイル化した際のはまったポイントと対処方法の備忘録。

環境

  • MS Windows 10 Pro (32bit, 1709)
  • Anaconda3-5.0.1-Windows-x86.exe (Python 3.6.3)
  • pycharm-community-2017.3.2.exe

はまったポイント

  • Python3.6対応
  • Sklearn 対応
  • Multiprocessing 対応
  • Matplotlibを使ったグラフ描画 対応

詳細

Python3.6 対応

問題点

Python 3.6スクリプトをPyinstallerでコンパイルすると、下記メッセージがでて失敗する。

AttributeError: 'str' object has no attribute 'items'

対処方法

最新のPyinstaller 3.3.1 を導入。

pip install --upgrade pyinstaller

参照サイト

https://qiita.com/y-tsutsu/items/f687cf4b57442557aade
https://github.com/pyinstaller/pyinstaller/releases

Sklearn対応

問題点

Pyinstaller によるコンパイルは成功するものの、コンパイルしたexeファイルを実行すると、下記エラーメッセージが発生。

ModuleNotFoundError: No module named 'typedefs'
[7436] Failed to execute script myprog

対処方法

  • コンパイル --> exeファイル実行時エラーメッセージで出てきたmodule を myprog.spec のhiddenimports に追加 --> 再コンパイル、を繰り返す。
  • myprog.spec は 最初のコンパイル時に生成される。

※ より効率が良い方法もあるようだが、それではうまく行かなかった。

1回目 エラーメッセージ

  File "sklearn\neighbors\dist_metrics.pyx", line 52, in init sklearn.neighbors.dist_metrics
ModuleNotFoundError: No module named 'typedefs'
[7436] Failed to execute script myprog

2回目 エラーメッセージ

  File "sklearn\neighbors\quad_tree.pxd", line 54, in init sklearn.tree._tree
ModuleNotFoundError: No module named 'sklearn.neighbors.quad_tree'
[592] Failed to execute script myprog

3回目 エラーメッセージ

  File "sklearn\tree\_utils.pxd", line 78, in init sklearn.neighbors.quad_tree
ModuleNotFoundError: No module named 'sklearn.tree._utils'
[2732] Failed to execute script myprog

参考サイト

https://stackoverflow.com/questions/44136159/no-module-name-typedefs-when-use-pyinstaller

https://stackoverflow.com/questions/15114695/pyinstaller-import-error
より効率の良いやり方?
https://stackoverflow.com/questions/35478526/pyinstaller-numpy-intel-mkl-fatal-error-cannot-load-mkl-intel-thread-dll

Multiprocessing対応

問題

Multiprocessing.pool関数を用いたスクリプトをコンパイルし、実行しても以下のエラーがでて失敗する。

Error: no such option: --multiprocessing-fork

対処方法

  • UPX化 のDisable
  • Myprog.py に multiprocessing.freeze_support() を追加(下記まとめ myprog.py 参照)。

※ 参考サイトでは onefileの場合は上記対処だけでは無理と記述があったが、手元ではできた。

参考サイト

https://stackoverflow.com/questions/24944558/pyinstaller-built-windows-exe-fails-with-multiprocessing

Matplotlibを使ったグラフ描画

問題

Matplotlibを用いたグラフ描画スクリプトをコンパイルし、実行しても以下のエラーがでて失敗する。

This application failed to start because it could not find or load the Qt platform plugin "windows"
in "".

Reinstalling the application may fix this problem.

対処方法

  • PyQt5のインストール
# pip install PyQt5
Collecting PyQt5
  Using cached PyQt5-5.9.2-5.9.3-cp35.cp36.cp37-none-win32.whl
Collecting sip<4.20,>=4.19.4 (from PyQt5)
  Using cached sip-4.19.6-cp36-none-win32.whl
Installing collected packages: sip, PyQt5
Successfully installed PyQt5-5.9.2 sip-4.19.6

まとめ

myprog.py (一部抜粋)

  • Multiprocessing対応コードの追加
myprog.py
import multiprocessing
import sys

<メイン処理>

if __name__ == '__main__':
    if sys.platform.startswith('win'):
        # On Windows calling this function is necessary.
        multiprocessing.freeze_support()

    <メイン処理呼び出し>

myprog.spec

  • pyinstaller myprog.py で生成されたmyprog.specを修正。
  • Sklearn対応のため、実行時ModuleNotFoundErrorエラーがなくなるまで、hiddenimports にモジュールを追加。
  • Multiprocessing対応のため、upx=Falseとする。
myprog.spec
# -*- mode: python -*-

block_cipher = None

himports = [
    'cython', 'sklearn', 'sklearn.neighbors.typedefs', 'sklearn.neighbors.quad_tree', 'sklearn.tree._utils']

a = Analysis(['myprog.py'],
             pathex=['C:\\Users\\XXXXX\\PycharmProjects\\myprog'],
             binaries=[],
             datas=[],
             hiddenimports=himports,
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
          cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='myprog',
          debug=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=True)

コンパイル方法

pyinstaller myprog.spec