Как я могу получить исполняемый текущий каталог в py2exe?

Я использую этот бит кода в своем script, чтобы указать кросс-платформенным способом, где именно он выполняется:

SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

Довольно просто. Затем я продолжаю использовать SCRIPT_ROOT в других областях моего script, чтобы убедиться, что все правильно относительное. Моя проблема возникает, когда я запускаю ее через py2exe, потому что сгенерированный исполняемый файл не устанавливает __file__, поэтому мой script ломается. Кто-нибудь знает, как исправить или обойти это?

Ответ 1

Вот ссылка py2exe документации и вот соответствующие пункты:

  • sys.executable установлен полный путь к файлу exe.
  • Первый элемент в sys.argv - это полный путь к исполняемому файлу, остальные - аргументы командной строки.
  • sys.frozen существует только в исполняемом файле. Он имеет значение "console_exe" для исполняемого файла консоли, "windows_exe" для исполняемого файла без консоли и для "dll" для сервера inprocess dll.
  • __file__ не определен (вместо этого вы можете использовать sys.argv [0])

Из этих документов неясно, являются ли "exe файл" и "исполняемый" одним и тем же, и, таким образом, то же самое: sys.executable и sys.argv[0]. Глядя на код, который работал как для script.py, так и py2exe_executable.exe в прошлый раз, я должен был сделать это, я нахожу что-то вроде:

if hasattr(sys, 'frozen'):
    basis = sys.executable
else:
    basis = sys.argv[0]
required_folder = os.path.split(basis)[0]

Как я уже сказал, это сработало, но я не помню, почему я думал, что это необходимо, а не просто используя sys.argv[0].

Использование только basis было адекватным для выполняемого задания (чтение файлов в этом каталоге). Для более постоянной записи разделите что-то вроде os.path.realpath(basis).

Обновление Фактически прошел тест; бьет догадку и позолоченность кресла: -)

Резюме: игнорировать sys.frozen, игнорировать sys.executable, переходить с sys.argv [0] безоговорочно.

Доказательства:

=== foo.py ===

# coding: ascii
import sys, os.path
print 'sys has frozen:', hasattr(sys, 'frozen')
print 'using sys.executable:', repr(os.path.dirname(os.path.realpath(sys.executable)))
print 'using sys.argv[0]:',    repr(os.path.dirname(os.path.realpath(sys.argv[0]   )))

=== setup.py ===

from distutils.core import setup
import py2exe
setup(console=['foo.py'])

=== результаты ===

C:\junk\so\py2exe>\python26\python foo.py
sys has frozen: False
using sys.executable: 'C:\\python26'
using sys.argv[0]: 'C:\\junk\\so\\py2exe' # where foo.py lives

C:\junk\so\py2exe>dist\foo
sys has frozen: True
using sys.executable: 'C:\\junk\\so\\py2exe\\dist'
using sys.argv[0]: 'C:\\junk\\so\\py2exe\\dist' # where foo.exe lives

Ответ 2

Py2exe не определяет __file__: http://www.py2exe.org/index.cgi/Py2exeEnvironment

OP запросил дружественную версию py2exe:

SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

Лучший ответ - определить, заморожен ли python в exe, py2exe имеет документацию по этому вопросу: http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe

import imp, os, sys

def main_is_frozen():
   return (hasattr(sys, "frozen") or # new py2exe
           hasattr(sys, "importers") # old py2exe
           or imp.is_frozen("__main__")) # tools/freeze

def get_main_dir():
   if main_is_frozen():
       return os.path.dirname(sys.executable)
   return os.path.dirname(os.path.realpath(__file__))

SCRIPT_ROOT = get_main_dir()

Так как python EAFP, здесь EAFP версия...

try:
   if sys.frozen or sys.importers:
      SCRIPT_ROOT = os.path.dirname(sys.executable)
except AttributeError:
   SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

Ура!

Ответ 3

Попробуйте следующее:

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

Ответ 4

sys.argv[0] - это надежный способ получить путь, так как он даст тот же результат независимо от того, выполняется ли он как скрипт или исполняемый файл. Получить каталог os.path.dirname(sys.argv[0])

comparison between file and exe