Объединение файлов данных с помощью PyInstaller (--onefile)
Я пытаюсь создать однофайловый EXE-файл с помощью PyInstaller, который должен включать изображение и иконку. Я ни за что на свете не смогу заставить его работать с --onefile.
Если я это сделаю, --onedir все работает очень хорошо. Когда я использую --onefile, он не может найти указанные дополнительные файлы (при запуске скомпилированного EXE-файла). Он находит библиотеки DLL и все остальное нормально, только не два изображения.
Я заглянул во временный каталог, созданный при запуске EXE (\Temp\_MEI95642\ например), и файлы действительно там есть. Когда я помещаю EXE в этот временный каталог, он их находит. Очень запутанно.
Я должен добавить, что я также пытался не помещать их во вложенные папки, но это ничего не изменило.
Редактировать:Отмечен новый ответ как правильный из-за обновления PyInstaller.
Переведено автоматически
Ответ 1
Более новые версии PyInstaller больше не устанавливают env переменную, поэтому отличный ответ Ши не будет работать. Теперь путь устанавливается как sys._MEIPASS:
defresource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ try: # PyInstaller creates a temp folder and stores path in _MEIPASS base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
Ответ 2
pyinstaller распаковывает ваши данные во временную папку и сохраняет путь к этому каталогу в _MEIPASS2 переменной окружения. Чтобы получить _MEIPASS2 каталог в упакованном режиме и использовать локальный каталог в распакованном режиме (разработки), я использую это:
# in development >>> resource_path("app_icon.ico") "/home/shish/src/my_app/app_icon.ico"
# in production >>> resource_path("app_icon.ico") "/tmp/_MEI34121/app_icon.ico"
Ответ 3
Во всех остальных ответах используется текущий рабочий каталог в случае, когда приложение не PyInstalled (т.е. sys._MEIPASS Не установлено). Это неправильно, поскольку не позволяет вам запускать ваше приложение из каталога, отличного от того, в котором находится ваш скрипт.
Лучшее решение:
import sys import os
defresource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) return os.path.join(base_path, relative_path)
Ответ 4
Я занимался этой проблемой долгое (ну, очень долгое) время. Я перерыл почти все источники, но в моей голове ничего не складывалось.
Наконец, я думаю, что выяснил точные шаги, которым нужно следовать, и хотел поделиться.
Обратите внимание, что в моем ответе используется информация об ответах других пользователей на этот вопрос.
Как создать автономный исполняемый файл проекта python.
Предположим, у нас есть project_folder и дерево файлов выглядит следующим образом:
project_folder/ main.py xxx.py # another module yyy.py # another module sound/ # directory containing the sound files img/ # directory containing the image files venv/ # if using a venv
Прежде всего, предположим, что вы определили пути к sound/ и img/ папкам в переменные sound_dir и img_dir следующим образом:
Где, resource_path() определяется в верхней части вашего скрипта как:
defresource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) return os.path.join(base_path, relative_path)
Активируйте виртуальный env при использовании venv,
Установите pyinstaller, если вы этого еще не сделали, с помощью: pip3 install pyinstaller.
Запустите: pyi-makespec --onefile main.py чтобы создать файл спецификации для процесса компиляции и сборки.
Это изменит иерархию файлов на:
project_folder/ main.py xxx.py # modules xxx.py # modules sound/ # directory containing the sound files img/ # directory containing the image files venv/ # if using a venv main.spec
Открыть (с помощью редактора) main.spec:
В верхней части файла вставьте:
added_files = [
("sound", "sound"), ("img", "img")
]
Затем измените строку datas=[], на datas=added_files,
Подробнее о выполняемых операциях main.spec смотрите Здесь.
Выполнить pyinstaller --onefile main.spec
И это все, вы можете запускать main в project_folder/dist из любого места, не имея ничего другого в своей папке. Вы можете распространять только этот main файл. Теперь это настоящий автономный файл.