Détermination du chemin de l'application dans un fichier EXE Python généré par pyInstaller
-
03-07-2019 - |
Question
J'ai une application qui réside dans un seul fichier .py. J'ai réussi à obtenir que pyInstaller l'intègre correctement dans un fichier EXE pour Windows. Le problème est que l’application nécessite un fichier .cfg qui est toujours placé directement à côté de l’application dans le même répertoire.
Normalement, je construis le chemin en utilisant le code suivant:
import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)
Cependant, il semble que sys.path est vide lorsqu'il est appelé depuis un fichier EXE généré par pyInstaller. Ce même problème se produit lorsque vous exécutez la ligne de commande interactive python et essayez d’extraire sys.path [0].
Existe-t-il un moyen plus concret d’obtenir le chemin de l’application en cours afin que je puisse trouver les fichiers qui lui sont relatifs?
La solution
J'ai trouvé une solution. Vous devez vérifier si l'application s'exécute en tant que script ou en tant qu'exe figé:
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)
Autres conseils
Selon la documentation de pyInstaller, la méthode suggérée. de récupération du chemin de l’application est la suivante:
#!/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__))
Testé pour pyInstaller v3.2, mais cela fonctionne certainement aussi pour les versions précédentes.
La solution de Soviut ne fonctionne pas, du moins pas en général pour les versions récentes de pyInstaller (notez que l'OP a de nombreuses années). Par exemple, sous MacOS, lorsque vous associez une application à un ensemble de fichiers unique, sys.executable
pointe uniquement sur l'emplacement de l'archive incorporée, qui est pas . où l'application est réellement exécutée après que le chargeur d'amorçage pyInstaller a créé un environnement d'application temporaire. Seul sys._MEIPASS
pointe correctement vers cet emplacement. Référez-vous à cette doc-page pour plus d'informations sur le fonctionnement de pyInstaller.
J'ai raccourci le code un peu.
import os, sys
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
os.chdir(application_path)
logging.debug('CWD: ' + os.getcwd())
Mais sys._MEIPASS
a indiqué un mauvais répertoire. Je pense qu'il faut aussi sys._MEIPASS
+ \ nom_app
os.path.dirname(sys.argv[0])
Cela fonctionne pour moi.
__ fichier __
fonctionne en ligne de commande avec un exécutable python. Il donne également le nom du fichier de script sans le chemin réel en mode figé. Cependant, cela donne une erreur en mode interactif.
Ce qui suit fonctionnera pour les trois modes:
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)
Sortie dans trois modes différents:
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>
Beaucoup de réponses ici mais j'ai trouvé cette solution fonctionne dans la plupart des situations:
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)