Определение пути приложения в Python EXE, сгенерированном pyInstaller - PullRequest
49 голосов
/ 01 января 2009

У меня есть приложение, которое находится в одном файле .py. Я был в состоянии заставить pyInstaller успешно связать его в EXE для Windows. Проблема в том, что приложению требуется файл .cfg, который всегда находится рядом с приложением в том же каталоге.

Обычно я строю путь, используя следующий код:

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

Однако, кажется, что sys.path пуст, когда его вызывают из EXE, сгенерированного pyInstaller. Такое же поведение возникает при запуске интерактивной командной строки python и попытке извлечь sys.path [0].

Есть ли более конкретный способ получить путь к запущенному в данный момент приложению, чтобы я мог найти файлы, относящиеся к нему?

Ответы [ 6 ]

86 голосов
/ 01 января 2009

Я нашел решение. Вам нужно проверить, работает ли приложение как скрипт или как замороженный 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)
22 голосов
/ 06 марта 2017

В соответствии с документацией 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, но это, безусловно, работало и для более ранних версий.

Решение Совиута не работает, по крайней мере, вообще не для последних версий pyInstaller (обратите внимание, что ОП уже много лет). Например, в MacOS при объединении приложения в пакет из одного файла sys.executable указывает только на местоположение встроенного архива, а это , а не место, где приложение фактически выполняется после pyInstaller загрузчик создал временную среду приложения. Только sys._MEIPASS правильно указывает на это место. Обратитесь к этой странице документа для получения дополнительной информации о том, как работает pyInstaller.

5 голосов
/ 21 декабря 2017

Я немного сократил код.

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

3 голосов
/ 17 января 2013
os.path.dirname(sys.argv[0])

Это работает для меня.

0 голосов
/ 26 апреля 2018

Здесь много ответов, но я обнаружил, что это решение работает в большинстве ситуаций:

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 голосов
/ 16 февраля 2018

__file__ работает из командной строки с исполняемым файлом Python. Это также дает имя файла сценария без фактического пути в замороженном режиме. Однако это дает ошибку в интерактивном режиме.

Следующее будет работать для всех трех режимов:

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)

Вывод в трех разных режимах:

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>
...