スポンサーリンク

【PyInstaller】exe実行時のパス取得でエラー

記事内に広告が含まれています。

作成したpythonのスクリプトをチームで共有するため、PyInstallerでexeを作成してみましたが、実行時にパスがうまく取得できないケースがありました。

原因

原因はスクリプトのファイルパスを取得する際に以下のpath1の記載を行っていたことで、path2の書き方に変更することで解消しました。

path1 = os.path.abspath(__file__)
path2 = os.path.abspath(sys.argv[0])

os.path.abspath は絶対パスを取得しています。path1の書き方をしているケースは多いかと思います。

動作確認

os.path.abspath の動作について確認してみます。環境は以下のとおりです。

  • Windows 10
  • Python 3.6.0
  • PyInstaller 3.6

pythonファイルの実行

以下の構成でプログラムを作成しました。

test
├── modules
│    └── test2.py
└── test1.py

test1.py、test2.pyの内容はそれぞれ以下のとおりです。両方のファイルでパス取得をしています。test1.pyにtest2.pyをインポートして関数を呼び出しています。

# test1.py
import os
import sys
import modules.test2 as t2

path1 = os.path.abspath(__file__)
path2 = os.path.abspath(sys.argv[0])

print('test2.py __file__   :', path1)
print('test2.py sys.argv[0]:', path2)

t2.print_path()
# test2.py
import os
import sys

def print_path():
    path1 = os.path.abspath(__file__)
    path2 = os.path.abspath(sys.argv[0])
    print('test2.py __file__   :', path1)
    print('test2.py sys.argv[0]:', path2)

test1.pyの実行結果は以下のとおりです。

D:\test>python test1.py
test1.py __file__   : D:\test\test1.py
test1.py sys.argv[0]: D:\test\test1.py
test2.py __file__   : D:\test\modules\test2.py
test2.py sys.argv[0]: D:\test\test1.py

os.path.abspath の引数が __file__ の場合、各pythonファイルの絶対パスが取得されています。一方、引数が sys.argv[0] の場合、実行ファイルの絶対パスが取得されています。

exeファイルの実行

続いて、exeファイルを作成し、実行してみます。

まず、PyInstallerをインストールします。

pip install pyinstaller

exeファイルを作成します。–onefile を付与することで、関連ファイルを1ファイルにまとめることができます。

D:\test>pyinstaller test1.py --onefile

distフォルダの下にexeファイルが作成されます。exeファイルを実行します。

D:\test\dist>test1.exe
test1.py __file__   : D:\test\dist\test1.py
test1.py sys.argv[0]: D:\test\dist\test1.exe
test2.py __file__   : C:\Users\name\AppData\Local\Temp\_MEI18322\modules\test2.pyc
test2.py sys.argv[0]: D:\test\dist\test1.exe

pythonファイル実行時とは異なる結果になりました。

引数が sys.argv[0] の場合、test1.pyでもtest2.pyでもexeファイルの絶対パスが取得されています。

一方、引数が __file__ の場合、test1.pyでは、ディレクトリはカレントディレクトリ(D:\test\dist)、ファイル名がtest.pyとなっています。test2.pyでは、exe実行時にスクリプトが展開される一時フォルダになっています。

sys.argv[0] を指定することでexeファイルのパス取得が可能です。

モジュール上(test2.py)では、そもそも os.path.abspath でのパスの判定はせず、パスが必要な場合は、呼び出し元ファイル(test1.py)でパスを判定して引数として渡すといった形式にした方がいいように思えました。

まとめ

pythonファイルからexeファイルを作成する場合、実行ファイルパスの取得方法は要注意です。exeファイルのパスを取得する場合は、os.path.abspath(sys.argv[0]) とする必要があります。

スポンサーリンク
Python
著者SNS
タイトルとURLをコピーしました