Приложение Flask, созданное с помощью pyinstaller, не отрисовки index.html

Я написал приложение с флягой, и он отлично работает. Я хотел распространять его как исполняемый файл. Пробовал делать это с помощью pyinstaller flaskScript.py папка dist создана. Зашел в папку dist и дважды щелкнул мой исполняемый флажок, он запустил мой сервер. При доступе к 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

Пока он отлично работает в настройках dev при выполнении python flaskScript.py

Ответ 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

Проблема в том, что когда сайт работает в упакованном виде, шаблоны находятся в каталоге с именем _MEIxxxxxx в каталоге temp (см. Это в Руководстве по PyInstaller), поэтому мы должны сообщить об этом Flask.

Это делается с помощью аргумента template_folder (о котором я узнал в этом ответе здесь и позже в документации по API).

Наконец, есть if чтобы гарантировать, что мы все еще можем использовать его без упаковки во время его разработки. Если он frozen, то скрипт упакован, и мы должны сообщить Flask, где найти шаблоны; в противном случае мы запускаем его в среде Python (взято отсюда), и настройки по умолчанию будут работать (если, конечно, вы используете стандартную директорию 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. он будет работать

Ответ 3

Если вы пытаетесь создать исполняемый файл --onefile, вам также необходимо добавить каталоги в файл спецификации.

  1. В коде Python найдите, где работает приложение, и сохраните путь в base_dir:

    import os, sys
    base_dir = '.'
    if hasattr(sys, '_MEIPASS'):
        base_dir = os.path.join(sys._MEIPASS)
    
  2. Передайте правильные пути к приложению Flask, используя параметры static_folder и template_folder:

    app = Flask(__name__,
            static_folder=os.path.join(base_dir, 'static'),
            template_folder=os.path.join(base_dir, 'templates'))
    
  3. В spec файле нам нужно указать pyinstaller, чтобы он включал templates и static папку, включая соответствующие папки в разделе Analysis в pyinstaller:

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

Немного объяснения:

Общая проблема с отсутствием поиска файлов после упаковки с помощью pyinstaller заключается в том, что файлы изменят свой путь. С --onefile ваши файлы будут сжаты внутри 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)

Более подробная информация о времени выполнения в pyinstaller

Ответ 4

Я только что написал сообщение в блоге об этой проблеме и другие похожие, Создайте один исполняемый файл для приложения Flask с PyInstaller

В основном элегантное решение состоит в следующем:

Окна

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

Linux (NOT TESTED)

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

Ответ 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 здесь