web-dev-qa-db-fra.com

Détermination du chemin de l'application dans un fichier EXE Python généré par pyInstaller

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 se trouve toujours 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é à partir d'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 le concernent?

42
Soviut

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)
79
Soviut

Selon la documentation de pyInstaller, la méthode de récupération du chemin d’application suggérée 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 le PO a plusieurs 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 intégrée, qui est not l'emplacement où l'application est réellement exécutée après que le chargeur de démarrage pyInstaller a créé un fichier. environnement d'application temporaire. Seul sys._MEIPASS pointe correctement vers cet emplacement. Reportez-vous à cette page de documentation pour plus d'informations sur le fonctionnement de pyInstaller.

16
normanius

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 + \app_name

5
Polv
os.path.dirname(sys.argv[0])

Ça marche pour moi.

3
user1986021

__file__ fonctionne à partir de la 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>
0
Rafiq

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)
0
dashesy