Build Python Script To Single Exe With Pyinstaller
Solution 1:
I just solved this myself yesterday using a tweaked version of what giumas did here: https://github.com/pyinstaller/pyinstaller/issues/1898
The issue isn't so much hooking (which was my first attempt at a solution), but the fact that pandas style module imports jinja2 which uses a "get_template" method which in turn uses the pkg_resources module. That last one is the issue, for some reason pyinstaller doesn't play well with the pkg_resources module.
Answer : Find where pandas is installed and go to something like
C:\Users\UserName\AppData\Local\Programs\Python\Python36\Lib\site-packages\pandas\io\formats
In the formats folder find the style.py file and open it in your favorite text editor. In style.py scroll down to about line 118 where you will see this:
template = env.get_template("html.tpl")
change this line to:
template = env.from_string("html.tpl")
save the file and re-run pyinstaller. When you try and run the executable it should perform as expected sans any error messages.
Hope it helps.
Solution 2:
The following doesn't require manually changing the library code. This could be added as a change to the official Jinja2 hook in pyinstaller if somebody has the time to do so:
import sys
from jinja2.loaders import FileSystemLoader
classPyInstallerPackageLoader(FileSystemLoader):
"""Load templates from packages deployed as part of a Pyinstaller build. It is constructed with
the name of the python package and the path to the templates in that
package::
loader = PackageLoader('mypackage', 'views')
If the package path is not given, ``'templates'`` is assumed.
Per default the template encoding is ``'utf-8'`` which can be changed
by setting the `encoding` parameter to something else. Due to the nature
of eggs it's only possible to reload templates if the package was loaded
from the file system and not a zip file.
"""def__init__(self, package_name, package_path="templates", encoding="utf-8"):
# Use the standard pyinstaller convention of storing additional package files
full_package_path = f"{sys._MEIPASS}/{package_name}/{package_path}"# Defer everything else to the FileSystemLoadersuper().__init__(full_package_path, encoding)
defpatch_jinja_loader():
# patching the pandas loader which fails to locate the template when called from a pyinstaller buildifgetattr(sys, "frozen", False):
import jinja2
jinja2.PackageLoader = PyInstallerPackageLoader
It basically makes a loader that looks like the Jinja2 PackageLoader
that pandas tries to use so that it can be patched. In fact it instead uses the FileSystemLoader which is what we need for pyinstaller to just find the template file.
The above needs to be run before pandas is imported.
I've also posted this solution on the GitHub issue
Post a Comment for "Build Python Script To Single Exe With Pyinstaller"