I am using pyinstaller
to build my flask application,
everything is working fine except I get problems with Jinja2 templates.
It gave me jinja2.ex
The Jinja2 package uses the pkg_resources API which is not supported by PyInstaller
. The pkg_resources
module is provided via the setuptools package.
From the 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.
I don't believe that the issue is what is described in https://stackoverflow.com/a/35816876/2741329. I have just been able to freeze an application with Jinja2
.
In my spec file I use this approach to collect all the templates:
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>')
Then add pkg_data
to the COLLECT
(1-folder) or to the EXE
(1-file) .spec.
In the 1-folder solution, you should be able to find all your templates in the created sub-folder.
Edit
This might work (assuming that you have a package (i.e., you have an __init__.py
) following these suggestions: 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')