pyInstallerによって生成されたPython EXEでのアプリケーションパスの決定
-
03-07-2019 - |
質問
単一の.pyファイルにあるアプリケーションがあります。 pyInstallerをWindowsのEXEに正常にバンドルすることができました。問題は、アプリケーションが常に同じディレクトリ内のアプリケーションのすぐ横にある.cfgファイルを必要とすることです。
通常、次のコードを使用してパスを作成します:
import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)
ただし、pyInstallerによって生成されたEXEから呼び出されたsys.pathは空白のようです。 Pythonの対話型コマンドラインを実行してsys.path [0]をフェッチしようとすると、これと同じ動作が発生します。
現在実行中のアプリケーションのパスを取得して、それに関連するファイルを見つけるためのより具体的な方法はありますか?
解決
解決策を見つけました。アプリケーションがスクリプトとして実行されているか、凍結されたexeとして実行されているかを確認する必要があります。
import os
import sys
config_name = 'myapp.cfg'
# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
elif __file__:
application_path = os.path.dirname(__file__)
config_path = os.path.join(application_path, config_name)
他のヒント
pyInstallerのドキュメントによると、推奨される方法アプリケーションパスを回復する方法は次のとおりです。
#!/usr/bin/python3
import sys, os
if getattr(sys, 'frozen', False):
# If the application is run as a bundle, the pyInstaller bootloader
# extends the sys module by a flag frozen=True and sets the app
# path into variable _MEIPASS'.
application_path = sys._MEIPASS
else:
application_path = os.path.dirname(os.path.abspath(__file__))
pyInstaller v3.2でテスト済みですが、これは以前のバージョンでも確実に機能しています。
Soviutのソリューションは、少なくとも最近のバージョンのpyInstallerでは動作しません(OPは長年使用されていることに注意してください)。たとえば、MacOSでは、アプリケーションを1つのファイルバンドルにバンドルすると、 sys.executable
は、埋め込みアーカイブの場所のみを指します。これは、場所ではありません pyInstallerブートローダーが一時的なアプリケーション環境を作成した後、アプリケーションが実際に実行される場所。 sys._MEIPASS
のみがその場所を正しく指します。 このドキュメントページ pyInstallerの動作方法の詳細について
コードを少し短くしました。
import os, sys
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
os.chdir(application_path)
logging.debug('CWD: ' + os.getcwd())
しかし、 sys._MEIPASS
は間違ったディレクトリを指しています。 sys._MEIPASS
+ \ app_name
os.path.dirname(sys.argv[0])
それは私のために働く。
__ file __
は、Python実行可能ファイルを使用してコマンドラインから機能します。また、フリーズモードで実際のパスなしでスクリプトファイル名を提供します。ただし、対話モードではエラーになります。
以下は3つのモードすべてで機能します:
import sys,os
config_name = 'myapp.cfg'
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
running_mode = 'Frozen/executable'
else:
try:
app_full_path = os.path.realpath(__file__)
application_path = os.path.dirname(app_full_path)
running_mode = "Non-interactive (e.g. 'python myapp.py')"
except NameError:
application_path = os.getcwd()
running_mode = 'Interactive'
config_full_path = os.path.join(application_path, config_name)
print('Running mode:', running_mode)
print(' Appliction path :', application_path)
print(' Config full path :', config_full_path)
3つの異なるモードでの出力:
Running mode: Interactive
Appliction path : C:\Projects\MyAppDir
Config full path : C:\Projects\MyAppDir\myapp.cfg
C:\Projects\MyAppDir>myapp.exe
Running mode: Frozen/executable
Appliction path : C:\Program Files\myapp
Config full path : C:\Program Files\myapp\myapp.cfg
C:\Projects\MyAppDir>python myapp.py
Running mode: Non-interactive (e.g. 'python myapp.py')
Appliction path : C:\Projects\MyAppDir
Config full path : C:\Projects\MyAppDir\myapp.cfg
C:\Projects\MyAppDir>
多くの回答がここにありますが、このソリューションはほとんどの状況で機能することがわかりました:
import os
import sys
import os.path as op
try:
this_file = __file__
except NameError:
this_file = sys.argv[0]
this_file = op.abspath(this_file)
if getattr(sys, 'frozen', False):
application_path = getattr(sys, '_MEIPASS', op.dirname(sys.executable))
else:
application_path = op.dirname(this_file)