2009-10-02 6 views
3

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

_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/утилитами/images.py», и он использует свой путь для доступа " gui/images/ok.png ", например. Прямо сейчас версия py2exe попытается получить доступ к «proj/dist/library.zip/gui/images/ok.png» или что-то еще, , которое просто не сработает.

ответ

2

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

+0

Хм, я дам этот снимок. im записывая функцию getAbsPath(), которая принимает относительный путь и просто возвращает правильную вещь для открытия. он обнаружит, находится ли он в файле library.zip, и если это так, он перейдет в другой каталог вместо этого, на фактическом fs – Claudiu

+0

. Вы также можете попытаться поместить ваши включенные файлы в каталог пакетов, так как '__init__ .py' '__path__' сохранит путь к скрипту' __init __. py'. – fucx

10

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

  1. проверка sys.frozen, который py2exe ухитряется установить, используя что-то вроде GetAttr (SYS, «замороженный», '')
  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

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

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

2

Вот мое решение (протестировано на 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) 
0

Я использую следующий трюк в окнах.
Когда программа заморожена в исполняемом файле 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 исполняемого, иначе папка, откуда ваш питон скрипт работает):

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

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

Смежные вопросы