Pyinstaller Jinja2 TemplateNotFound

Pyinstaller Jinja2 TemplateNotFound

我正在使用 pyinstaller 构建我的 Flask 应用程序, 一切正常,除了 Jinja2 模板出现问题。

它给了我 jinja2.exceptions.TemplateNotFound,

我试图将 from app import template 放入模板文件夹,但没有成功(我猜是因为它们不包含任何 py 文件)。

我还尝试更改 .spec 文件以包含 templates 文件夹

added_files = [
         ( '..\CommerceApp\app\templates', 'templates' ),
         ( '..\CommerceApp\app\static', 'static' )
        ]

a = Analysis(['..\CommerceApp\run.py'],
             pathex=['D:\PythonProjects\CommerceAppExe'],
             binaries=None,
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)

但是也没用,和我自己手动复制文件夹一样

有什么方法可以包含与 .exe 捆绑在一起的模板吗?


编辑

这是我的 spec 文件

# -*- mode: python -*-

block_cipher = None

a = Analysis(['..\CommerceApp_withPyInstaller\run.py'],
             pathex=['D:\PythonProjects\CommerceAppExe'],
             binaries=None,
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='SupplyTracker',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='SupplyTracker')

编辑 2

已接受的答案更改为 ,因为它解决了问题。

编辑 3

另外我才意识到,我可以用我的包名创建一个新文件夹并填写静态模板 csshtml 等,它会起作用(类似的结果来自gmas80 脚本的作用)

Jinja2 package uses the pkg_resources API which is not supported by PyInstaller. The pkg_resources module is provided via the setuptools 包。

来自FAQ page of pyinstaller

pkg_resources is currently not supported by PyInstaller. This means that an application using a library which uses the the pkg_resources API will probably not work out of the box. The only situation in which it works is when it's being used on .egg files (see above). For details follow issue #183.

我认为 中描述的不是问题所在。我刚刚能够使用 Jinja2.

冻结应用程序

在我的规格文件中,我使用这种方法收集所有模板:

from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT, BUNDLE, TOC


def collect_pkg_data(package, include_py_files=False, subdir=None):
    import os
    from PyInstaller.utils.hooks import get_package_paths, remove_prefix, PY_IGNORE_EXTENSIONS

    # Accept only strings as packages.
    if type(package) is not str:
        raise ValueError

    pkg_base, pkg_dir = get_package_paths(package)
    if subdir:
        pkg_dir = os.path.join(pkg_dir, subdir)
    # Walk through all file in the given package, looking for data files.
    data_toc = TOC()
    for dir_path, dir_names, files in os.walk(pkg_dir):
        for f in files:
            extension = os.path.splitext(f)[1]
            if include_py_files or (extension not in PY_IGNORE_EXTENSIONS):
                source_file = os.path.join(dir_path, f)
                dest_folder = remove_prefix(dir_path, os.path.dirname(pkg_base) + os.sep)
                dest_file = os.path.join(dest_folder, f)
                data_toc.append((dest_file, source_file, 'DATA'))

    return data_toc

pkg_data = collect_pkg_data('<YOUR LIB HERE>')

然后将 pkg_data 添加到 COLLECT(1 个文件夹)或 EXE(1 个文件).spec.

在 1 文件夹解决方案中,您应该能够在创建的子文件夹中找到所有模板。


编辑

这可能有效(假设您有一个包裹(即,您有一个 __init__.py),遵循这些建议:http://flask.pocoo.org/docs/0.10/patterns/packages/):

# -*- mode: python -*-

# <<< START ADDED PART    
from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT, BUNDLE, TOC


def collect_pkg_data(package, include_py_files=False, subdir=None):
    import os
    from PyInstaller.utils.hooks import get_package_paths, remove_prefix, PY_IGNORE_EXTENSIONS

    # Accept only strings as packages.
    if type(package) is not str:
        raise ValueError

    pkg_base, pkg_dir = get_package_paths(package)
    if subdir:
        pkg_dir = os.path.join(pkg_dir, subdir)
    # Walk through all file in the given package, looking for data files.
    data_toc = TOC()
    for dir_path, dir_names, files in os.walk(pkg_dir):
        for f in files:
            extension = os.path.splitext(f)[1]
            if include_py_files or (extension not in PY_IGNORE_EXTENSIONS):
                source_file = os.path.join(dir_path, f)
                dest_folder = remove_prefix(dir_path, os.path.dirname(pkg_base) + os.sep)
                dest_file = os.path.join(dest_folder, f)
                data_toc.append((dest_file, source_file, 'DATA'))

    return data_toc

pkg_data = collect_pkg_data('<yourapplication>')  # <<< Put the name of your package here
# <<< END ADDED PART    

block_cipher = None

a = Analysis(['..\CommerceApp_withPyInstaller\run.py'],
             pathex=['D:\PythonProjects\CommerceAppExe'],
             binaries=None,
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='SupplyTracker',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               pkg_data,  # <<< Add here the collected files
               strip=False,
               upx=True,
               name='SupplyTracker')