Pergunta

Eu tenho um aplicativo que reside em um único arquivo .py. Eu tenho sido capaz de obter pyInstaller para empacotá-lo com sucesso em um EXE para Windows. O problema é que o aplicativo requer um arquivo .cfg que sempre fica diretamente ao lado do aplicativo no mesmo diretório.

Normalmente, eu construir o caminho usando o seguinte código:

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

No entanto, parece que o sys.path é em branco quando a sua chamada de um EXE gerado pelo pyInstaller. Este mesmo comportamento ocorre quando você executar a linha de comando interativo do Python e tentar buscar sys.path [0].

Existe uma maneira mais concreta de obter o caminho do aplicativo em execução no momento para que eu possa encontrar arquivos que estão em relação a ele?

Foi útil?

Solução

Eu encontrei uma solução. Você precisa verificar se o aplicativo está sendo executado como um script ou como um exe congelados:

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)

Outras dicas

método

De acordo com a documentação de pyInstaller, a sugerida de recuperar caminho da aplicação é o seguinte:

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

Testado para pyInstaller v3.2, mas isso certamente tem trabalhado para versões anteriores também.

A solução da Soviut não funciona, pelo menos não em geral, para as versões recentes do pyInstaller (note que o OP é de muitos anos de idade). Por exemplo, no MacOS, quando empacotar um aplicativo em um arquivo-bundle, sys.executable pontos apenas na localização do arquivo incorporado, que é não o local onde o aplicativo realmente é executado após o bootloader pyInstaller criou um ambiente de aplicação temporária. Apenas sys._MEIPASS corretamente aponta para esse local. Consulte este doc-página para obter mais informações sobre como pyInstaller funciona.

Eu encurtou o código um pouco.

import os, sys

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

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

Mas, sys._MEIPASS apontou para um diretório errado. Eu acho que ele também precisa sys._MEIPASS + \app_name

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

que funciona para mim.

__file__ funciona a partir de linha de comando com executável python. Ele também dá o nome do arquivo script sem caminho real no modo congelado. No entanto, dá erro no modo interativo.

A seguir irá funcionar para todos os três modos:

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)

Saída em três modos diferentes:

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>

Muitas respostas aqui, mas eu achei essa solução funciona na maioria das situações:

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)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top