gpt4 book ai didi

python - 如何使 Flask/Jinja2 加载可执行 zip 存档中的捆绑模板?

转载 作者:太空宇宙 更新时间:2023-11-03 19:42:18 25 4
gpt4 key购买 nike

我已将 Flask Web 应用程序打包到可执行的 Python 压缩存档中 ( zipapp )。我在加载模板时遇到问题。 Flask/Jinja2 无法找到模板。

为了加载模板,我使用了 jinja2.FunctionLoader 和一个加载函数,该函数应该能够从可执行 zip 存档内部读取捆绑文件(在本例中为 Jinja 模板)(引用:python: can executable zip files include data files? )。但是,加载函数无法找到模板(请参阅代码中的 (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 installwheelflask --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 找到与可执行 Python zip 存档内的 Flask 应用程序捆绑在一起的 Jinja 模板?

(Linux 上的 Python 版本:3.6.8;Flask 版本:1.1.1)

最佳答案

jinja2.FunctionLoader(load_template) 正在寻找一个函数来以 unicode 字符串形式返回完整的 index.html 模板。根据 jinja2 docs :

A loader that is passed a function which does the loading. The function receives the name of the template and has to return either an unicode string with the template source, a tuple in the form (source, filename, uptodatefunc) or None if the template does not exist.

pkgutil.get_data('templates', name) 不返回 unicode 字符串,而是返回 bytes 对象。要解决此问题,您应该使用 pkgutil.get_data('templates', name).decode('utf-8')

def load_template(name):
"""
Loads file from the templates folder and returns file contents as a string.
See jinja2.FunctionLoader docs.
"""
return pkgutil.get_data('templates', name).decode('utf-8')

这意味着第 (2) 部分将正常工作,因为代码将 index.html 打印为字节对象。 Print 可以处理字节对象,它在控制台上看起来几乎与字符串相同。但是,第 (1) 部分中的代码将失败,因为它被馈送到需要字符串的 jinja2.FunctionLoader 。第 (1) 部分因 ValueError 对我来说失败了。

我怀疑,由于您的错误消息是 FileNotFoundError 并调用 myapp 作为文件,因此您帖子的该部分与您的应用程序不完全匹配。我在 Windows 10 和 Ubuntu Server 18.04 以及 Python 3.6 和 3.7 上准确复制了这些说明,除了需要使用解码之外没有任何问题。我偶尔会在 Ubuntu 上遇到 PermissionErrors,这需要我运行 sudo python3 myapp

关于python - 如何使 Flask/Jinja2 加载可执行 zip 存档中的捆绑模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60357727/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com