Domanda

Ho un'applicazione che risiede in un singolo file .py. Sono stato in grado di ottenere pyInstaller per raggrupparlo con successo in un EXE per Windows. Il problema è che l'applicazione richiede un file .cfg che si trova sempre accanto all'applicazione nella stessa directory.

Normalmente, costruisco il percorso usando il seguente codice:

import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)

Tuttavia, sembra che sys.path sia vuoto quando viene chiamato da un EXE generato da pyInstaller. Questo stesso comportamento si verifica quando si esegue la riga di comando interattiva di Python e si tenta di recuperare sys.path [0].

Esiste un modo più concreto per ottenere il percorso dell'applicazione attualmente in esecuzione in modo da poter trovare i file relativi ad essa?

È stato utile?

Soluzione

Ho trovato una soluzione. Devi verificare se l'applicazione è in esecuzione come script o come exe congelato:

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)

Altri suggerimenti

Secondo la documentazione di pyInstaller, il metodo suggerito del recupero del percorso dell'applicazione è il seguente:

#!/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__))

Testato per pyInstaller v3.2, ma sicuramente ha funzionato anche per le versioni precedenti.

La soluzione di Soviut non funziona, almeno non in generale per le recenti versioni di pyInstaller (si noti che l'OP ha molti anni). Ad esempio, su MacOS, quando si raggruppa un'applicazione in un pacchetto di un file, sys.executable punta solo alla posizione dell'archivio incorporato, che è non la posizione dove l'applicazione viene effettivamente eseguita dopo che il bootloader pyInstaller ha creato un ambiente applicativo temporaneo. Solo sys._MEIPASS punta correttamente a quella posizione. Fare riferimento a questa pagina dei documenti per ulteriori informazioni su come funziona pyInstaller.

Ho abbreviato un po 'il codice.

import os, sys

if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
    os.chdir(application_path)

logging.debug('CWD: ' + os.getcwd())

Ma sys._MEIPASS indicava una directory sbagliata. Penso che abbia bisogno anche di sys._MEIPASS + \app_name

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

Questo funziona per me.

__file__ funziona dalla riga di comando con eseguibile python. Fornisce inoltre il nome del file di script senza percorso effettivo in modalità bloccata. Tuttavia, genera un errore in modalità interattiva.

Quanto segue funzionerà per tutte e tre le modalità:

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)

Output in tre diverse modalità:

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>

Molte risposte qui, ma ho scoperto che questa soluzione funziona nella maggior parte dei casi:

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top