【问题标题】:Flask application built using pyinstaller not rendering index.html使用 pyinstaller 构建的 Flask 应用程序不呈现 index.html
【发布时间】:2015-11-15 23:07:37
【问题描述】:

我编写了一个烧瓶应用程序,它工作得非常好。我想将它作为可执行文件分发。 尝试使用 pyinstaller flaskScript.py 生成了 dist 文件夹。 进入 dist 文件夹并双击我的可执行flaskScript,它启动了我的服务器。 在访问 url 时,localhost:9090 会出现以下异常

jinja2.exceptions.TemplateNotFound

TemplateNotFound: index.html

Traceback (most recent call last)
File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1836, in __call__

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1820, in wsgi_app

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1403, in handle_exception

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1817, in wsgi_app

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1477, in full_dispatch_request

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1381, in handle_user_exception

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1475, in full_dispatch_request

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.app", line 1461, in dispatch_request

File "<string>", line 13, in index

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.templating", line 127, in render_template

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/jinja2.environment", line 851, in get_or_select_template

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/jinja2.environment", line 812, in get_template

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/jinja2.environment", line 774, in _load_template

File "/Users/george/Downloads/flaskApps/flaskScript/build/flaskScript/out00-PYZ.pyz/flask.templating", line 64, in get_source

TemplateNotFound: index.html

虽然它在执行 python flaskScript.py 时在开发设置中工作正常

【问题讨论】:

  • 朋友,你错过了sys.path.append(os.getcwd())
  • 您好我已经添加:在 python 文件中导入 sys sys.path.append(os.getcwd()) 并且它给出了相同的错误,我是否必须将它添加到渲染模板行@app.route('/index') def index(): return render_template('index.html') return 语句的某个地方?提前致谢!
  • 你是怎么解决的?

标签: python flask jinja2


【解决方案1】:

这个问题现在有点老了,但我在将它打包到单个文件时遇到了同样的问题(Python 3.4.3、Flask 0.10.1 和 PyInstaller 3.1.1)。

我已经设法通过在初始化脚本 (app\__init__.py) 中添加以下内容来解决它:

import sys
import os
from flask import Flask
# Other imports

if getattr(sys, 'frozen', False):
    template_folder = os.path.join(sys._MEIPASS, 'templates')
    app = Flask(__name__, template_folder=template_folder)
else:
    app = Flask(__name__)

# etc

问题在于,当站点以打包形式运行时,模板位于 temp 目录下名为 _MEIxxxxxx 的目录中(请参阅 PyInstaller 手册中的this),所以我们必须告诉到 Flask。

这是通过template_folder 参数完成的(我在这个答案here 和后来的API docs 中发现了这一点)。

最后,if 的存在是为了确保我们在开发时仍然可以在未打包的情况下使用它。如果是frozen,那么脚本就打包好了,我们要告诉Flask去哪里找模板;否则我们将在 Python 环境中运行它(取自 here),默认值将起作用(当然假设您使用的是标准的 templates 目录)。

【讨论】:

    【解决方案2】:
    if getattr(sys, 'frozen', False):                                                                                                                                     
          template_folder = os.path.join(sys.executable, '..','templates')                                                                                                  
          static_folder = os.path.join(sys.executable, '..','static')                                                                                                       
          app = Flask(__name__, template_folder = template_folder,\                                                                                                         
                                  static_folder = static_folder)
    

    复制此代码并粘贴到您的文件中。现在 pyinstaller 在您的 dist 目录中查找静态和模板文件夹。现在将静态和模板文件夹复制并粘贴到您的 dist 文件夹中。它会起作用的

    【讨论】:

    • 我了解您要执行的操作,但由于可执行文件不是目录,因此会导致 NotADirectoryError NotADirectoryError: [Errno 20] Not a directory: '/home/shravan/Documents /repos/gallery/dotmole/dotmole/dist/dotmole/../templates/pages/placeholder.dashboard.html'
    【解决方案3】:

    我刚刚写了一篇关于这个问题和其他类似问题的博文, Create one executable file for a Flask app with PyInstaller

    基本上一个优雅的解决方案是执行以下操作:

    窗户

    pyinstaller -w -F --add-data "templates;templates" --add-data "static;static" app.py
    

    Linux(未测试)

    pyinstaller -w -F --add-data "templates:templates" --add-data "static:static" app.py
    

    【讨论】:

    • 嗨,它正在工作,但我有图像没有出现
    • Linux 语法在 Mac 上似乎可以正常工作,谢谢。官方文档说--add-data &lt;SRC;DEST or SRC:DEST&gt; 要添加到可执行文件中的其他非二进制文件或文件夹。路径分隔符是特定于平台的,使用 os.pathsep(在 Windows 上为 ;,在大多数 unix 系统上为 :)。
    【解决方案4】:

    如果您尝试创建 --onefile 可执行文件,您还需要在规范文件中添加目录。

    1. 在 Python 代码中,找到应用程序运行的位置并将路径存储在base_dir

      import os, sys
      base_dir = '.'
      if hasattr(sys, '_MEIPASS'):
          base_dir = os.path.join(sys._MEIPASS)
      
    2. 使用 `static_folder 和 template_folder 参数将正确的路径传递给 Flask 应用程序:

      app = Flask(__name__,
              static_folder=os.path.join(base_dir, 'static'),
              template_folder=os.path.join(base_dir, 'templates'))
      
    3. 在 spec 文件中,我们确实需要告诉 pyinstaller 将 templatesstatic 文件夹包括在 pyinstaller 的 Analysis 部分中的相应文件夹:

      a = Analysis(
           ...
           datas=[
             ('PATH_TO_THE_APP\\static\\', 'static'),
             ('PATH_TO_THE_APP\\templates\\', 'templates'),
           ],
           ...
      

    一点解释:

    用pyinstaller打包后找不到文件的普遍问题是文件会改变它的路径。使用--onefile 选项,您的文件将在exe 中压缩。当您执行 exe 时,它​​们会被解压缩并放在某个临时文件夹中。

    每次执行文件时都会发生变化,但可以在此处找到正在运行的应用程序(不是 spec 文件,而是您的主要 python 文件,例如 main.py):

    import os
    os.path.join(sys._MEIPASS)
    

    因此,模板文件将不在./templates 中,而是在os.path.join(os.path.join(sys._MEIPASS), templates) 中。现在的问题是,除非打包,否则您的代码将无法运行。因此,python main.py 不会运行。

    因此需要一个条件才能在正确的位置找到文件:

    import os, sys
    base_dir = '.'
    if hasattr(sys, '_MEIPASS'): # or, untested: if getattr(sys, 'frozen', False):
        base_dir = os.path.join(sys._MEIPASS)
    

    这里有更多关于runtime information in pyinstaller

    【讨论】:

      【解决方案5】:

      如果您是从 .spec 文件构建,则无需更改即可轻松完成

      __int__.py
      

      1) 将模板和静态文件夹添加到 .spec 中的数据

      2) 确保将 jinja2 添加到 hiddenimports

      block_cipher = None
      
      # add templates and static folders to a list
      added_files =[
          ('templates/*.html', 'templates'),
          ('static/*.css', 'static'),
          ]
      
      a = Analysis(['run.py'],
                   pathex=['/your/app/location'],
                   binaries=[],
                   datas = added_files, # set datas = added_files list
                   hiddenimports=['jinja2.ext'], # be sure to add jinja2 
                   hookspath=[],
                   runtime_hooks=[],
                   excludes=[],
                   win_no_prefer_redirects=False,
                   win_private_assemblies=False,
                   cipher=block_cipher,
                   noarchive=False)
                   ...
      

      此方法直接来自 pyinstaller 文档here

      【讨论】:

        【解决方案6】:
        pyinstaller spec_an_API.py --onefile --add-data "templates";"templates" --add-data "static";"static"
        

        对于使用 --onefile 的窗口

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-08-28
          • 1970-01-01
          • 1970-01-01
          • 2022-11-03
          • 1970-01-01
          • 2023-02-12
          • 2021-09-26
          相关资源
          最近更新 更多