Bestimmen Anwendungspfad in einem Python EXE erzeugt durch pyInstaller
-
03-07-2019 - |
Frage
Ich habe eine Anwendung, die in einer Py-Datei befindet. Ich habe in der Lage pyInstaller, um es zu bündeln erfolgreich in eine EXE-Datei für Windows. Das Problem ist, erfordert die Anwendung eine CFG-Datei, die immer direkt neben der Anwendung im selben Verzeichnis befindet.
Normalerweise baue ich den Weg mit dem folgenden Code:
import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)
Es scheint jedoch, die sys.path leer ist, wenn sein aus einer EXE erzeugt durch pyInstaller genannt. Das gleiche Verhalten tritt auf, wenn Sie die interaktive Python-Kommandozeile aus und versuchen sys.path zu holen [0].
Gibt es eine konkrete Möglichkeit, den Pfad der gerade laufende Anwendung zu bekommen, so dass ich Dateien finden kann, die es bezüglich?
Lösung
ich eine Lösung gefunden. Sie müssen prüfen, ob die Anwendung als Skript ausgeführt wird oder als gefrorene 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)
Andere Tipps
Nach dem Dokumentation von pyInstaller, wobei das Verfahren vorgeschlagen Anwendungspfad zurückzugewinnen ist wie folgt:
#!/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__))
für pyInstaller v3.2 getestet, aber für frühere Versionen sicherlich wurde als gut funktioniert.
Soviut-Lösung funktioniert nicht, zumindest nicht im Allgemeinen für aktuelle Versionen von pyInstaller (beachten Sie, dass die OP viele Jahre alt ist). Zum Beispiel auf MacOS, wenn eine Anwendung in ein Ein-Datei-Bündel zu bündeln, sys.executable
Punkte nur auf den Standort des Archivs eingebettet, die nicht den Ort, an dem die Anwendung tatsächlich nach dem Bootloader pyInstaller läuft hat eine temporäre Anwendungsumgebung erstellt. Nur sys._MEIPASS
weist zu Recht auf diese Position. Siehe dieser doc-Seite für weitere Informationen darüber, wie pyInstaller funktioniert.
Ich verkürzte den Code ein bisschen.
import os, sys
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
os.chdir(application_path)
logging.debug('CWD: ' + os.getcwd())
Aber, wies sys._MEIPASS
auf ein falsches Verzeichnis. Ich denke, es muss auch sys._MEIPASS
+ \app_name
os.path.dirname(sys.argv[0])
Das ist für mich funktioniert.
__file__
arbeitet von der Kommandozeile mit Python ausführbar. Es gibt auch die Skriptdateinamen ohne tatsächlichen Pfad in gefrorenem Modus. Allerdings gibt es Fehler in den interaktiven Modus.
Im Folgenden wird für alle drei Modi arbeiten:
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)
Ausgabe in drei verschiedenen Modi:
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>
Viele Antworten hier, aber ich fand diese Lösung in den meisten Fällen funktioniert:
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)