作業中のメモ

よく「計算機」を使って作業をする.知らなかったことを中心にまとめるつもり.

Python Script を実行形式(exe 形式)に変換

どうも,筆者です. 今回は,Python Script を Windows で動作する exe 形式に変換する手順を説明する.

動作環境

利用した OS,Python のバージョンを以下に示す.

pyinstaller のインストール

Python Script を exe 形式に変換するため,pyinstaller をインストールする.コマンドプロンプトに以下のコマンドを入力する.

python -m pip install pyinstaller

以下のコマンドを入力し,バージョンを確認しておく.筆者の環境では,3.3.1 となった.

pyinstaller -v

exe 形式に変換

今回は,以下のような Python Script を exe 形式に変換する.この Python Script は,動作確認用に作成したものである.ここでは,test.py という名前で保存した.

#!/usr/bin/env python
# -*- coding: shift-jis -*-

import tkinter
from tkinter import filedialog as dialog
from tkinter import messagebox as msgbox
import os, sys

# ディレクトリ名とファイル名に分割
def splitFilePath(fileName):
    dirName = os.path.dirname(fileName)
    baseName = os.path.basename(fileName)

    return dirName, baseName

# ファイルダイアログを開き、対象のファイルのパスを取得
def getTargetFileName():
    # 現在のディレクトリを取得
    currentDir = os.getcwd()
    # ダイアログを開き、フルパスを取得
    fileName = dialog.askopenfilename(title="Choose file", initialdir=currentDir)

    if fileName is None or fileName == '':
        baseName = ''
    else:
        # ファイル名のみ抽出
        _, baseName = splitFilePath(fileName)

    return baseName

# ファイルの存在確認と拡張子の確認
def chkFilePath(filePath):
    # 以下の 2 点を確認
    # 1.指定されたパスのファイルが存在するか
    # 2.対象とする拡張子か
    targetExtensionList = ['txt', 'csv'] # 対象とする拡張子のリスト

    if filePath == '':
        return False

    # ファイルの存在確認
    if not os.path.exists(filePath):
        # 存在しない場合
        outMsg = '以下のファイルが存在しません\n%s' % filePath
        msgbox.showinfo('Error', outMsg)
        return False
    else:
        # 拡張子の確認
        _, ext = os.path.splitext(filePath)

        if ext[1:] not in targetExtensionList:
            joinExt = ', '.join(map(lambda x: '.%s' % x, targetExtensionList))
            outMsg  = '対象の拡張子ではありません: %s\n対象の拡張子: %s' % (ext, joinExt)
            msgbox.showinfo('Error', outMsg)
            return False
        else:
            return True

def execution(inputFilePath):
    dirName, baseName = splitFilePath(inputFilePath)
    outputFilePath = os.path.join(dirName, 'out_' + baseName)

    with open(outputFilePath, 'w') as fout:
        for line in open(inputFilePath, 'r'):
            data = line.replace('\n', '')
            fout.write(data + '\n')

def main():
    argv = sys.argv
    argc = len(argv)
    useFilePath = ''

    # GUI の初期設定
    rootTk = tkinter.Tk()
    rootTk.withdraw()

    if argc < 2:
        useFilePath = getTargetFileName()
    else:
        useFilePath = argv[1]

    if chkFilePath(useFilePath):
        # 処理を実行
        useFullPath = os.path.abspath(useFilePath)
        execution(useFullPath)

if __name__ == '__main__':
    main()

Python Script を exe 形式に変換するには,コマンドプロンプトに以下のコマンドを入力する.

rem icon をつけない場合
pyinstaller --onefile --clean --noconsole test.py
rem icon をつける場合
rem 同一フォルダに test.ico を配置しておく必要がある.
pyinstaller --onefile --clean --noconsole --add-binary test.ico;. --icon=test.ico test.py

実行すると,以下のようなログが表示される.最後に successfully が表示されていれば変換完了である.なお,exe ファイルは dist フォルダ以下に生成される.

62 INFO: PyInstaller: 3.3.1
62 INFO: Python: 3.6.4
62 INFO: Platform: Windows-7-6.1.7601-SP1
62 INFO: wrote path\test.spec
62 INFO: UPX is not available.
62 INFO: Removing temporary files and cleaning cache in userPath\AppData\Roaming\pyinstaller
93 INFO: Extending PYTHONPATH with paths
['path\\test', 'path\\test']
93 INFO: checking Analysis
93 INFO: Building Analysis because out00-Analysis.toc is non existent
93 INFO: Initializing module dependency graph...
93 INFO: Initializing module graph hooks...
109 INFO: Analyzing base_library.zip ...
2683 INFO: running Analysis out00-Analysis.toc
2683 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable
  required by userPath\AppData\Local\Programs\Python\Python36\python.exe
3229 INFO: Caching module hooks...
3229 INFO: Analyzing path\test.py
3369 INFO: Loading module hooks...
3369 INFO: Loading module hook "hook-encodings.py"...
3447 INFO: Loading module hook "hook-pydoc.py"...
3447 INFO: Loading module hook "hook-xml.py"...
3634 INFO: Loading module hook "hook-_tkinter.py"...
3759 INFO: checking Tree
3759 INFO: Building Tree because out00-Tree.toc is non existent
3759 INFO: Building Tree out00-Tree.toc
3822 INFO: checking Tree
3822 INFO: Building Tree because out01-Tree.toc is non existent
3822 INFO: Building Tree out01-Tree.toc
3853 INFO: Looking for ctypes DLLs
3853 INFO: Analyzing run-time hooks ...
3853 INFO: Including run-time hook 'pyi_rth__tkinter.py'
3853 INFO: Looking for dynamic libraries
4024 INFO: Looking for eggs
4024 INFO: Using Python library userPath\AppData\Local\Programs\Python\Python36\python36.dll
4024 INFO: Found binding redirects: 
[]
4024 INFO: Warnings written to path\build\test\warntest.txt
4056 INFO: Graph cross-reference written to path\build\test\xref-test.html
4087 INFO: checking PYZ
4087 INFO: Building PYZ because out00-PYZ.toc is non existent
4087 INFO: Building PYZ (ZlibArchive) path\build\test\out00-PYZ.pyz
4508 INFO: Building PYZ (ZlibArchive) path\build\test\out00-PYZ.pyz completed successfully.
4508 INFO: checking PKG
4508 INFO: Building PKG because out00-PKG.toc is non existent
4508 INFO: Building PKG (CArchive) out00-PKG.pkg
4804 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\python36.dll
4804 INFO: Updating resource type 24 name 2 language 1033
5413 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_ssl.pyd
5413 INFO: Updating resource type 24 name 2 language 1033
5569 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\unicodedata.pyd
5569 INFO: Updating resource type 24 name 2 language 1033
5584 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\pyexpat.pyd
5584 INFO: Updating resource type 24 name 2 language 1033
5616 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_hashlib.pyd
5616 INFO: Updating resource type 24 name 2 language 1033
5662 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_bz2.pyd
5662 INFO: Updating resource type 24 name 2 language 1033
5678 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_lzma.pyd
5678 INFO: Updating resource type 24 name 2 language 1033
5694 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_socket.pyd
5694 INFO: Updating resource type 24 name 2 language 1033
6037 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\select.pyd
6037 INFO: Updating resource type 24 name 2 language 1033
6084 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\_tkinter.pyd
6084 INFO: Updating resource type 24 name 2 language 1033
6130 INFO: Updating manifest in userPath\AppData\Roaming\pyinstaller\bincache00_py36_64bit\tk86t.dll
6130 INFO: Updating resource type 24 name 1 language 1033
8814 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully.
8829 INFO: Bootloader userPath\AppData\Local\Programs\Python\Python36\lib\site-packages\PyInstaller\bootloader\Windows-64bit\runw.exe
8829 INFO: checking EXE
8829 INFO: Building EXE because out00-EXE.toc is non existent
8829 INFO: Building EXE from out00-EXE.toc
8845 INFO: SRCPATH [('test.ico', None)]
8845 INFO: Updating icons from ['test.ico'] to userPath\AppData\Local\Temp\tmp1k39lqf2
8845 INFO: Writing RT_GROUP_ICON 0 resource with 20 bytes
8845 INFO: Writing RT_ICON 1 resource with 68578 bytes
8860 INFO: Appending archive to EXE path\dist\test.exe
8892 INFO: Building EXE from out00-EXE.toc completed successfully.