Управление ресурсами в приложениях pyz
У меня есть многомодульное приложение Python, которое я упаковал в pyz
исполняемый файл с python3 -m zipapp
.
Я хотел бы развернуть это приложение с некоторыми ресурсами, которые ему необходимы для запуска (некоторые текстовые файлы). Я попытался просто добавить эти текстовые файлы вproject_root/res
а потом просто сделай что-нибудь вроде with open("./res/resource1.txt", "r") as f: do_something()
но конечно файл не найден.
Как я могу прочитать текстовый файл, встроенный в zipapp
применение?
1 ответ
import pkgutil
pkgutil.get_data(<module name>, 'resource1.txt')
вернет объект байтов.
<module name>
должен быть строкой, содержащей путь к папке, в которой находится resource1.txt, как если бы вы пытались его импортировать; например, если хотите/res/some_subfolder/foo.txt
тогда ты бы сделал pkgutil.get_data('yourmodule.res.some_subfolder', 'foo.txt')
.
Обратите внимание, что res
а также some_subfolder
в этом случае должно быть полно модулей Python, а не только каталогов (разница заключается в наличии или отсутствии пустого файла с именем __init__.py
); в противном случае zipapp проигнорирует их. Таким образом, ваша структура папок в приведенном выше примере должна быть:
project root
| main.py
| <whatever other files you have>
| res
| | __init__.py
| | some_subfolder
| | | __init__.py
| | | foo.txt
Опять же, эти файлы могут быть пустыми, если вы хотите, они просто должны существовать (хотя, если вы поместите в них код, вы можете сделать import res
(или import res.some_subfolder
) и он будет работать res/__init__.py
, который может быть полезным способом организовать все ваши ресурсы из одного места, если вам так хочется). Между прочим, если кто-то, читающий это, как и большинство программистов Python, не знаком с принципами работы модулей, вот краткое руководство из документации Python.
Кроме того, если вы просто используете zipapp (в отличие от exe, созданного с помощью pyinstaller), вы можете просто:
import sys
import zipfile
with zipfile.ZipFile(sys.argv[0]) as zf:
with zf.open('res/resource1.txt') as f:
print(f.read())