Я упаковал мое Flask веб-приложение в исполняемый Python архив ( zipapp ). У меня проблемы с загрузкой шаблонов. Flask / Jinja2 не может найти шаблоны.
Для загрузки шаблонов я использовал jinja2.FunctionLoader
с функцией загрузки, которая должна была бы считывать связанные файлы (в данном случае шаблоны Jinja) из исполняемого файла. zip-архив (ссылка: python: могут ли исполняемые zip-файлы включать файлы данных? ). Однако функция загрузки не может найти шаблон (см .: (1)
в коде), даже если шаблон доступен для чтения извне функции загрузки (см .: (2)
в коде).
Вот структура каталогов:
└── src
├── __main__.py
└── templates
├── index.html
└── __init__.py # Empty file.
src/__main__.py
:
import pkgutil
import jinja2
from flask import Flask, render_template
def load_template(name):
# (1) ATTENTION: this produces an error. Why?
# Error message:
# FileNotFoundError: [Errno 2] No such file or directory: 'myapp'
data = pkgutil.get_data('templates', name)
return data
# (2) ATTENTION: Unlike (1), this successfully found and read the template file. Why?
data = pkgutil.get_data('templates', 'index.html')
print(data)
# This also works:
data = load_template('index.html')
print(data)
# Why?
app = Flask(__name__)
app.config['SECRET_KEY'] = 'my-secret-key'
app.jinja_loader = jinja2.FunctionLoader(load_template) # <-
@app.route('/')
def index():
return render_template('index.html')
app.run(host='127.0.0.1', port=3000)
Чтобы создать исполняемый архив, я установил все зависимости в src/
(используя pip3 install wheel flask --target src/
), затем я побежал python3 -m zipapp src/ -o myapp
, чтобы создать сам исполняемый архив. Затем я запустил исполняемый архив, используя python3 myapp
. К сожалению, попытка получить доступ к странице индекса через веб-браузер приводит к ошибке:
# ...
File "myapp/__main__.py", line 10, in load_template
File "/usr/lib/python3.6/pkgutil.py", line 634, in get_data
return loader.get_data(resource_name)
FileNotFoundError: [Errno 2] No such file or directory: 'myapp'
Ошибка вызвана (1)
в коде. Как часть моих усилий по отладке, я добавил (2)
, чтобы проверить, можно ли найти шаблон в глобальной области видимости файла. Удивительно, но он успешно находит и читает файл шаблона.
Чем объясняется разница в поведении между (1)
и (2)
? Что еще более важно, как я могу Flask найти шаблоны Jinja, которые связаны вместе с приложением Flask в исполняемом Python zip-архиве?
(Python версия: 3.6.8 для linux; Flask версия: 1.1.1)