py2exe и файловая система - PullRequest
       25

py2exe и файловая система

3 голосов
/ 02 октября 2009

У меня есть приложение на Python. Он загружает файлы конфигурации (и другие файлы) делать такие вещи, как:

_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = os.path.join(_path, 'conf')

Это отлично работает. Однако, когда я упаковываю приложение с py2exe, происходят плохие вещи:

  File "proj\config.pyc", line 8, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\
\dist\\library.zip\\conf'

Очевидно, что это неверный путь ... Какой более надежный способ сделать это? Я не хотите указать абсолютные пути в программе, потому что она может быть размещена в разных папки. Должен ли я просто сказать «если он говорит, что имя папки« library.zip », то перейдите еще один уровень вниз к папке 'dist' "?

Обратите внимание, что у меня есть довольно вложенные иерархии каталогов ... например, у меня есть модуль gui.utils.images, хранится в «gui / utils / images.py» и использует его путь например, для доступа к "gui / images / ok.png". Прямо сейчас версия py2exe будет пытаться получить доступ к "proj / dist / library.zip / gui / images / ok.png", или что-то, что просто не сработает.

Ответы [ 5 ]

10 голосов
/ 04 декабря 2009

Обычный подход к выполнению подобных вещей (если я правильно понимаю) заключается в следующем:

  1. проверьте sys.frozen, который py2exe умудряется установить, используя что-то вроде getattr (sys, 'frozen', '')
  2. если это не установлено, используйте обычный метод, так как вы запускаете из источника
  3. если он установлен, проверьте sys.executable, так как он укажет вам, где находится .exe (вместо того, где находится python.exe, на что он обычно указывает). Используйте что-то вроде os.path.dirname (sys.executable), а затем соедините его с вашими относительными путями, чтобы найти подпапки и т. Д.

Пример:

frozen = getattr(sys, 'frozen', '')

if not frozen:
    # not frozen: in regular python interpreter
    approot = os.path.dirname(__file__)

elif frozen in ('dll', 'console_exe', 'windows_exe'):
    # py2exe:
    approot = os.path.dirname(sys.executable)

elif frozen in ('macosx_app',):
    # py2app:
    # Notes on how to find stuff on MAC, by an expert (Bob Ippolito):
    # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html
    approot = os.environ['RESOURCEPATH']

Или какой-то другой вариант ... последний обрабатывает использование py2app. При необходимости вы можете расширить это для других строителей.

2 голосов
/ 15 апреля 2012

Вот мое решение (проверено на Windows, Linux и Mac). Это также работает, если приложение или скрипт Python запускаются по символической ссылке.

# Get if frozen
is_frozen = bool( getattr(sys, 'frozen', None) )

# Get path variable
path = sys.path if is_frozen else sys.argv

# Get nonempty first element or raise error
if path and path[0]:
    apppath = path[0]
elif is_frozen():
    raise RuntimeError('Cannot determine app path because sys.path[0] is empty.')
else:
    raise RuntimeError('Cannot determine app path in interpreter mode.')

# Make absolute (eliminate symbolic links)
apppath = os.path.abspath( os.path.realpath(apppath) )

# Split and return
appdir, appname = os.path.split(apppath)
2 голосов
/ 18 мая 2010

Используйте os.path.dirname (os.path.abspath (sys.argv [0])) из приложения py2exe, оно будет работать так же, как и сценарий python (так что вы можете тестировать, не создавая exe каждый раз время) и из exe.

Это может быть намного лучше, чем использование относительных путей, потому что вам не нужно беспокоиться о том, откуда запускается ваше приложение (.py или .exe).

2 голосов
/ 03 октября 2009

Что вы думаете об использовании относительных путей для всех включенных файлов? Я полагаю, можно использовать sys.path.append(".." + os.path.sep + "images") для вашего примера о ok.png, тогда вы можете просто open("ok.png", "rb"). Использование относительных путей должно исправить проблемы с файлом library.zip, который генерируется py2exe, по крайней мере, это то, что он делает для меня.

0 голосов
/ 27 августа 2014

Я использую следующий трюк в Windows.
Когда программа замораживается в «исполняемом файле» py2exe (например, my_application.exe ), dirname(__file__) возвращает папку, в которой выполняется ваш основной скрипт на python. Как ни странно, эта папка - не папка, содержащая my_application.exe , а сама my_application.exe .
Обратите внимание, что my_application.exe - это не двоичный файл, а сжатая папка (вы можете разархивировать ее), которая содержит библиотеки Python и ваши скомпилированные скрипты.
Вот почему os.path.dirname вашего __file__ на самом деле my_application.exe .

Таким образом, этот код дает вам корневой каталог для ваших файлов конфигурации или изображений (в случае замороженного приложения - папка, содержащая исполняемый файл py2exe, в противном случае - папка, из которой выполняется ваш скрипт python):

dirname = os.path.dirname(__file__)
if dirname.endswith('.exe'):
    dirname = os.path.split(dirname)[0]

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

...