Как прописать настройки 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 шт):

Автор решения: AddmiX

Нашёл я ответ на свой же вопрос. Действительно, данная проблема уже освещалась на англоязычном 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.

Если в ответе или тексте вопроса присуствует технические ошибки, прошу в комментариях их осветить =)

→ Ссылка