Как прописать настройки spec файла для конвертации .exe вложенных файлов и папок?
Я использую в своей программе файлы .json для удобного хранения данных. Структура программы вполне примитивна: в каталоге Main лежит главный скрипт Main.py, который должен создавать файл inputs.json в подкаталоге Main\Calculations.
А потом в этом подкаталоге скрипт Calculations.py обращается к файлу inputs.json чтобы работать с ним далее. В IDE PyCharm для работы достаточно прописать относительный путь Calculations\inputs.json чтобы программа поняла куда сохранять файл.
Однако если программу залить в .exe с помощью pyinstaller, то естественно уже не работает такой подход.
Я пробовал вставлять функцию os.path.abspath() чтобы получить абсолютный путь, но это не работает. В любом случае выходит ошибка no such file or directory
Структура проекта:
/Calculations
|----__init__.py
|----inputs.json (изначально отсутствует)
|----Calculations.py
Main.py
Если это важно, то .json формируется из таблицы pandas DataFrame под названием mech_df. Ещё я пробовал использовать функцию getcwd() и добавлять к ней подкаталог:
main_path = os.getcwd()
inputs_path = os.path.join(main_path, 'Calculations', 'inputs.json')
mech_df.to_json(inputs_path, orient = 'index', indent = 5)
UPD: В общем, разобравшись я понял, что дело здесь вообще не в каталоге, дело в том, что в моей программе импортируется только Calculations.py безотностильно каталога.
Вопрос: как нужно правильно прописать конфиг spec файла, чтобы конечный .exe файл мог оперировать вложенными папками и файлами в них?
Ответы (1 шт):
Нашёл я ответ на свой же вопрос. Действительно, данная проблема уже освещалась на англоязычном stackoverflow. Проблема решается в 2 действия (при условии что вам нужны файлы подкатолагах в рантайме как мне:
1)В spec файле вы должны прописать директорию в которой эти самые файлы лежат или будут лежать:
datas = [('C:/full/path/to/folder', 'folder')]
2)В скрипте который создаёт/обращается к этим файлам вам нужен метод:
import sys
import os
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)`
Далее вы должны определить абсолютный путь к каталогу с помощью этого метода:
base_path = resource_path('folder')
И чтобы окончательно добраться до файла есть замечательный метод os.path.join()
inp_path = Path(os.path.join(base_path, "inputs.json"))
Теперь вы можете прописывать путь inp_path для создания файлов в подкаталогах, и исполняемый файл .exe полученный из pyinstaller будет работать исправно. Я не берусь объяснять полную механику почему это работает именно так, но как я понял, это из-за того, что pyinstaller создаёт временную папку и хранит этот путь в _MEIPASS. Таким образом вы точно попадёте на правильный каталог, при условии что загрузили его в пункте 1.
Если в ответе или тексте вопроса присуствует технические ошибки, прошу в комментариях их осветить =)